add order item

This commit is contained in:
2026-01-22 11:24:11 +03:30
parent f2d30af119
commit e53c574931
5 changed files with 119 additions and 18 deletions
@@ -11,6 +11,7 @@ import { CreateInvoiceDto } from '../dto/create-invoice.dto';
import { AdminId } from 'src/common/decorators/admin-id.decorator'; import { AdminId } from 'src/common/decorators/admin-id.decorator';
import { CreateOrderAsAdminDto } from '../dto/create-order-as-admin.dto'; import { CreateOrderAsAdminDto } from '../dto/create-order-as-admin.dto';
import { AssignDesignerDto } from '../dto/assign-designer.dto'; import { AssignDesignerDto } from '../dto/assign-designer.dto';
import { AddOrderItemDto } from '../dto/add-order-item.dto';
@ApiTags('orders') @ApiTags('orders')
@ApiBearerAuth() @ApiBearerAuth()
@@ -61,7 +62,14 @@ export class OrderController {
hardDelete(@Param('orderId') orderId: string) { hardDelete(@Param('orderId') orderId: string) {
return this.orderService.hardDeleteOrder(orderId); return this.orderService.hardDeleteOrder(orderId);
} }
@Post('admin/orders/:orderId/add-item')
@UseGuards(AuthGuard)
@ApiOperation({ summary: 'add item to Order ' })
addItem(@Param('orderId') orderId: string, @Body() body: AddOrderItemDto) {
return this.orderService.addOrderItem(orderId, body);
}
@Post('admin/orders/:orderId/create-invoice') @Post('admin/orders/:orderId/create-invoice')
@UseGuards(AuthGuard) @UseGuards(AuthGuard)
@ApiOperation({ summary: 'Create invoice for new order' }) @ApiOperation({ summary: 'Create invoice for new order' })
@@ -0,0 +1,47 @@
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[];
}
+5 -3
View File
@@ -15,6 +15,10 @@ export class InvoiceItemDto {
@IsNumber() @IsNumber()
unitPrice: number unitPrice: number
@ApiProperty()
@IsNumber()
discount: number
} }
export class CreateInvoiceDto { export class CreateInvoiceDto {
@@ -32,8 +36,6 @@ export class CreateInvoiceDto {
@Type(() => InvoiceItemDto) @Type(() => InvoiceItemDto)
items: InvoiceItemDto[]; items: InvoiceItemDto[];
@ApiProperty()
@IsNumber()
discount: number
} }
@@ -26,9 +26,14 @@ export class OrderItem extends BaseEntity {
@Property({ type: 'decimal', precision: 10, scale: 0 }) @Property({ type: 'decimal', precision: 10, scale: 0 })
unitPrice!: number; unitPrice!: number;
@Property({ type: 'decimal', precision: 10, scale: 0 })
subTotal!: number;
@Property({ type: 'decimal', precision: 10, scale: 0, default: 0 })
discount: number = 0;
@Property({ type: 'decimal', precision: 10, scale: 0 }) @Property({ type: 'decimal', precision: 10, scale: 0 })
totalPrice!: number; total!: number;
@Property({ nullable: true }) @Property({ nullable: true })
description?: string; description?: string;
+52 -13
View File
@@ -1,14 +1,9 @@
import { Injectable, NotFoundException, BadRequestException, Logger } from '@nestjs/common'; import { Injectable, NotFoundException, BadRequestException, Logger } from '@nestjs/common';
import { EntityManager } from '@mikro-orm/postgresql'; import { EntityManager } from '@mikro-orm/postgresql';
import { OrderItem } from '../entities/order-item.entity'; import { OrderItem } from '../entities/order-item.entity';
import { PaymentService } from '../../payment/services/payments.service';
import { OrderRepository } from '../repositories/order.repository'; import { OrderRepository } from '../repositories/order.repository';
import { FindOrdersDto } from '../dto/find-orders.dto'; import { FindOrdersDto } from '../dto/find-orders.dto';
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
import { Payment } from 'src/modules/payment/entities/payment.entity';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events';
import { OrderMessage } from 'src/common/enums/message.enum';
import { CreateOrderDto } from '../dto/create-order.dto'; import { CreateOrderDto } from '../dto/create-order.dto';
import { UserService } from 'src/modules/user/providers/user.service'; import { UserService } from 'src/modules/user/providers/user.service';
import { OrderItemStatus, OrderStatusEnum } from '../interface/order.interface'; import { OrderItemStatus, OrderStatusEnum } from '../interface/order.interface';
@@ -20,6 +15,7 @@ import { TicketRepository } from 'src/modules/ticket/repositories/tickets.reposi
import { CreateInvoiceDto } from '../dto/create-invoice.dto'; import { CreateInvoiceDto } from '../dto/create-invoice.dto';
import { AdminRepository } from 'src/modules/admin/repositories/admin.repository'; import { AdminRepository } from 'src/modules/admin/repositories/admin.repository';
import { CreateOrderAsAdminDto } from '../dto/create-order-as-admin.dto'; import { CreateOrderAsAdminDto } from '../dto/create-order-as-admin.dto';
import { AddOrderItemDto } from '../dto/add-order-item.dto';
@Injectable() @Injectable()
@@ -81,7 +77,9 @@ export class OrderService {
quantity: item.quantity, quantity: item.quantity,
status: OrderItemStatus.PENDING, status: OrderItemStatus.PENDING,
unitPrice: 0, unitPrice: 0,
totalPrice: 0, total: 0,
subTotal: 0,
discount: 0
}) })
em.persist(orderItem) em.persist(orderItem)
}); });
@@ -159,7 +157,9 @@ export class OrderService {
quantity: item.quantity, quantity: item.quantity,
status: OrderItemStatus.CONFIRMED, status: OrderItemStatus.CONFIRMED,
unitPrice: item.unitPrice, unitPrice: item.unitPrice,
totalPrice: item.unitPrice * item.quantity, total: item.unitPrice * item.quantity,
discount: 0,
subTotal: 0
}) })
em.persist(orderItem) em.persist(orderItem)
@@ -200,7 +200,7 @@ export class OrderService {
} }
async createInvoice(orderId: string, dto: CreateInvoiceDto) { async createInvoice(orderId: string, dto: CreateInvoiceDto) {
const { items, discount } = dto const { items } = dto
const targetOrder = await this.findOneOrFail(orderId) const targetOrder = await this.findOneOrFail(orderId)
@@ -212,6 +212,7 @@ export class OrderService {
const order = await this.em.transactional(async (em) => { const order = await this.em.transactional(async (em) => {
let subTotal = 0 let subTotal = 0
let totalDiscount = 0
// Calculate order item finnicials // Calculate order item finnicials
for (let orderItem of targetOrder.items) { for (let orderItem of targetOrder.items) {
@@ -222,9 +223,10 @@ export class OrderService {
} }
// TODO use Deciaml js to calculation // TODO use Deciaml js to calculation
orderItem.unitPrice = found.unitPrice orderItem.unitPrice = found.unitPrice
orderItem.totalPrice = (found.unitPrice) * orderItem.quantity orderItem.subTotal = (found.unitPrice) * orderItem.quantity
subTotal += orderItem.totalPrice
subTotal += orderItem.subTotal
em.persist(orderItem) em.persist(orderItem)
@@ -232,10 +234,10 @@ export class OrderService {
// calculate order financials // calculate order financials
targetOrder.subTotal = subTotal targetOrder.subTotal = subTotal
targetOrder.discount = discount targetOrder.discount = totalDiscount
targetOrder.total = subTotal - discount targetOrder.total = subTotal - totalDiscount
targetOrder.balance = subTotal - discount targetOrder.balance = subTotal - totalDiscount
// change status // change status
targetOrder.status = OrderStatusEnum.INVOICED targetOrder.status = OrderStatusEnum.INVOICED
@@ -311,4 +313,41 @@ export class OrderService {
return { message: "Order deleted successfully" } return { message: "Order deleted successfully" }
} }
async addOrderItem(orderId: string, dto: AddOrderItemDto) {
const order = await this.orderRepository.findOne({ id: orderId })
if (!order) {
throw new BadRequestException("Order not Found!")
}
const { items } = dto
items.forEach(async item => {
const found = order.items.find((it => Number(it.product.id) === item.productId))
if (found) {
throw new BadRequestException("Product already exist!")
}
const product = await this.productRepository.findOne({ id: item.productId })
if (!product) {
throw new BadRequestException("Product not found!")
}
const newOrderItem = this.orderItemRepository.create({
discount: item.discount,
product,
unitPrice: item.unitPrice,
total: (item.unitPrice - item.discount) * item.quantity,
subTotal: item.unitPrice * item.quantity,
quantity: item.quantity,
status: OrderItemStatus.CONFIRMED,
attributesValues: item.attributesValues,
order
})
this.em.persist(newOrderItem)
})
// need calculate order finacial
await this.em.flush()
return order
}
} }