update prepare time
deploy to danak / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-07-01 14:05:39 +03:30
parent bd084e2e63
commit 18f200df9f
6 changed files with 96 additions and 0 deletions
@@ -0,0 +1,13 @@
import { Migration } from '@mikro-orm/migrations';
export class Migration20260701120000_addPrepareTimeToOrders extends Migration {
override async up(): Promise<void> {
this.addSql(`alter table "orders" add column "prepare_time" int null;`);
}
override async down(): Promise<void> {
this.addSql(`alter table "orders" drop column "prepare_time";`);
}
}
+2
View File
@@ -697,6 +697,8 @@ export const enum OrderMessage {
FOOD_NOT_BELONGS_TO_RESTAURANT = 'غذا به این رستوران تعلق ندارد',
CREDIT_CARD_PAYMENT_DETAILS_REQUIRED = 'حداقل یکی از توضیحات پرداخت یا پیوست رسید کارت به کارت الزامی است',
DISCOUNT_AMOUNT_EXCEEDS_ORDER_TOTAL = 'مبلغ تخفیف بیشتر از مبلغ سفارش است',
CANNOT_UPDATE_CANCELED_OR_COMPLETED_ORDER = 'امکان ویرایش سفارش لغو شده یا تکمیل شده وجود ندارد',
NO_FIELDS_TO_UPDATE = 'حداقل یک فیلد برای بروزرسانی الزامی است',
}
export const enum CartMessage {
@@ -12,6 +12,7 @@ import { UpdateOrderStatusDto } from '../dto/update-order-status.dto';
import { Permissions } from 'src/common/decorators/permissions.decorator';
import { Permission } from 'src/common/enums/permission.enum';
import { AdminCreateOrderDto } from '../dto/admin-create-order.dto';
import { AdminUpdateOrderFeesDto } from '../dto/admin-update-order-fees.dto';
import { FoodOrderReportDto } from '../dto/food-order-report.dto';
import { DailyOrderReportDto } from '../dto/daily-order-report.dto';
@@ -113,6 +114,20 @@ export class OrdersController {
return this.ordersService.changeOrderStatus(orderId, restId, status, 'admin', dto?.desc);
}
@UseGuards(AdminAuthGuard)
@Permissions(Permission.MANAGE_ORDERS)
@Patch('admin/orders/:orderId/fees')
@ApiOperation({ summary: 'Update order delivery fee, packing fee, and preparation time' })
@ApiParam({ name: 'orderId', description: 'Order ID' })
@ApiBody({ type: AdminUpdateOrderFeesDto })
updateOrderFees(
@Param('orderId') orderId: string,
@Body() dto: AdminUpdateOrderFeesDto,
@RestId() restId: string,
) {
return this.ordersService.updateOrderFees(orderId, restId, dto);
}
@UseGuards(AdminAuthGuard)
@Permissions(Permission.VIEW_REPORTS)
@ApiOperation({ summary: 'Get Stats for report page' })
@@ -0,0 +1,22 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsNumber, IsOptional, Min } from 'class-validator';
export class AdminUpdateOrderFeesDto {
@ApiPropertyOptional({ description: 'Delivery fee amount', minimum: 0 })
@IsOptional()
@IsNumber()
@Min(0)
deliveryFee?: number;
@ApiPropertyOptional({ description: 'Packing fee amount', minimum: 0 })
@IsOptional()
@IsNumber()
@Min(0)
packingFee?: number;
@ApiPropertyOptional({ description: 'Estimated preparation time in minutes', minimum: 0 })
@IsOptional()
@IsNumber()
@Min(0)
prepareTime?: number;
}
@@ -83,6 +83,9 @@ export class Order extends BaseEntity {
@Property({ type: 'decimal', precision: 10, scale: 0, default: 0 })
packingFee: number = 0;
@Property({ type: 'int', nullable: true })
prepareTime?: number | null;
@Property({ type: 'decimal', precision: 10, scale: 0 })
total!: number;
@@ -26,6 +26,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events';
import { OrderMessage } from 'src/common/enums/message.enum';
import { AdminCreateOrderDto } from '../dto/admin-create-order.dto';
import { AdminUpdateOrderFeesDto } from '../dto/admin-update-order-fees.dto';
import { FoodOrderReportDto, FoodOrderReportSortBy } from '../dto/food-order-report.dto';
import { DailyOrderReportDto, DailyOrderReportSortBy } from '../dto/daily-order-report.dto';
type OrderItemData = { food: Food; quantity: number; unitPrice: number; discount: number };
@@ -243,6 +244,46 @@ export class OrdersService {
return order;
}
async updateOrderFees(orderId: string, restId: string, dto: AdminUpdateOrderFeesDto): Promise<Order> {
if (dto.deliveryFee === undefined && dto.packingFee === undefined && dto.prepareTime === undefined) {
throw new BadRequestException(OrderMessage.NO_FIELDS_TO_UPDATE);
}
const order = await this.getOrderOrFail(orderId, restId);
if ([OrderStatus.CANCELED, OrderStatus.COMPLETED].includes(order.status)) {
throw new BadRequestException(OrderMessage.CANNOT_UPDATE_CANCELED_OR_COMPLETED_ORDER);
}
const feesChanged = dto.deliveryFee !== undefined || dto.packingFee !== undefined;
if (dto.deliveryFee !== undefined) {
order.deliveryFee = dto.deliveryFee;
}
if (dto.packingFee !== undefined) {
order.packingFee = dto.packingFee;
}
if (dto.prepareTime !== undefined) {
order.prepareTime = dto.prepareTime;
}
if (feesChanged) {
order.total = order.subTotal - order.totalDiscount + order.deliveryFee + order.packingFee + order.tax;
const pendingPayment = await this.em.findOne(Payment, {
order: { id: orderId },
status: PaymentStatusEnum.Pending,
});
if (pendingPayment) {
pendingPayment.amount = order.total;
}
}
await this.em.persistAndFlush(order);
return order;
}
/**
* Validates cart and prepares all required data for order creation
*/