add item to invoice

This commit is contained in:
2026-01-24 11:47:44 +03:30
parent 49390ce62e
commit bdc76689a5
4 changed files with 122 additions and 43 deletions
@@ -63,12 +63,12 @@ export class OrderController {
return this.orderService.hardDeleteOrder(orderId); return this.orderService.hardDeleteOrder(orderId);
} }
@Post('admin/orders/:orderId/add-item') // @Post('admin/orders/:orderId/add-item')
@UseGuards(AuthGuard) // @UseGuards(AuthGuard)
@ApiOperation({ summary: 'add item to Order ' }) // @ApiOperation({ summary: 'add item to Order ' })
addItem(@Param('orderId') orderId: string, @Body() body: AddOrderItemDto) { // addItem(@Param('orderId') orderId: string, @Body() body: AddOrderItemDto) {
return this.orderService.addOrderItem(orderId, body); // return this.orderService.addOrderItem(orderId, body);
} // }
@Post('admin/orders/:orderId/create-invoice') @Post('admin/orders/:orderId/create-invoice')
@UseGuards(AuthGuard) @UseGuards(AuthGuard)
+48 -2
View File
@@ -2,9 +2,10 @@ import {
IsInt, IsArray, IsNumber, IsInt, IsArray, IsNumber,
IsNotEmpty, IsNotEmpty,
ArrayMinSize, ArrayMinSize,
IsBoolean IsBoolean,
IsString
} from 'class-validator'; } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
export class InvoiceItemDto { export class InvoiceItemDto {
@@ -20,6 +21,33 @@ export class InvoiceItemDto {
@IsNumber() @IsNumber()
discount: number discount: number
@ApiProperty()
@IsNumber()
quantity: number
}
export class InvoiceNewItemDto {
@IsNumber()
@ApiProperty()
productId: number;
@ApiProperty()
@IsArray()
attributesValues: string[]
@ApiProperty()
@IsNumber()
quantity: number
@ApiProperty()
@IsNumber()
unitPrice: number
@ApiProperty()
@IsNumber()
discount: number
} }
export class CreateInvoiceDto { export class CreateInvoiceDto {
@@ -37,9 +65,27 @@ export class CreateInvoiceDto {
@Type(() => InvoiceItemDto) @Type(() => InvoiceItemDto)
items: InvoiceItemDto[]; items: InvoiceItemDto[];
@IsArray()
@ApiProperty({
isArray: true, type: [InvoiceItemDto], example: [
{
orderItemId: 1,
unitPrice: 100,
}
]
})
@Type(() => InvoiceNewItemDto)
newItems: InvoiceNewItemDto[];
@ApiProperty() @ApiProperty()
@IsBoolean() @IsBoolean()
enableTax: boolean enableTax: boolean
@ApiPropertyOptional({ example: [] })
@IsArray()
@IsString({ each: true })
attachments: string[]
} }
@@ -100,6 +100,9 @@ export class Order extends BaseEntity {
@Property({ type: 'json', nullable: true }) @Property({ type: 'json', nullable: true })
attachments?: string[] attachments?: string[]
@Property({ type: 'string', nullable: true })
paymentMethod?: string;
@BeforeCreate() @BeforeCreate()
async generateOrderNumber(args: EventArgs<Order>) { async generateOrderNumber(args: EventArgs<Order>) {
const em = args.em; const em = args.em;
+65 -35
View File
@@ -54,7 +54,7 @@ export class OrderService {
paidAmount: 0, paidAmount: 0,
balance: 0, balance: 0,
status: OrderStatusEnum.DRAFT, status: OrderStatusEnum.DRAFT,
taxAmount: 0 taxAmount: 0,
}) })
em.persist(order) em.persist(order)
@@ -202,14 +202,14 @@ export class OrderService {
} }
async createInvoice(orderId: string, dto: CreateInvoiceDto) { async createInvoice(orderId: string, dto: CreateInvoiceDto) {
const { items, enableTax } = dto const { items, enableTax, attachments, newItems } = dto
const targetOrder = await this.findOneOrFail(orderId) const targetOrder = await this.findOneOrFail(orderId)
if (items.length !== targetOrder.items.length) { if (items.length !== targetOrder.items.length) {
throw new BadRequestException("One or more order items price is not set") throw new BadRequestException("One or more order items price is not set")
} }
//TODO : calc is not correct
const order = await this.em.transactional(async (em) => { const order = await this.em.transactional(async (em) => {
@@ -234,6 +234,33 @@ export class OrderService {
} }
newItems.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
})
subTotal += item.unitPrice
this.em.persist(newOrderItem)
})
// calculate order financials // calculate order financials
targetOrder.subTotal = subTotal targetOrder.subTotal = subTotal
targetOrder.discount = totalDiscount targetOrder.discount = totalDiscount
@@ -249,6 +276,9 @@ export class OrderService {
targetOrder.total = total + tax targetOrder.total = total + tax
targetOrder.balance = total + tax targetOrder.balance = total + tax
if (attachments.length) {
order.attachments = attachments
}
// change status // change status
targetOrder.status = OrderStatusEnum.INVOICED targetOrder.status = OrderStatusEnum.INVOICED
@@ -325,40 +355,40 @@ export class OrderService {
} }
async addOrderItem(orderId: string, dto: AddOrderItemDto) { // async addOrderItem(orderId: string, dto: AddOrderItemDto) {
const order = await this.orderRepository.findOne({ id: orderId }) // const order = await this.orderRepository.findOne({ id: orderId })
if (!order) { // if (!order) {
throw new BadRequestException("Order not Found!") // throw new BadRequestException("Order not Found!")
} // }
const { items } = dto // const { items } = dto
items.forEach(async item => { // items.forEach(async item => {
const found = order.items.find((it => Number(it.product.id) === item.productId)) // const found = order.items.find((it => Number(it.product.id) === item.productId))
if (found) { // if (found) {
throw new BadRequestException("Product already exist!") // throw new BadRequestException("Product already exist!")
} // }
const product = await this.productRepository.findOne({ id: item.productId }) // const product = await this.productRepository.findOne({ id: item.productId })
if (!product) { // if (!product) {
throw new BadRequestException("Product not found!") // throw new BadRequestException("Product not found!")
} // }
const newOrderItem = this.orderItemRepository.create({ // const newOrderItem = this.orderItemRepository.create({
discount: item.discount, // discount: item.discount,
product, // product,
unitPrice: item.unitPrice, // unitPrice: item.unitPrice,
total: (item.unitPrice - item.discount) * item.quantity, // total: (item.unitPrice - item.discount) * item.quantity,
subTotal: item.unitPrice * item.quantity, // subTotal: item.unitPrice * item.quantity,
quantity: item.quantity, // quantity: item.quantity,
status: OrderItemStatus.CONFIRMED, // status: OrderItemStatus.CONFIRMED,
attributesValues: item.attributesValues, // attributesValues: item.attributesValues,
order // order
}) // })
this.em.persist(newOrderItem) // this.em.persist(newOrderItem)
}) // })
// need calculate order finacial // // need calculate order finacial
await this.em.flush() // await this.em.flush()
return order // return order
} // }
} }