From 9bbab2f400086321934b053f10159830a704f8ec Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Tue, 23 Jun 2026 10:30:29 +0330 Subject: [PATCH] modify create order --- .../orders/controllers/orders.controller.ts | 4 +- .../orders/dto/admin-create-order.dto.ts | 51 +++---------------- .../orders/providers/orders.service.ts | 51 ++++++++++++------- 3 files changed, 41 insertions(+), 65 deletions(-) diff --git a/src/modules/orders/controllers/orders.controller.ts b/src/modules/orders/controllers/orders.controller.ts index 9a901c4..1e0eddc 100644 --- a/src/modules/orders/controllers/orders.controller.ts +++ b/src/modules/orders/controllers/orders.controller.ts @@ -70,10 +70,10 @@ export class OrdersController { @UseGuards(AdminAuthGuard) @Permissions(Permission.MANAGE_ORDERS) @Post('admin/orders') - @ApiOperation({ summary: 'Create an order for a user (by phone) from admin side' }) + @ApiOperation({ summary: 'Create an order for a user from admin side' }) @ApiBody({ type: AdminCreateOrderDto }) createOrderForUser(@RestId() restId: string, @Body() dto: AdminCreateOrderDto) { - return this.ordersService.createOrderForUserByPhone(restId, dto); + return this.ordersService.createOrderForUser(restId, dto); } @UseGuards(AdminAuthGuard) diff --git a/src/modules/orders/dto/admin-create-order.dto.ts b/src/modules/orders/dto/admin-create-order.dto.ts index 65077d8..fb7b05c 100644 --- a/src/modules/orders/dto/admin-create-order.dto.ts +++ b/src/modules/orders/dto/admin-create-order.dto.ts @@ -10,7 +10,7 @@ import { ArrayMinSize, IsNotEmpty, } from 'class-validator'; -import type { OrderCarAddress, OrderUserAddress } from '../interface/order.interface'; +import type { OrderCarAddress } from '../interface/order.interface'; export class AdminOrderItemDto { @ApiProperty({ description: 'Food ID' }) @@ -25,20 +25,10 @@ export class AdminOrderItemDto { } export class AdminCreateOrderDto { - @ApiProperty({ description: 'Phone number of the user to create the order for' }) + @ApiProperty({ description: 'User ID to create the order for' }) @IsString() @IsNotEmpty() - userPhone: string; - - @ApiPropertyOptional({ description: 'First name — used when creating a new user' }) - @IsOptional() - @IsString() - firstName?: string; - - @ApiPropertyOptional({ description: 'Last name — used when creating a new user' }) - @IsOptional() - @IsString() - lastName?: string; + userId: string; @ApiProperty({ type: [AdminOrderItemDto], description: 'Order items' }) @IsArray() @@ -67,21 +57,10 @@ export class AdminCreateOrderDto { @IsString() tableNumber?: string; - @ApiPropertyOptional({ - description: 'User delivery address (required for courier delivery)', - example: { - fullName: 'علی محمدی', - phone: '09121234567', - city: 'تهران', - province: 'تهران', - address: 'خیابان ولیعصر، پلاک ۱۲', - postalCode: '1234567890', - latitude: 35.6892, - longitude: 51.389, - }, - }) + @ApiPropertyOptional({ description: 'Saved user address ID (required for courier delivery)' }) @IsOptional() - userAddress?: OrderUserAddress; + @IsString() + addressId?: string; @ApiPropertyOptional({ description: 'Car address (required for car delivery)', @@ -94,22 +73,4 @@ export class AdminCreateOrderDto { }) @IsOptional() carAddress?: OrderCarAddress; - - @ApiPropertyOptional({ - description: 'Payment description. At least one of paymentDesc or paymentAttachments is required for credit card.', - example: 'Transfer from account ending 1234', - }) - @IsOptional() - @IsString() - paymentDesc?: string; - - @ApiPropertyOptional({ - description: 'Payment receipt attachments (URLs). At least one of paymentDesc or paymentAttachments is required for credit card.', - type: [String], - example: ['https://example.com/receipt.jpg'], - }) - @IsOptional() - @IsArray() - @IsString({ each: true }) - paymentAttachments?: string[]; } diff --git a/src/modules/orders/providers/orders.service.ts b/src/modules/orders/providers/orders.service.ts index e0eeeff..d98f5ea 100644 --- a/src/modules/orders/providers/orders.service.ts +++ b/src/modules/orders/providers/orders.service.ts @@ -3,6 +3,7 @@ import { EntityManager } from '@mikro-orm/postgresql'; import { Order } from '../entities/order.entity'; import { OrderItem } from '../entities/order-item.entity'; import { User } from '../../users/entities/user.entity'; +import { UserAddress } from '../../users/entities/user-address.entity'; import { UserRestaurant } from '../../users/entities/user-restuarant.entity'; import { Restaurant } from '../../restaurants/entities/restaurant.entity'; import { Food } from '../../foods/entities/food.entity'; @@ -27,7 +28,6 @@ import { OrderMessage } from 'src/common/enums/message.enum'; import { AdminCreateOrderDto } from '../dto/admin-create-order.dto'; import { FoodOrderReportDto, FoodOrderReportSortBy } from '../dto/food-order-report.dto'; import { DailyOrderReportDto, DailyOrderReportSortBy } from '../dto/daily-order-report.dto'; -import { normalizePhone } from 'src/modules/utils/phone.util'; type OrderItemData = { food: Food; quantity: number; unitPrice: number; discount: number }; type ValidatedCartForOrder = { @@ -147,18 +147,8 @@ console.log(cart); return { paymentUrl, order }; } - async createOrderForUserByPhone(restaurantId: string, dto: AdminCreateOrderDto): Promise { - const normalizedPhone = normalizePhone(dto.userPhone); - let user = await this.em.findOne(User, { phone: normalizedPhone }); - if (!user) { - user = this.em.create(User, { - phone: normalizedPhone, - firstName: dto.firstName?.trim() || normalizedPhone, - lastName: dto.lastName?.trim(), - }); - await this.em.persistAndFlush(user); - this.logger.debug(`Auto-created user ${user.id} with phone ${normalizedPhone} via admin order`); - } + async createOrderForUser(restaurantId: string, dto: AdminCreateOrderDto): Promise { + const user = await this.getUserOrFail(dto.userId); const [restaurant, delivery] = await Promise.all([ this.getRestaurantOrFail(restaurantId), @@ -167,10 +157,14 @@ console.log(cart); const paymentMethod = await this.getPaymentMethodOrFail(dto.paymentMethodId, restaurantId); this.assertPaymentMethodEnabled(paymentMethod); - this.assertCreditCardPaymentDetails(paymentMethod, dto.paymentDesc, dto.paymentAttachments); this.assertAdminDeliveryRequirements(dto, delivery); + const userAddress = + delivery.method === DeliveryMethodEnum.DeliveryCourier + ? await this.resolveUserAddressForOrder(user, dto.addressId!) + : null; + const orderItemsData = await this.buildOrderItemsDataFromDto(dto.items, restaurantId); const subTotal = orderItemsData.reduce((sum, item) => sum + item.unitPrice * item.quantity, 0); @@ -185,7 +179,7 @@ console.log(cart); user, restaurant, deliveryMethod: delivery, - userAddress: delivery.method === DeliveryMethodEnum.DeliveryCourier ? (dto.userAddress ?? null) : null, + userAddress, carAddress: delivery.method === DeliveryMethodEnum.DeliveryCar ? (dto.carAddress ?? null) : null, paymentMethod, couponDiscount: 0, @@ -219,7 +213,6 @@ console.log(cart); status: PaymentStatusEnum.Pending, method: order.paymentMethod.method, gateway: order.paymentMethod.gateway ?? null, - ...this.buildCreditCardPaymentFields(paymentMethod, dto.paymentDesc, dto.paymentAttachments), }); em.persist(payment); @@ -229,7 +222,7 @@ console.log(cart); await this.inventoryService.deductFromInventory(em, bulkReserveFoodDto); await em.flush(); - this.logger.debug(`Admin created order ${order.id} for user ${user.id} (phone: ${normalizedPhone}, restaurant: ${restaurantId})`); + this.logger.debug(`Admin created order ${order.id} for user ${user.id} (restaurant: ${restaurantId})`); return order; }); @@ -467,6 +460,28 @@ console.log(cart); return user; } + private async resolveUserAddressForOrder(user: User, addressId: string): Promise { + const address = await this.em.findOne(UserAddress, { + id: addressId, + user: { id: user.id }, + }); + + if (!address) { + throw new NotFoundException(`Address with ID ${addressId} not found for user ${user.id}.`); + } + + return { + fullName: [user.firstName, user.lastName].filter(Boolean).join(' '), + phone: address.phone || user.phone, + city: address.city, + province: address.province || '', + address: address.address, + postalCode: address.postalCode ?? undefined, + latitude: address.latitude, + longitude: address.longitude, + }; + } + private async getRestaurantOrFail(restaurantId: string): Promise { const restaurant = await this.em.findOne(Restaurant, { id: restaurantId }); if (!restaurant) throw new NotFoundException(OrderMessage.RESTAURANT_NOT_FOUND); @@ -619,7 +634,7 @@ console.log(cart); } } - if (delivery.method === DeliveryMethodEnum.DeliveryCourier && !dto.userAddress) { + if (delivery.method === DeliveryMethodEnum.DeliveryCourier && !dto.addressId) { throw new BadRequestException(OrderMessage.ADDRESS_REQUIRED); }