diff --git a/src/modules/orders/interface/order-status.ts b/src/modules/orders/interface/order-status.ts index d3bddb4..935e0b4 100644 --- a/src/modules/orders/interface/order-status.ts +++ b/src/modules/orders/interface/order-status.ts @@ -1,20 +1,25 @@ import type { CouponType } from 'src/modules/coupons/interface/coupon'; export enum OrderStatus { + // Initial status Pending = 'pending', + // Cancellation statuses + CancelledBySystem = 'cancelledBySystem', + CancelledByUser = 'cancelledByUser', + RejectedByRestaurant = 'rejectedByRestaurant', + + // Active processing statuses Confirmed = 'confirmed', Preparing = 'preparing', - RejectedByRestaurant = 'rejectedByRestaurant', - CancelledByUser = 'cancelledByUser', - CancelledBySystem = 'cancelledBySystem', - + // Ready for pickup/delivery statuses ReadyForCustomerPickup = 'readyForCustomerPickup', ReadyForDineIn = 'readyForDineIn', ReadyForDeliveryCar = 'readyForDeliveryCar', ReadyForDeliveryCourier = 'readyForDeliveryCourier', + // Final status Delivered = 'delivered', } diff --git a/src/modules/orders/orders.controller.ts b/src/modules/orders/orders.controller.ts index 6f25add..2ac5a28 100644 --- a/src/modules/orders/orders.controller.ts +++ b/src/modules/orders/orders.controller.ts @@ -98,4 +98,13 @@ export class OrdersController { readyForPickup(@Param('orderId') orderId: string, @RestId() restId: string) { return this.ordersService.readyForDelivery(orderId, restId); } + + @UseGuards(AdminAuthGuard) + @ApiBearerAuth() + @Patch('admin/orders/:orderId/delivered') + @ApiOperation({ summary: 'Mark an order as delivered' }) + @ApiParam({ name: 'orderId', description: 'Order ID' }) + markAsDelivered(@Param('orderId') orderId: string, @RestId() restId: string) { + return this.ordersService.markAsDelivered(orderId, restId); + } } diff --git a/src/modules/orders/orders.service.ts b/src/modules/orders/orders.service.ts index edd74cd..e2dfeb7 100644 --- a/src/modules/orders/orders.service.ts +++ b/src/modules/orders/orders.service.ts @@ -287,7 +287,10 @@ export class OrdersService { if (!order) { throw new NotFoundException('Order not found'); } - order.status = OrderStatus.Confirmed; + if (order.status !== OrderStatus.Confirmed) { + throw new BadRequestException('Order must be confirmed before preparing'); + } + order.status = OrderStatus.Preparing; await this.em.persistAndFlush(order); return order; } @@ -344,6 +347,30 @@ export class OrdersService { return order; } + async markAsDelivered(orderId: string, restId: string) { + const order = await this.em.findOne(Order, { id: orderId, restaurant: { id: restId } }); + if (!order) { + throw new NotFoundException('Order not found'); + } + + const readyStatuses = [ + OrderStatus.ReadyForCustomerPickup, + OrderStatus.ReadyForDineIn, + OrderStatus.ReadyForDeliveryCar, + OrderStatus.ReadyForDeliveryCourier, + ]; + + if (!readyStatuses.includes(order.status)) { + throw new BadRequestException( + `Order must be in a ready status to mark as delivered. Current status: ${order.status}`, + ); + } + + order.status = OrderStatus.Delivered; + await this.em.persistAndFlush(order); + return order; + } + /** * Cleanup job to handle abandoned orders (pending payment for >30 minutes) * Runs every 10 minutes to check for abandoned orders