add order item
This commit is contained in:
@@ -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[];
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user