This commit is contained in:
@@ -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";`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -697,6 +697,8 @@ export const enum OrderMessage {
|
|||||||
FOOD_NOT_BELONGS_TO_RESTAURANT = 'غذا به این رستوران تعلق ندارد',
|
FOOD_NOT_BELONGS_TO_RESTAURANT = 'غذا به این رستوران تعلق ندارد',
|
||||||
CREDIT_CARD_PAYMENT_DETAILS_REQUIRED = 'حداقل یکی از توضیحات پرداخت یا پیوست رسید کارت به کارت الزامی است',
|
CREDIT_CARD_PAYMENT_DETAILS_REQUIRED = 'حداقل یکی از توضیحات پرداخت یا پیوست رسید کارت به کارت الزامی است',
|
||||||
DISCOUNT_AMOUNT_EXCEEDS_ORDER_TOTAL = 'مبلغ تخفیف بیشتر از مبلغ سفارش است',
|
DISCOUNT_AMOUNT_EXCEEDS_ORDER_TOTAL = 'مبلغ تخفیف بیشتر از مبلغ سفارش است',
|
||||||
|
CANNOT_UPDATE_CANCELED_OR_COMPLETED_ORDER = 'امکان ویرایش سفارش لغو شده یا تکمیل شده وجود ندارد',
|
||||||
|
NO_FIELDS_TO_UPDATE = 'حداقل یک فیلد برای بروزرسانی الزامی است',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum CartMessage {
|
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 { Permissions } from 'src/common/decorators/permissions.decorator';
|
||||||
import { Permission } from 'src/common/enums/permission.enum';
|
import { Permission } from 'src/common/enums/permission.enum';
|
||||||
import { AdminCreateOrderDto } from '../dto/admin-create-order.dto';
|
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 { FoodOrderReportDto } from '../dto/food-order-report.dto';
|
||||||
import { DailyOrderReportDto } from '../dto/daily-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);
|
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)
|
@UseGuards(AdminAuthGuard)
|
||||||
@Permissions(Permission.VIEW_REPORTS)
|
@Permissions(Permission.VIEW_REPORTS)
|
||||||
@ApiOperation({ summary: 'Get Stats for report page' })
|
@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 })
|
@Property({ type: 'decimal', precision: 10, scale: 0, default: 0 })
|
||||||
packingFee: number = 0;
|
packingFee: number = 0;
|
||||||
|
|
||||||
|
@Property({ type: 'int', nullable: true })
|
||||||
|
prepareTime?: number | null;
|
||||||
|
|
||||||
@Property({ type: 'decimal', precision: 10, scale: 0 })
|
@Property({ type: 'decimal', precision: 10, scale: 0 })
|
||||||
total!: number;
|
total!: number;
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ 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 { AdminCreateOrderDto } from '../dto/admin-create-order.dto';
|
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 { FoodOrderReportDto, FoodOrderReportSortBy } from '../dto/food-order-report.dto';
|
||||||
import { DailyOrderReportDto, DailyOrderReportSortBy } from '../dto/daily-order-report.dto';
|
import { DailyOrderReportDto, DailyOrderReportSortBy } from '../dto/daily-order-report.dto';
|
||||||
type OrderItemData = { food: Food; quantity: number; unitPrice: number; discount: number };
|
type OrderItemData = { food: Food; quantity: number; unitPrice: number; discount: number };
|
||||||
@@ -243,6 +244,46 @@ export class OrdersService {
|
|||||||
return order;
|
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
|
* Validates cart and prepares all required data for order creation
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user