refactor cart

This commit is contained in:
2026-02-09 14:29:21 +03:30
parent a21d1f6004
commit 626d8194d8
9 changed files with 67 additions and 125 deletions
@@ -62,7 +62,7 @@ export class DeliveryController {
@ApiOperation({ summary: 'Get a shop delivery method by delivery ID' }) @ApiOperation({ summary: 'Get a shop delivery method by delivery ID' })
@ApiParam({ name: 'deliveryId', description: 'Delivery method ID' }) @ApiParam({ name: 'deliveryId', description: 'Delivery method ID' })
findOne(@Param('deliveryId') deliveryId: string, @ShopId() restId: string) { findOne(@Param('deliveryId') deliveryId: string, @ShopId() restId: string) {
return this.deliveryService.findOne(restId, deliveryId); return this.deliveryService.findOrFail(restId, deliveryId);
} }
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
@@ -1,7 +1,5 @@
export enum DeliveryMethodEnum { export enum DeliveryMethodEnum {
DineIn = 'dineIn',
CustomerPickup = 'customerPickup', CustomerPickup = 'customerPickup',
DeliveryCar = 'deliveryCar',
DeliveryCourier = 'deliveryCourier', DeliveryCourier = 'deliveryCourier',
} }
@@ -54,7 +54,7 @@ export class DeliveryService {
return this.deliveryRepository.find({ shop: { id: restId } }, { orderBy: { order: 'asc' } }); return this.deliveryRepository.find({ shop: { id: restId } }, { orderBy: { order: 'asc' } });
} }
async findOne(restId: string, deliveryId: string): Promise<Delivery> { async findOrFail(restId: string, deliveryId: string): Promise<Delivery> {
const delivery = await this.deliveryRepository.findOne({ const delivery = await this.deliveryRepository.findOne({
id: deliveryId, id: deliveryId,
shop: { id: restId }, shop: { id: restId },
@@ -44,9 +44,6 @@ export class Order extends BaseEntity {
@Property({ type: 'json', nullable: true }) @Property({ type: 'json', nullable: true })
userAddress?: OrderUserAddress | null; userAddress?: OrderUserAddress | null;
// for car delivery
@Property({ type: 'json', nullable: true })
carAddress?: OrderCarAddress | null;
@ManyToOne(() => PaymentMethod) @ManyToOne(() => PaymentMethod)
paymentMethod: PaymentMethod; paymentMethod: PaymentMethod;
@@ -84,8 +81,6 @@ export class Order extends BaseEntity {
@Property({ type: 'text', nullable: true }) @Property({ type: 'text', nullable: true })
description?: string; description?: string;
@Property({ nullable: true })
tableNumber?: string;
@Enum(() => OrderStatus) @Enum(() => OrderStatus)
status!: OrderStatus; status!: OrderStatus;
@@ -11,19 +11,12 @@ export interface OrderUserAddress {
phone: string; phone: string;
} }
export interface OrderCarAddress {
carModel: string;
carColor: string;
plateNumber: string;
phone: string;
}
export enum OrderStatus { export enum OrderStatus {
PENDING_PAYMENT = 'pendingPayment', PENDING_PAYMENT = 'pendingPayment',
PAID = 'paid', PAID = 'paid',
PREPARING = 'preparing', PREPARING = 'preparing',
DELIVERED_TO_WAITER = 'deliveredToWaiter', DELIVERED = 'delivered',
DELIVERED_TO_RECEPTIONIST = 'deliveredToReceptionist',
SHIPPED = 'shipped', SHIPPED = 'shipped',
COMPLETED = 'completed', COMPLETED = 'completed',
CANCELED = 'canceled', CANCELED = 'canceled',
+51 -102
View File
@@ -6,7 +6,7 @@ import { User } from '../../users/entities/user.entity';
import { Shop } from '../../shops/entities/shop.entity'; import { Shop } from '../../shops/entities/shop.entity';
import { Product } from '../../products/entities/product.entity'; import { Product } from '../../products/entities/product.entity';
import { CartService } from '../../cart/providers/cart.service'; import { CartService } from '../../cart/providers/cart.service';
import { OrderStatus, OrderUserAddress, OrderCarAddress } from '../interface/order.interface'; import { OrderStatus, OrderUserAddress } from '../interface/order.interface';
import { PaymentMethodEnum, PaymentStatusEnum } from '../../payments/interface/payment'; import { PaymentMethodEnum, PaymentStatusEnum } from '../../payments/interface/payment';
import { Cart } from '../../cart/interfaces/cart.interface'; import { Cart } from '../../cart/interfaces/cart.interface';
import { PaymentMethod } from '../../payments/entities/payment-method.entity'; import { PaymentMethod } from '../../payments/entities/payment-method.entity';
@@ -21,6 +21,11 @@ import { StatusTransitionRef } from '../interface/order.interface';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events'; import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events';
import { OrderMessage } from 'src/common/enums/message.enum'; import { OrderMessage } from 'src/common/enums/message.enum';
import { UserService } from 'src/modules/users/providers/user.service';
import { ShopService } from 'src/modules/shops/providers/shops.service';
import { DeliveryService } from 'src/modules/delivery/providers/delivery.service';
import { PaymentMethodService } from 'src/modules/payments/services/payment-method.service';
type OrderItemData = { product: Product; quantity: number; unitPrice: number; discount: number }; type OrderItemData = { product: Product; quantity: number; unitPrice: number; discount: number };
type ValidatedCartForOrder = { type ValidatedCartForOrder = {
@@ -28,7 +33,6 @@ type ValidatedCartForOrder = {
shop: Shop; shop: Shop;
delivery: Delivery; delivery: Delivery;
userAddress: OrderUserAddress | null; userAddress: OrderUserAddress | null;
carAddress: OrderCarAddress | null;
paymentMethod: PaymentMethod; paymentMethod: PaymentMethod;
orderItemsData: OrderItemData[]; orderItemsData: OrderItemData[];
}; };
@@ -40,9 +44,8 @@ export class OrdersService {
private static readonly STATUS_TRANSITIONS: Record<OrderStatus, readonly OrderStatus[]> = { private static readonly STATUS_TRANSITIONS: Record<OrderStatus, readonly OrderStatus[]> = {
[OrderStatus.PENDING_PAYMENT]: [OrderStatus.PAID, OrderStatus.CANCELED, OrderStatus.PREPARING], [OrderStatus.PENDING_PAYMENT]: [OrderStatus.PAID, OrderStatus.CANCELED, OrderStatus.PREPARING],
[OrderStatus.PAID]: [OrderStatus.PREPARING, OrderStatus.CANCELED], [OrderStatus.PAID]: [OrderStatus.PREPARING, OrderStatus.CANCELED],
[OrderStatus.PREPARING]: [OrderStatus.DELIVERED_TO_RECEPTIONIST, OrderStatus.DELIVERED_TO_WAITER, OrderStatus.SHIPPED, OrderStatus.CANCELED], [OrderStatus.PREPARING]: [OrderStatus.DELIVERED, OrderStatus.SHIPPED, OrderStatus.CANCELED],
[OrderStatus.DELIVERED_TO_WAITER]: [OrderStatus.COMPLETED, OrderStatus.CANCELED], [OrderStatus.DELIVERED]: [OrderStatus.COMPLETED, OrderStatus.CANCELED],
[OrderStatus.DELIVERED_TO_RECEPTIONIST]: [OrderStatus.COMPLETED, OrderStatus.CANCELED],
[OrderStatus.SHIPPED]: [OrderStatus.COMPLETED, OrderStatus.CANCELED], [OrderStatus.SHIPPED]: [OrderStatus.COMPLETED, OrderStatus.CANCELED],
[OrderStatus.COMPLETED]: [OrderStatus.CANCELED], [OrderStatus.COMPLETED]: [OrderStatus.CANCELED],
[OrderStatus.CANCELED]: [], [OrderStatus.CANCELED]: [],
@@ -52,13 +55,17 @@ export class OrdersService {
private readonly em: EntityManager, private readonly em: EntityManager,
private readonly cartService: CartService, private readonly cartService: CartService,
private readonly orderRepository: OrderRepository, private readonly orderRepository: OrderRepository,
private readonly shopService: ShopService,
private readonly deliveryService: DeliveryService,
private readonly paymentMethodService: PaymentMethodService,
private readonly paymentsService: PaymentsService, private readonly paymentsService: PaymentsService,
private readonly eventEmitter: EventEmitter2, private readonly eventEmitter: EventEmitter2,
private readonly userService: UserService,
) { } ) { }
async checkout(userId: string, restaurantId: string) { async checkout(userId: string, shopId: string) {
const cart = await this.cartService.findOneOrFail(userId, restaurantId); const cart = await this.cartService.findOneOrFail(userId, shopId);
const validated = await this.validateCartForOrder(userId, restaurantId, cart); const validated = await this.validateCartForOrder(userId, shopId, cart);
const order = await this.em.transactional(async em => { const order = await this.em.transactional(async em => {
const order = em.create(Order, { const order = em.create(Order, {
@@ -66,7 +73,6 @@ export class OrdersService {
shop: validated.shop, shop: validated.shop,
deliveryMethod: validated.delivery, deliveryMethod: validated.delivery,
userAddress: validated.userAddress, userAddress: validated.userAddress,
carAddress: validated.carAddress,
paymentMethod: validated.paymentMethod, paymentMethod: validated.paymentMethod,
couponDiscount: cart.couponDiscount || 0, couponDiscount: cart.couponDiscount || 0,
couponDetail: cart.coupon, couponDetail: cart.coupon,
@@ -78,7 +84,6 @@ export class OrdersService {
total: cart.total || 0, total: cart.total || 0,
totalItems: cart.totalItems || 0, totalItems: cart.totalItems || 0,
description: cart.description, description: cart.description,
tableNumber: cart.tableNumber,
status: OrderStatus.PENDING_PAYMENT, status: OrderStatus.PENDING_PAYMENT,
history: [{ status: OrderStatus.PENDING_PAYMENT, changedAt: new Date() }], history: [{ status: OrderStatus.PENDING_PAYMENT, changedAt: new Date() }],
}); });
@@ -113,16 +118,16 @@ export class OrdersService {
em.persist(payment); em.persist(payment);
await em.flush(); await em.flush();
this.logger.debug(`Order ${order.id} created for user ${userId} (shop ${restaurantId})`); this.logger.debug(`Order ${order.id} created for user ${userId} (shop ${shopId})`);
return order; return order;
}); });
await this.cartService.clearCart(userId, restaurantId); await this.cartService.clearCart(userId, shopId);
const { paymentUrl } = await this.paymentsService.payOrder(order.id); const { paymentUrl } = await this.paymentsService.payOrder(order.id);
this.eventEmitter.emit( this.eventEmitter.emit(
OrderCreatedEvent.name, OrderCreatedEvent.name,
new OrderCreatedEvent(order.id, restaurantId, String(order?.orderNumber) || '', order.total), new OrderCreatedEvent(order.id, shopId, String(order?.orderNumber) || '', order.total),
); );
return { paymentUrl, order }; return { paymentUrl, order };
@@ -131,24 +136,24 @@ export class OrdersService {
/** /**
* Validates cart and prepares all required data for order creation * Validates cart and prepares all required data for order creation
*/ */
private async validateCartForOrder(userId: string, restaurantId: string, cart: Cart): Promise<ValidatedCartForOrder> { private async validateCartForOrder(userId: string, shopId: string, cart: Cart): Promise<ValidatedCartForOrder> {
this.assertCartHasItems(cart); this.assertCartHasItems(cart);
this.assertCartHasDeliveryMethod(cart); this.assertCartHasDeliveryMethod(cart);
this.assertCartHasPaymentMethod(cart); this.assertCartHasPaymentMethod(cart);
const [user, shop, delivery] = await Promise.all([ const [user, shop, delivery] = await Promise.all([
this.getUserOrFail(userId), this.userService.findOneOrFail(userId),
this.getRestaurantOrFail(restaurantId), this.shopService.findOrFail(shopId),
this.getDeliveryOrFail(cart.deliveryMethodId!), this.deliveryService.findOrFail(shopId, cart.deliveryMethodId!),
]); ]);
this.assertMeetsMinOrderForDelivery(cart, delivery); this.assertMeetsMinOrderForDelivery(cart, delivery);
this.assertDeliveryMethodRequirements(cart, delivery); this.assertDeliveryMethodRequirements(cart, delivery);
const paymentMethod = await this.getPaymentMethodOrFail(cart.paymentMethodId!, restaurantId); const paymentMethod = await this.paymentMethodService.findOneOrFail(cart.paymentMethodId!);
this.assertPaymentMethodEnabled(paymentMethod); this.assertPaymentMethodEnabled(paymentMethod);
const orderItemsData = await this.buildOrderItemsData(cart, restaurantId); const orderItemsData = await this.buildOrderItemsData(cart, shopId);
return { return {
user, user,
@@ -156,13 +161,12 @@ export class OrdersService {
delivery, delivery,
paymentMethod, paymentMethod,
userAddress: delivery.method === DeliveryMethodEnum.DeliveryCourier ? (cart?.userAddress ?? null) : null, userAddress: delivery.method === DeliveryMethodEnum.DeliveryCourier ? (cart?.userAddress ?? null) : null,
carAddress: delivery.method === DeliveryMethodEnum.DeliveryCar ? (cart?.carAddress ?? null) : null,
orderItemsData, orderItemsData,
}; };
} }
async findAllForUser(restId: string, dto: FindOrdersDto, userId: string): Promise<PaginatedResult<Order>> { async findAllForUser(shopId: string, dto: FindOrdersDto, userId: string): Promise<PaginatedResult<Order>> {
const result = await this.orderRepository.findAllPaginated(restId, { const result = await this.orderRepository.findAllPaginated(shopId, {
page: dto.page, page: dto.page,
limit: dto.limit, limit: dto.limit,
statuses: dto.statuses, statuses: dto.statuses,
@@ -178,8 +182,8 @@ export class OrdersService {
return result; return result;
} }
async findAllForAdmin(restId: string, dto: FindOrdersDto): Promise<PaginatedResult<Order>> { async findAllForAdmin(shopId: string, dto: FindOrdersDto): Promise<PaginatedResult<Order>> {
const result = await this.orderRepository.findAllPaginated(restId, { const result = await this.orderRepository.findAllPaginated(shopId, {
page: dto.page, page: dto.page,
limit: dto.limit, limit: dto.limit,
statuses: dto.statuses, statuses: dto.statuses,
@@ -195,16 +199,15 @@ export class OrdersService {
return result; return result;
} }
async findOne(id: string, restId: string): Promise<Order> { async findOne(id: string, shopId: string): Promise<Order> {
const order = await this.orderRepository.findOne( const order = await this.orderRepository.findOne(
{ id, shop: { id: restId } }, { id, shop: { id: shopId } },
{ {
populate: [ populate: [
'user', 'user',
'shop', 'shop',
'deliveryMethod', 'deliveryMethod',
'userAddress', 'userAddress',
'carAddress',
'paymentMethod', 'paymentMethod',
'payments', 'payments',
'items', 'items',
@@ -219,15 +222,14 @@ export class OrdersService {
} }
async changeOrderStatus( async changeOrderStatus(
orderId: string, orderId: string,
restId: string, shopId: string,
toStatus: OrderStatus, toStatus: OrderStatus,
ref: StatusTransitionRef, ref: StatusTransitionRef,
desc?: string, desc?: string,
): Promise<Order> { ): Promise<Order> {
const order = await this.getOrderOrFail(orderId, restId); const order = await this.getOrderOrFail(orderId, shopId);
// Store previous status before changing it // Store previous status before changing it
const previousStatus = order.status; const previousStatus = order.status;
@@ -244,7 +246,7 @@ export class OrdersService {
orderId, orderId,
order.user?.id || '', order.user?.id || '',
String(order?.orderNumber) || '', String(order?.orderNumber) || '',
restId, shopId,
previousStatus, previousStatus,
toStatus, toStatus,
ref, ref,
@@ -297,15 +299,8 @@ export class OrdersService {
} }
if ( if (
from == OrderStatus.PREPARING && from == OrderStatus.PREPARING &&
to == OrderStatus.DELIVERED_TO_WAITER && to == OrderStatus.DELIVERED &&
deliveryMethod !== DeliveryMethodEnum.DineIn && deliveryMethod !== DeliveryMethodEnum.DeliveryCourier &&
deliveryMethod !== DeliveryMethodEnum.DeliveryCar
) {
return false;
}
if (
from == OrderStatus.PREPARING &&
to == OrderStatus.DELIVERED_TO_RECEPTIONIST &&
deliveryMethod !== DeliveryMethodEnum.CustomerPickup deliveryMethod !== DeliveryMethodEnum.CustomerPickup
) { ) {
return false; return false;
@@ -318,10 +313,10 @@ export class OrdersService {
return true; return true;
} }
private async getOrderOrFail(orderId: string, restId: string): Promise<Order> { private async getOrderOrFail(orderId: string, shopId: string): Promise<Order> {
const order = await this.em.findOne( const order = await this.em.findOne(
Order, Order,
{ id: orderId, shop: { id: restId } }, { id: orderId, shop: { id: shopId } },
{ populate: ['paymentMethod', 'deliveryMethod', 'user'] }, { populate: ['paymentMethod', 'deliveryMethod', 'user'] },
); );
if (!order) throw new NotFoundException(OrderMessage.NOT_FOUND); if (!order) throw new NotFoundException(OrderMessage.NOT_FOUND);
@@ -346,23 +341,6 @@ export class OrdersService {
} }
} }
private async getUserOrFail(userId: string): Promise<User> {
const user = await this.em.findOne(User, { id: userId });
if (!user) throw new NotFoundException(OrderMessage.USER_NOT_FOUND);
return user;
}
private async getRestaurantOrFail(restaurantId: string): Promise<Shop> {
const shop = await this.em.findOne(Shop, { id: restaurantId });
if (!shop) throw new NotFoundException(OrderMessage.SHOP_NOT_FOUND);
return shop;
}
private async getDeliveryOrFail(deliveryId: string): Promise<Delivery> {
const delivery = await this.em.findOne(Delivery, { id: deliveryId });
if (!delivery) throw new NotFoundException(OrderMessage.DELIVERY_NOT_FOUND);
return delivery;
}
private assertMeetsMinOrderForDelivery(cart: Cart, delivery: Delivery) { private assertMeetsMinOrderForDelivery(cart: Cart, delivery: Delivery) {
const minOrderPrice = Number(delivery.minOrderPrice) || 0; const minOrderPrice = Number(delivery.minOrderPrice) || 0;
@@ -372,36 +350,10 @@ export class OrdersService {
} }
private assertDeliveryMethodRequirements(cart: Cart, delivery: Delivery) { private assertDeliveryMethodRequirements(cart: Cart, delivery: Delivery) {
if (delivery.method === DeliveryMethodEnum.DineIn) {
if (!cart.tableNumber || cart.tableNumber.trim() === '') {
throw new BadRequestException(OrderMessage.TABLE_NUMBER_REQUIRED);
}
}
if (delivery.method === DeliveryMethodEnum.DeliveryCourier && !cart.userAddress) { if (delivery.method === DeliveryMethodEnum.DeliveryCourier && !cart.userAddress) {
throw new BadRequestException(OrderMessage.ADDRESS_REQUIRED); throw new BadRequestException(OrderMessage.ADDRESS_REQUIRED);
} }
if (delivery.method === DeliveryMethodEnum.DeliveryCar && !cart.carAddress) {
throw new BadRequestException(OrderMessage.CAR_ADDRESS_REQUIRED);
}
}
private async getPaymentMethodOrFail(paymentMethodId: string, restaurantId: string): Promise<PaymentMethod> {
const paymentMethod = await this.em.findOne(
PaymentMethod,
{
id: paymentMethodId,
shop: { id: restaurantId },
},
{ populate: ['shop'] },
);
if (!paymentMethod) {
throw new NotFoundException(`Payment method with ID ${paymentMethodId} not found for shop ${restaurantId}`);
}
return paymentMethod;
} }
private assertPaymentMethodEnabled(paymentMethod: PaymentMethod) { private assertPaymentMethodEnabled(paymentMethod: PaymentMethod) {
@@ -410,14 +362,14 @@ export class OrdersService {
} }
} }
private async buildOrderItemsData(cart: Cart, restaurantId: string): Promise<OrderItemData[]> { private async buildOrderItemsData(cart: Cart, shopId: string): Promise<OrderItemData[]> {
const orderItemsData: OrderItemData[] = []; const orderItemsData: OrderItemData[] = [];
for (const cartItem of cart.items) { for (const cartItem of cart.items) {
const product = await this.em.findOne(Product, { id: cartItem.foodId }, { populate: ['shop'] }); const product = await this.em.findOne(Product, { id: cartItem.foodId }, { populate: ['shop'] });
if (!product) throw new NotFoundException(OrderMessage.PRODUCT_NOT_FOUND); if (!product) throw new NotFoundException(OrderMessage.PRODUCT_NOT_FOUND);
if (product.shop.id !== restaurantId) { if (product.shop.id !== shopId) {
throw new BadRequestException(OrderMessage.PRODUCT_NOT_BELONGS_TO_SHOP); throw new BadRequestException(OrderMessage.PRODUCT_NOT_BELONGS_TO_SHOP);
} }
@@ -431,20 +383,17 @@ export class OrdersService {
return orderItemsData; return orderItemsData;
} }
// Charts
async getStats(shopId: string) {
async getStats(restId: string) {
return this.em.transactional(async em => { return this.em.transactional(async em => {
// 1. Total orders count (excluding pending and canceled) // 1. Total orders count (excluding pending and canceled)
const totalOrders = await em.count(Order, { const totalOrders = await em.count(Order, {
shop: { id: restId }, shop: { id: shopId },
status: { status: {
$in: [ $in: [
OrderStatus.PAID, OrderStatus.PAID,
OrderStatus.PREPARING, OrderStatus.PREPARING,
OrderStatus.DELIVERED_TO_WAITER, OrderStatus.DELIVERED,
OrderStatus.DELIVERED_TO_RECEPTIONIST,
OrderStatus.SHIPPED, OrderStatus.SHIPPED,
OrderStatus.COMPLETED, OrderStatus.COMPLETED,
], ],
@@ -453,7 +402,7 @@ export class OrdersService {
// 2. Active products count // 2. Active products count
const activeFoods = await em.count(Product, { const activeFoods = await em.count(Product, {
shop: { id: restId }, shop: { id: shopId },
isActive: true, isActive: true,
}); });
@@ -464,7 +413,7 @@ export class OrdersService {
FROM orders o FROM orders o
WHERE o.restaurant_id = ? WHERE o.restaurant_id = ?
`, `,
[restId], [shopId],
); );
const totalClients = Number(clientsResult[0]?.count || 0); const totalClients = Number(clientsResult[0]?.count || 0);
@@ -476,7 +425,7 @@ export class OrdersService {
INNER JOIN orders o ON p.order_id = o.id INNER JOIN orders o ON p.order_id = o.id
WHERE o.restaurant_id = ? AND p.status = 'paid' WHERE o.restaurant_id = ? AND p.status = 'paid'
`, `,
[restId], [shopId],
); );
const totalRevenue = Number(revenueResult[0]?.total || 0); const totalRevenue = Number(revenueResult[0]?.total || 0);
@@ -489,7 +438,7 @@ export class OrdersService {
}); });
} }
async getFoodSalesPieChart(restId: string) { async getFoodSalesPieChart(shopId: string) {
return this.em.transactional(async em => { return this.em.transactional(async em => {
// Use last 30 days instead of just last month to be more inclusive // Use last 30 days instead of just last month to be more inclusive
const now = new Date(); const now = new Date();
@@ -505,7 +454,7 @@ export class OrdersService {
const lastDayOfLastMonth = new Date(now.getFullYear(), now.getMonth(), 0, 23, 59, 59, 999); const lastDayOfLastMonth = new Date(now.getFullYear(), now.getMonth(), 0, 23, 59, 59, 999);
this.logger.debug( this.logger.debug(
`Product sales pie chart query params: restId=${restId}, startDate=${startDate.toISOString()}, endDate=${endDate.toISOString()}`, `Product sales pie chart query params: shopId=${shopId}, startDate=${startDate.toISOString()}, endDate=${endDate.toISOString()}`,
); );
// Diagnostic query to check what orders exist // Diagnostic query to check what orders exist
@@ -523,9 +472,9 @@ export class OrdersService {
ORDER BY o.created_at DESC ORDER BY o.created_at DESC
LIMIT 10 LIMIT 10
`, `,
[restId], [shopId],
); );
this.logger.debug(`Diagnostic: Found ${diagnosticResult.length} recent orders for shop ${restId}`); this.logger.debug(`Diagnostic: Found ${diagnosticResult.length} recent orders for shop ${shopId}`);
if (diagnosticResult.length > 0) { if (diagnosticResult.length > 0) {
this.logger.debug(`Sample order: status=${diagnosticResult[0].status}, created_at=${diagnosticResult[0].created_at}`); this.logger.debug(`Sample order: status=${diagnosticResult[0].status}, created_at=${diagnosticResult[0].created_at}`);
} }
@@ -549,7 +498,7 @@ export class OrdersService {
GROUP BY f.id, f.title GROUP BY f.id, f.title
ORDER BY total_revenue DESC ORDER BY total_revenue DESC
`, `,
[restId, startDate, endDate], [shopId, startDate, endDate],
); );
this.logger.debug(`Product sales pie chart query returned ${result.length} rows`); this.logger.debug(`Product sales pie chart query returned ${result.length} rows`);
@@ -94,7 +94,7 @@ export class PaymentsController {
@ApiOperation({ summary: 'Get shop payment method by ID' }) @ApiOperation({ summary: 'Get shop payment method by ID' })
@ApiParam({ name: 'paymentMethodId', type: 'string', description: 'Payment method ID' }) @ApiParam({ name: 'paymentMethodId', type: 'string', description: 'Payment method ID' })
findOneRestaurantPaymentMethod(@Param('paymentMethodId') paymentMethodId: string) { findOneRestaurantPaymentMethod(@Param('paymentMethodId') paymentMethodId: string) {
return this.paymentMethodService.findOne(paymentMethodId); return this.paymentMethodService.findOneOrFail(paymentMethodId);
} }
@UseGuards(AdminAuthGuard) @UseGuards(AdminAuthGuard)
@@ -34,7 +34,7 @@ export class PaymentMethodService {
return this.paymentMethodRepository.findAll({ populate: ['shop'] }); return this.paymentMethodRepository.findAll({ populate: ['shop'] });
} }
async findOne(id: string): Promise<PaymentMethod> { async findOneOrFail(id: string): Promise<PaymentMethod> {
const paymentMethod = await this.paymentMethodRepository.findOne({ id }, { populate: ['shop'] }); const paymentMethod = await this.paymentMethodRepository.findOne({ id }, { populate: ['shop'] });
if (!paymentMethod) { if (!paymentMethod) {
throw new NotFoundException(PaymentMessage.PAYMENT_METHOD_NOT_FOUND); throw new NotFoundException(PaymentMessage.PAYMENT_METHOD_NOT_FOUND);
@@ -47,14 +47,14 @@ export class PaymentMethodService {
} }
async update(id: string, updatePaymentMethodDto: UpdatePaymentMethodDto): Promise<PaymentMethod> { async update(id: string, updatePaymentMethodDto: UpdatePaymentMethodDto): Promise<PaymentMethod> {
const paymentMethod = await this.findOne(id); const paymentMethod = await this.findOneOrFail(id);
this.em.assign(paymentMethod, updatePaymentMethodDto); this.em.assign(paymentMethod, updatePaymentMethodDto);
await this.em.flush(); await this.em.flush();
return paymentMethod; return paymentMethod;
} }
async remove(id: string): Promise<PaymentMethod> { async remove(id: string): Promise<PaymentMethod> {
const paymentMethod = await this.findOne(id); const paymentMethod = await this.findOneOrFail(id);
await this.em.removeAndFlush(paymentMethod); await this.em.removeAndFlush(paymentMethod);
return paymentMethod; return paymentMethod;
} }
@@ -385,4 +385,11 @@ export class UserService {
}); });
} }
async findOneOrFail(userId: string): Promise<User> {
const user = await this.userRepository.findOne({ id: userId });
if (!user) {
throw new NotFoundException(`User with ID ${userId} not found.`);
}
return user;
}
} }