From d53bb75fae46e13b26b8b62485fbbb39753744cc Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Mon, 26 Jan 2026 15:37:11 +0330 Subject: [PATCH] update order --- .../order/controllers/order.controller.ts | 35 ++++--- src/modules/order/dto/add-order-item.dto.ts | 47 --------- .../order/dto/create-order-as-admin.dto.ts | 97 ------------------ src/modules/order/dto/create-order.dto.ts | 99 ++++++++++++++++++- .../order/dto/update-order-as-user.dto.ts | 59 ----------- src/modules/order/dto/update-order.dto.ts | 5 + .../order/entities/order-item.entity.ts | 3 +- .../order/interface/order.interface.ts | 8 +- src/modules/order/providers/order.service.ts | 79 +++++++++++++-- 9 files changed, 200 insertions(+), 232 deletions(-) delete mode 100644 src/modules/order/dto/add-order-item.dto.ts delete mode 100644 src/modules/order/dto/create-order-as-admin.dto.ts delete mode 100644 src/modules/order/dto/update-order-as-user.dto.ts create mode 100644 src/modules/order/dto/update-order.dto.ts diff --git a/src/modules/order/controllers/order.controller.ts b/src/modules/order/controllers/order.controller.ts index ef57dbd..3963917 100644 --- a/src/modules/order/controllers/order.controller.ts +++ b/src/modules/order/controllers/order.controller.ts @@ -4,11 +4,14 @@ import { OrderService } from '../providers/order.service'; import { AuthGuard } from '../../auth/guards/auth.guard'; import { UserId } from '../../../common/decorators/user-id.decorator'; import { FindOrdersDto } from '../dto/find-orders.dto'; -import { CreateOrderDto, CreateOrderItemAsUserDto, CreateOrderItemDtoAsAdmin } from '../dto/create-order.dto'; +import { + CreateOrderDto, CreateOrderItemAsUserDto, + CreateOrderItemDtoAsAdmin, CreateOrderAsAdminDto +} from '../dto/create-order.dto'; import { AdminId } from 'src/common/decorators/admin-id.decorator'; -import { CreateOrderAsAdminDto } from '../dto/create-order-as-admin.dto'; import { AssignDesignerDto } from '../dto/assign-designer.dto'; import { UpdateOrderItemDtoAsAdmin, UpdateOrderItemDtoAsUser } from '../dto/update-order-item.dto'; +import { UpdateOrderDtoAsAdmin } from '../dto/update-order.dto'; @ApiTags('orders') @ApiBearerAuth() @@ -18,14 +21,14 @@ export class OrderController { @Post('public/order') @UseGuards(AuthGuard) - @ApiOperation({ summary: 'create order as user' }) + @ApiOperation({ summary: 'create order ' }) createOrder(@UserId() userId: string, @Body() body: CreateOrderDto) { return this.orderService.createOrderAsUser(userId, body); } @Delete('public/order/:id') @UseGuards(AuthGuard) - @ApiOperation({ summary: 'Delete order as user' }) + @ApiOperation({ summary: 'Delete order ' }) deleteOrder(@Param('id') orderId: string) { return this.orderService.removeOrderAsUser(orderId); } @@ -41,7 +44,7 @@ export class OrderController { @Patch('public/order/:id/item') @UseGuards(AuthGuard) - @ApiOperation({ summary: 'add item to order as user' }) + @ApiOperation({ summary: 'add item to order ' }) addOrderItem(@Param('id') orderId: string, @UserId() userId: string, @Body() body: CreateOrderItemAsUserDto) { return this.orderService.addOrderItemAsUser(userId, orderId, body); } @@ -49,16 +52,15 @@ export class OrderController { @Patch('public/order/:id/item/:itemId') @UseGuards(AuthGuard) - @ApiOperation({ summary: 'Update order item as user' }) - updateOrder(@Param('id') orderId: string, @UserId() userId: string, @Param(':itemId') itemId: string, @Body() body: UpdateOrderItemDtoAsUser) { + @ApiOperation({ summary: 'Update order item ' }) + updateOrderItem(@Param('id') orderId: string, @UserId() userId: string, @Param(':itemId') itemId: string, @Body() body: UpdateOrderItemDtoAsUser) { return this.orderService.updateOrderItemAsUser(userId, orderId, itemId, body); } - @Post('public/orders/:orderId/items/:orderItemId/confirm') @UseGuards(AuthGuard) - @ApiOperation({ summary: 'Confirm Invoice Item By User' }) + @ApiOperation({ summary: 'Confirm Invoice Item ' }) confirmOrderItem( @Param('orderId') orderId: string, @Param('orderItemId') orderItemId: string, @@ -69,7 +71,7 @@ export class OrderController { @Delete('public/orders/:orderId/items/:orderItemId') @UseGuards(AuthGuard) - @ApiOperation({ summary: 'Remove order Item By User' }) + @ApiOperation({ summary: 'Remove order Item ' }) removeOrderItem( @Param('orderId') orderId: string, @Param('orderItemId') orderItemId: string, @@ -82,11 +84,18 @@ export class OrderController { @Post('admin/order') @UseGuards(AuthGuard) - @ApiOperation({ summary: 'create order as admin' }) + @ApiOperation({ summary: 'create order ' }) createOrderAsAdmin(@AdminId() adminId: string, @Body() body: CreateOrderAsAdminDto) { return this.orderService.createOrderAsAdmin(adminId, body); } + @Patch('admin/orders/:orderId') + @UseGuards(AuthGuard) + @ApiOperation({ summary: 'Update Order ' }) + updateOrder(@Param('orderId') orderId: string, @Body() dto: UpdateOrderDtoAsAdmin) { + return this.orderService.updateOrder(orderId, dto); + } + @Delete('admin/orders/:orderId') @UseGuards(AuthGuard) @ApiOperation({ summary: 'Hard Delete Order ' }) @@ -112,7 +121,7 @@ export class OrderController { @Delete('admin/orders/:orderId/items/:orderItemId') @UseGuards(AuthGuard) - @ApiOperation({ summary: 'Remove order Item By Admin' }) + @ApiOperation({ summary: 'Remove order Item ' }) removeOrderItemAdAdmin( @Param('orderId') orderId: string, @Param('orderItemId') orderItemId: string, @@ -122,7 +131,7 @@ export class OrderController { @Patch('admin/order/:id/item') @UseGuards(AuthGuard) - @ApiOperation({ summary: 'add item to order By Admin' }) + @ApiOperation({ summary: 'add item to order ' }) addOrderItemAsAdmin(@Param('id') orderId: string, @Body() body: CreateOrderItemDtoAsAdmin) { return this.orderService.addOrderItemAsAdmin(orderId, body); } diff --git a/src/modules/order/dto/add-order-item.dto.ts b/src/modules/order/dto/add-order-item.dto.ts deleted file mode 100644 index 62ebc8d..0000000 --- a/src/modules/order/dto/add-order-item.dto.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - IsArray, IsNumber, - IsNotEmpty, - ArrayMinSize -} from 'class-validator'; -import { ApiProperty } from '@nestjs/swagger'; -import { Type } from 'class-transformer'; - -export class InvoiceItemDto { - @IsNumber() - @ApiProperty() - productId: number; - - @ApiProperty() - @IsArray() - attributesValues: string[] - - @ApiProperty() - @IsNumber() - quantity: number - - @ApiProperty() - @IsNumber() - unitPrice: number - - @ApiProperty() - @IsNumber() - discount: number - -} - -export class AddOrderItemDto { - @IsArray() - @ApiProperty({ - isArray: true, type: [InvoiceItemDto], example: [ - { - orderItemId: 1, - unitPrice: 100, - } - ] - }) - @IsNotEmpty() - @ArrayMinSize(1, { message: 'At least one product is required' }) - @Type(() => InvoiceItemDto) - items: InvoiceItemDto[]; -} - diff --git a/src/modules/order/dto/create-order-as-admin.dto.ts b/src/modules/order/dto/create-order-as-admin.dto.ts deleted file mode 100644 index 6e1bcf2..0000000 --- a/src/modules/order/dto/create-order-as-admin.dto.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { - IsString, - IsInt, IsArray, IsNumber, - IsNotEmpty, - ArrayMinSize, - IsMobilePhone, - IsOptional, - IsBoolean, - IsEnum -} from 'class-validator'; -import { ApiPropertyOptional, ApiProperty } from '@nestjs/swagger'; -import { Type } from 'class-transformer'; -import { OrderStatusEnum } from '../interface/order.interface'; - -export class CreateOrderItemDto { - - @IsInt() - @ApiProperty() - productId: bigint; - - @ApiProperty() - @IsNumber() - quantity: number - - @ApiProperty() - @IsArray() - attributesValues: string[] - - @ApiProperty() - @IsNumber() - unitPrice: number - - @ApiProperty() - @IsNumber() - discount: number - - @ApiPropertyOptional({ example: 'توضیحات' }) - @IsString() - description: string - - @ApiPropertyOptional({ example: [] }) - @IsArray() - @IsString({ each: true }) - attachments: { url: string, type: string }[] -} - -export class CreateOrderAsAdminDto { - @ApiProperty({ example: '' }) - @IsString() - @IsNotEmpty() - userId: string - - @IsArray() - @ApiProperty({ - isArray: true, type: [CreateOrderItemDto], example: [ - { - productId: 1, - quantity: 100, - attributesValues: [] - } - ] - }) - @IsNotEmpty() - @ArrayMinSize(1, { message: 'At least one product is required' }) - @Type(() => CreateOrderItemDto) - items: CreateOrderItemDto[]; - - @ApiProperty({ example: '' }) - @IsString() - @IsNotEmpty() - designerId: string - - @ApiProperty({ example: '' }) - @IsArray() - @IsString({ each: true }) - @IsNotEmpty() - attachments: string[] - - @ApiProperty({}) - @IsString() - @IsOptional() - paymentMethod: string - - @ApiProperty({}) - @IsBoolean() - enableTax: Boolean - - @ApiProperty({}) - @IsInt() - estimatedDays: number - - @ApiProperty({ enum: OrderStatusEnum }) - @IsEnum(OrderStatusEnum) - status: OrderStatusEnum - -} - diff --git a/src/modules/order/dto/create-order.dto.ts b/src/modules/order/dto/create-order.dto.ts index c85015c..2e96169 100644 --- a/src/modules/order/dto/create-order.dto.ts +++ b/src/modules/order/dto/create-order.dto.ts @@ -2,10 +2,14 @@ import { IsString, IsInt, IsArray, IsNumber, IsNotEmpty, - ArrayMinSize + ArrayMinSize, + IsOptional, + IsBoolean, + IsEnum } from 'class-validator'; import { ApiPropertyOptional, ApiProperty, OmitType } from '@nestjs/swagger'; import { Type } from 'class-transformer'; +import { IAttribute, OrderStatusEnum } from '../interface/order.interface'; export class CreateOrderItemDtoAsAdmin { @@ -16,10 +20,10 @@ export class CreateOrderItemDtoAsAdmin { @ApiProperty() @IsNumber() quantity: number - // TODO : find a way to save attribute and value + @ApiProperty() @IsArray() - attributesValues: string[] + attributes: IAttribute[] @ApiPropertyOptional({ example: 'توضیحات' }) @IsString() @@ -49,7 +53,12 @@ export class CreateOrderDto { { productId: 1, quantity: 100, - attributesValues: [], + attributes: [ + { + attributeId:1, + value:'string | boolean| number' + } + ], attachments: [ { url: '', type: '' } ], @@ -63,3 +72,85 @@ export class CreateOrderDto { items: CreateOrderItemAsUserDto[]; } +export class CreateOrderItemDto { + + @IsInt() + @ApiProperty() + productId: bigint; + + @ApiProperty() + @IsNumber() + quantity: number + + @ApiProperty() + @IsArray() + attributes: IAttribute[] + + @ApiProperty() + @IsNumber() + unitPrice: number + + @ApiProperty() + @IsNumber() + discount: number + + @ApiPropertyOptional({ example: 'توضیحات' }) + @IsString() + description: string + + @ApiPropertyOptional({ example: [] }) + @IsArray() + @IsString({ each: true }) + attachments: { url: string, type: string }[] +} + +export class CreateOrderAsAdminDto { + @ApiProperty({ example: '' }) + @IsString() + @IsNotEmpty() + userId: string + + @IsArray() + @ApiProperty({ + isArray: true, type: [CreateOrderItemDto], example: [ + { + productId: 1, + quantity: 100, + attributesValues: [] + } + ] + }) + @IsNotEmpty() + @ArrayMinSize(1, { message: 'At least one product is required' }) + @Type(() => CreateOrderItemDto) + items: CreateOrderItemDto[]; + + @ApiProperty({ example: '' }) + @IsString() + @IsNotEmpty() + designerId: string + + @ApiProperty({ example: '' }) + @IsArray() + @IsString({ each: true }) + @IsNotEmpty() + attachments: string[] + + @ApiProperty({}) + @IsString() + @IsOptional() + paymentMethod: string + + @ApiProperty({}) + @IsBoolean() + enableTax: Boolean + + @ApiProperty({}) + @IsInt() + estimatedDays: number + + @ApiProperty({ enum: OrderStatusEnum }) + @IsEnum(OrderStatusEnum) + status: OrderStatusEnum + +} diff --git a/src/modules/order/dto/update-order-as-user.dto.ts b/src/modules/order/dto/update-order-as-user.dto.ts deleted file mode 100644 index b2a2114..0000000 --- a/src/modules/order/dto/update-order-as-user.dto.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - IsArray, IsNumber, - IsNotEmpty, - ArrayMinSize, - IsBoolean, - IsString -} from 'class-validator'; -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { Type } from 'class-transformer'; - -export class ItemDto { - @IsNumber() - @ApiProperty() - orderItemId: number; - - @ApiProperty() - @IsNumber() - unitPrice: number - - @ApiProperty() - @IsNumber() - discount: number - - @ApiProperty() - @IsNumber() - quantity: number - -} - - - -export class UpdateOrderDtoAsUser { - @IsArray() - @ApiProperty({ - isArray: true, type: [ItemDto], example: [ - { - orderItemId: 1, - unitPrice: 100, - } - ] - }) - @IsNotEmpty() - @ArrayMinSize(1, { message: 'At least one product is required' }) - @Type(() => ItemDto) - items: ItemDto[]; - - - @ApiProperty() - @IsBoolean() - enableTax: boolean - - - @ApiPropertyOptional({ example: [] }) - @IsArray() - @IsString({ each: true }) - attachments: string[] - -} - diff --git a/src/modules/order/dto/update-order.dto.ts b/src/modules/order/dto/update-order.dto.ts new file mode 100644 index 0000000..b86918c --- /dev/null +++ b/src/modules/order/dto/update-order.dto.ts @@ -0,0 +1,5 @@ +import { OmitType, PartialType } from '@nestjs/swagger'; +import { CreateOrderAsAdminDto, CreateOrderDto } from './create-order.dto'; + +export class UpdateOrderDtoAsAdmin extends PartialType(OmitType(CreateOrderAsAdminDto, 'items' as any)) { } + diff --git a/src/modules/order/entities/order-item.entity.ts b/src/modules/order/entities/order-item.entity.ts index 0e8efd7..73378e5 100644 --- a/src/modules/order/entities/order-item.entity.ts +++ b/src/modules/order/entities/order-item.entity.ts @@ -2,6 +2,7 @@ import { Entity, Index, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core' import { BaseEntity } from '../../../common/entities/base.entity'; import { Order } from './order.entity'; import { Product } from 'src/modules/product/entities/product.entity'; +import { IAttribute } from '../interface/order.interface'; // import { OrderItemStatus } from '../interface/order.interface'; @Entity({ tableName: 'order_items' }) @@ -17,7 +18,7 @@ export class OrderItem extends BaseEntity { product!: Product; @Property({ type: 'json' }) - attributesValues: string[] + attributes: IAttribute[] @Property({ type: 'int' }) quantity!: number; diff --git a/src/modules/order/interface/order.interface.ts b/src/modules/order/interface/order.interface.ts index b7f54de..cd123c4 100644 --- a/src/modules/order/interface/order.interface.ts +++ b/src/modules/order/interface/order.interface.ts @@ -29,7 +29,7 @@ export enum OrderStatusEnum { export interface IAddOrderItem { productId: bigint; quantity: number - attributesValues: string[] + attributes: IAttribute[] description: string attachments: { url: string, type: string }[] unitPrice?: number @@ -49,4 +49,8 @@ export interface ICreateOrder { adminId?: string estimatedDays?: number designerId?: string -} \ No newline at end of file +} + +export type IUpdateOrder = Partial> + +export interface IAttribute { attributeId: number, value: string | number | boolean } \ No newline at end of file diff --git a/src/modules/order/providers/order.service.ts b/src/modules/order/providers/order.service.ts index 32685a2..61adc8b 100644 --- a/src/modules/order/providers/order.service.ts +++ b/src/modules/order/providers/order.service.ts @@ -4,20 +4,21 @@ import { OrderItem } from '../entities/order-item.entity'; import { OrderRepository } from '../repositories/order.repository'; import { FindOrdersDto } from '../dto/find-orders.dto'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { CreateOrderDto, CreateOrderItemAsUserDto, CreateOrderItemDtoAsAdmin } from '../dto/create-order.dto'; +import { + CreateOrderDto, CreateOrderItemAsUserDto, + CreateOrderItemDtoAsAdmin, CreateOrderAsAdminDto +} from '../dto/create-order.dto'; import { UserService } from 'src/modules/user/providers/user.service'; -import { IAddOrderItem, ICreateOrder, OrderStatusEnum, IUpdateOrderItem } from '../interface/order.interface'; +import { IAddOrderItem, ICreateOrder, OrderStatusEnum, IUpdateOrderItem, IUpdateOrder } from '../interface/order.interface'; import { OrderItemRepository } from '../repositories/order-item.repository'; import { ProductService } from 'src/modules/product/providers/product.service'; import { ProductRepository } from 'src/modules/product/repositories/product.repository'; import { TicketService } from 'src/modules/ticket/providers/tickets.service'; import { TicketRepository } from 'src/modules/ticket/repositories/tickets.repository'; import { AdminRepository } from 'src/modules/admin/repositories/admin.repository'; -import { CreateOrderAsAdminDto } from '../dto/create-order-as-admin.dto'; import { Order } from '../entities/order.entity'; import { PaymentRepository } from 'src/modules/payment/repositories/payment.repository'; import { UpdateOrderItemDtoAsAdmin, UpdateOrderItemDtoAsUser } from '../dto/update-order-item.dto'; -import { UpdateOrderDtoAsUser } from '../dto/update-order-as-user.dto'; import { Admin } from 'src/modules/admin/entities/admin.entity'; @@ -117,6 +118,66 @@ export class OrderService { } + async updateOrder(orderId: string, dto: IUpdateOrder) { + const { attachments, adminId, designerId, enableTax, estimatedDays, paymentMethod, status, userId } = dto + + const order = await this.findOneOrFail(orderId) + + if (userId) { + const user = await this.userService.findById(userId) + if (!user) { + throw new BadRequestException("User not found!") + } + order.user = user + } + + + if (adminId) { + const admin = await this.adminRepository.findOne({ id: adminId }) + if (!admin) { + throw new BadRequestException("Admin not found") + } + order.creator = admin + } + + + if (designerId) { + const designer = await this.adminRepository.findOne({ id: designerId }) + if (!designer) { + throw new BadRequestException("designer not found") + } + order.designer = designer + } + + if (attachments) { + order.attachments = attachments + } + + if (typeof enableTax !== 'undefined') { + order.enableTax = enableTax + } + + if (estimatedDays) { + order.estimatedDays = estimatedDays + } + + if (paymentMethod) { + order.paymentMethod = paymentMethod + } + + if (status) { + order.status = status + } + + this.em.persist(order) + + await this.calculateOrder(order) + + await this.em.flush() + + return order + } + async addOrderItemAsUser(userId: string, orderId: string, dto: CreateOrderItemAsUserDto) { const order = await this.findOneOrFail(orderId) @@ -152,7 +213,7 @@ export class OrderService { } private async persistOrderItem(order: Order, dto: IAddOrderItem) { - const { attributesValues, description, productId, quantity, attachments, discount, unitPrice } = dto + const { attributes, description, productId, quantity, attachments, discount, unitPrice } = dto const found = order.items.find(it => it.product.id == productId) if (found) { @@ -165,7 +226,7 @@ export class OrderService { } const orderItem = this.orderItemRepository.create({ order, - attributesValues, + attributes, description, quantity, attachments, @@ -212,7 +273,7 @@ export class OrderService { } async updateOrderItem(itemId: string, dto: IUpdateOrderItem) { - const { attributesValues, description, productId, quantity, attachments, discount, unitPrice } = dto + const { attributes, description, productId, quantity, attachments, discount, unitPrice } = dto const orderItem = await this.orderItemRepository.findOne({ id: itemId @@ -233,8 +294,8 @@ export class OrderService { orderItem.product = product } - if (attributesValues) { - orderItem.attributesValues = attributesValues + if (attributes) { + orderItem.attributes = attributes } if (description) { orderItem.description = description