product
This commit is contained in:
@@ -70,12 +70,12 @@ export class OrderController {
|
|||||||
// 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)
|
||||||
@ApiOperation({ summary: 'Create invoice for new order' })
|
// @ApiOperation({ summary: 'Create invoice for new order' })
|
||||||
createInvoice(@Param('orderId') orderId: string, @Body() body: CreateInvoiceDto) {
|
// createInvoice(@Param('orderId') orderId: string, @Body() body: CreateInvoiceDto) {
|
||||||
return this.orderService.createInvoice(orderId, body);
|
// return this.orderService.calculateOrder(orderId, body);
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Post('admin/orders/:orderId/assign-designer')
|
@Post('admin/orders/:orderId/assign-designer')
|
||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import {
|
||||||
|
IsArray, IsNumber,
|
||||||
|
IsNotEmpty,
|
||||||
|
ArrayMinSize,
|
||||||
|
IsBoolean,
|
||||||
|
IsString
|
||||||
|
} from 'class-validator';
|
||||||
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
|
||||||
|
export class InvoiceOrderItemDto {
|
||||||
|
@IsNumber()
|
||||||
|
@ApiProperty()
|
||||||
|
orderItemId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
unitPrice: number
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
discount: number
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
quantity: number
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InvoiceOrderNewItemDto {
|
||||||
|
@IsNumber()
|
||||||
|
@ApiProperty()
|
||||||
|
productId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsArray()
|
||||||
|
attributesValues: string[]
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
quantity: number
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
unitPrice: number
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
discount: number
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateInvoicedOrderDto {
|
||||||
|
@IsArray()
|
||||||
|
@ApiProperty({
|
||||||
|
isArray: true, type: [InvoiceOrderItemDto], example: [
|
||||||
|
{
|
||||||
|
orderItemId: 1,
|
||||||
|
unitPrice: 100,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ArrayMinSize(1, { message: 'At least one product is required' })
|
||||||
|
@Type(() => InvoiceOrderItemDto)
|
||||||
|
items: InvoiceOrderItemDto[];
|
||||||
|
|
||||||
|
@IsArray()
|
||||||
|
@ApiProperty({
|
||||||
|
isArray: true, type: [InvoiceOrderNewItemDto], example: [
|
||||||
|
{
|
||||||
|
orderItemId: 1,
|
||||||
|
unitPrice: 100,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
@Type(() => InvoiceOrderNewItemDto)
|
||||||
|
newItems: InvoiceOrderNewItemDto[];
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
enableTax: boolean
|
||||||
|
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ example: [] })
|
||||||
|
@IsArray()
|
||||||
|
@IsString({ each: true })
|
||||||
|
attachments: string[]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,5 +1 @@
|
|||||||
// import { PartialType } from '@nestjs/swagger';
|
|
||||||
// import { CreateOrderDto } from './create-order.dto';
|
|
||||||
|
|
||||||
// export class UpdateOrderDto extends PartialType(CreateOrderDto) {}
|
|
||||||
export class UpdateOrderDto {}
|
export class UpdateOrderDto {}
|
||||||
|
|||||||
@@ -26,14 +26,16 @@ 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 })
|
get subTotal(): number {
|
||||||
subTotal!: number;
|
return Number(this.unitPrice) * (this.quantity)
|
||||||
|
}
|
||||||
|
|
||||||
@Property({ type: 'decimal', precision: 10, scale: 0, default: 0 })
|
@Property({ type: 'decimal', precision: 10, scale: 0, default: 0 })
|
||||||
discount: number = 0;
|
discount: number = 0;
|
||||||
|
|
||||||
@Property({ type: 'decimal', precision: 10, scale: 0 })
|
get total(): number {
|
||||||
total!: number;
|
return Number(this.subTotal) - Number(this.discount || 0)
|
||||||
|
}
|
||||||
|
|
||||||
@Property({ nullable: true })
|
@Property({ nullable: true })
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|||||||
@@ -102,6 +102,12 @@ export class Order extends BaseEntity {
|
|||||||
@Property({ type: 'string', nullable: true })
|
@Property({ type: 'string', nullable: true })
|
||||||
paymentMethod?: string;
|
paymentMethod?: string;
|
||||||
|
|
||||||
|
@Property({ nullable: true, columnType: 'timestamptz' })
|
||||||
|
invoicedAt?: Date;
|
||||||
|
|
||||||
|
@Property({ type: 'boolean', default: false })
|
||||||
|
enableTax?: Boolean = false
|
||||||
|
|
||||||
@BeforeCreate()
|
@BeforeCreate()
|
||||||
async generateOrderNumber(args: EventArgs<Order>) {
|
async generateOrderNumber(args: EventArgs<Order>) {
|
||||||
const em = args.em;
|
const em = args.em;
|
||||||
|
|||||||
@@ -1,15 +1,28 @@
|
|||||||
export enum OrderStatusEnum {
|
export enum OrderStatusEnum {
|
||||||
DRAFT = 'draft',
|
CREATED = 'created',
|
||||||
|
|
||||||
INVOICED = 'invoiced',
|
INVOICED = 'invoiced',
|
||||||
|
WAITING_to_CONFIRM_INVOICE = 'waiting_to_confirm_invoice',
|
||||||
|
|
||||||
IN_DESIGN = 'in_design',
|
|
||||||
|
DESIGN_INITIATED = 'design_initiated',
|
||||||
|
DESIGN_FINISHED = 'design_finished',
|
||||||
|
DESIGN_REVISION = 'design_revision',
|
||||||
|
|
||||||
|
READY_TO_PRINTING = 'ready_to_printing',
|
||||||
IN_PRINTING = 'in_printing',
|
IN_PRINTING = 'in_printing',
|
||||||
|
|
||||||
|
READY_FOR_DELIVERY = 'ready_for_delivery',
|
||||||
|
DELIVERED = 'delivered',
|
||||||
|
|
||||||
|
AFTER_PRINT_COVER = 'after_print_cover',
|
||||||
|
AFTER_PRINT_BOXING = 'after_print_boxing',
|
||||||
|
AFTER_PRINT_CARTONING = 'after_print_cartoning',
|
||||||
|
|
||||||
|
|
||||||
FINISHED = 'finished',
|
FINISHED = 'finished',
|
||||||
|
|
||||||
CANCELED = 'canceled',
|
CANCELED = 'canceled',
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -52,8 +52,9 @@ export class OrderService {
|
|||||||
total: 0,
|
total: 0,
|
||||||
paidAmount: 0,
|
paidAmount: 0,
|
||||||
balance: 0,
|
balance: 0,
|
||||||
status: OrderStatusEnum.DRAFT,
|
status: OrderStatusEnum.CREATED,
|
||||||
taxAmount: 0,
|
taxAmount: 0,
|
||||||
|
enableTax: false
|
||||||
})
|
})
|
||||||
|
|
||||||
em.persist(order)
|
em.persist(order)
|
||||||
@@ -198,7 +199,47 @@ export class OrderService {
|
|||||||
return order
|
return order
|
||||||
}
|
}
|
||||||
|
|
||||||
async createInvoice(orderId: string, dto: CreateInvoiceDto) {
|
async calculateOrder(orderId: string, em: EntityManager) {
|
||||||
|
|
||||||
|
const targetOrder = await this.findOneOrFail(orderId)
|
||||||
|
|
||||||
|
const order = await this.em.transactional(async (em) => {
|
||||||
|
|
||||||
|
// calculate order financials
|
||||||
|
let subTotal = 0
|
||||||
|
let totalDiscount = 0
|
||||||
|
|
||||||
|
// TODO : use reduce
|
||||||
|
|
||||||
|
for (let orderItem of targetOrder.items) {
|
||||||
|
subTotal += orderItem.total
|
||||||
|
totalDiscount += orderItem.discount
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalBeforeTax = subTotal - totalDiscount
|
||||||
|
let tax = 0
|
||||||
|
|
||||||
|
if (targetOrder.enableTax) {
|
||||||
|
tax = 0.1 * totalBeforeTax
|
||||||
|
}
|
||||||
|
|
||||||
|
const total = totalBeforeTax + tax
|
||||||
|
|
||||||
|
// Update Order financial values
|
||||||
|
targetOrder.subTotal = subTotal
|
||||||
|
targetOrder.discount = totalDiscount
|
||||||
|
targetOrder.taxAmount = tax
|
||||||
|
targetOrder.total = total
|
||||||
|
|
||||||
|
em.persist(targetOrder)
|
||||||
|
|
||||||
|
return targetOrder
|
||||||
|
})
|
||||||
|
|
||||||
|
return order
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateOrder(orderId: string, dto: CreateInvoiceDto) {
|
||||||
const { items, enableTax, attachments, newItems } = dto
|
const { items, enableTax, attachments, newItems } = dto
|
||||||
|
|
||||||
const targetOrder = await this.findOneOrFail(orderId)
|
const targetOrder = await this.findOneOrFail(orderId)
|
||||||
@@ -222,7 +263,7 @@ export class OrderService {
|
|||||||
}
|
}
|
||||||
// TODO use Deciaml js to calculation
|
// TODO use Deciaml js to calculation
|
||||||
orderItem.unitPrice = found.unitPrice
|
orderItem.unitPrice = found.unitPrice
|
||||||
orderItem.subTotal = (found.unitPrice) * orderItem.quantity
|
// orderItem.subTotal = (found.unitPrice) * orderItem.quantity
|
||||||
|
|
||||||
|
|
||||||
subTotal += orderItem.subTotal
|
subTotal += orderItem.subTotal
|
||||||
@@ -279,6 +320,7 @@ export class OrderService {
|
|||||||
|
|
||||||
// change status
|
// change status
|
||||||
targetOrder.status = OrderStatusEnum.INVOICED
|
targetOrder.status = OrderStatusEnum.INVOICED
|
||||||
|
targetOrder.invoicedAt = new Date()
|
||||||
|
|
||||||
em.persist(targetOrder)
|
em.persist(targetOrder)
|
||||||
|
|
||||||
@@ -321,7 +363,7 @@ export class OrderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
order.designer = designer
|
order.designer = designer
|
||||||
order.status = OrderStatusEnum.IN_DESIGN
|
// order.status = OrderStatusEnum.IN_DESIGN
|
||||||
|
|
||||||
|
|
||||||
await this.em.persistAndFlush(order)
|
await this.em.persistAndFlush(order)
|
||||||
@@ -335,7 +377,7 @@ export class OrderService {
|
|||||||
if (!order) {
|
if (!order) {
|
||||||
throw new BadRequestException("Order not found")
|
throw new BadRequestException("Order not found")
|
||||||
}
|
}
|
||||||
if (![OrderStatusEnum.DRAFT, OrderStatusEnum.INVOICED].includes(order.status)) {
|
if (![OrderStatusEnum.CREATED, OrderStatusEnum.INVOICED].includes(order.status)) {
|
||||||
throw new BadRequestException("Order status must be of of Drfat or Invoiced")
|
throw new BadRequestException("Order status must be of of Drfat or Invoiced")
|
||||||
}
|
}
|
||||||
if (order.payments.length > 0) {
|
if (order.payments.length > 0) {
|
||||||
@@ -352,6 +394,18 @@ export class OrderService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateStatus(orderId: string, newStatus: OrderStatusEnum) {
|
||||||
|
const order = await this.orderRepository.findOne({ id: orderId })
|
||||||
|
if (!order) {
|
||||||
|
throw new BadRequestException("Order not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
order.status = newStatus
|
||||||
|
|
||||||
|
await this.em.flush()
|
||||||
|
|
||||||
|
return order
|
||||||
|
}
|
||||||
// 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) {
|
||||||
|
|||||||
@@ -99,6 +99,16 @@ export class productController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* =============================== PRODUCT ================================= */
|
/* =============================== PRODUCT ================================= */
|
||||||
|
@Get('public/products')
|
||||||
|
// @UseGuards(AdminAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Permissions(Permission.MANAGE_PRODUCTS)
|
||||||
|
@ApiOperation({ summary: 'Get list of products' })
|
||||||
|
async findAllAsUser() {
|
||||||
|
const result = await this.productService.findAll({ limit: 1000 });
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Post('admin/product')
|
@Post('admin/product')
|
||||||
// @UseGuards(AdminAuthGuard)
|
// @UseGuards(AdminAuthGuard)
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@@ -160,6 +170,7 @@ export class productController {
|
|||||||
|
|
||||||
|
|
||||||
/*=============================== Attibute ==========================*/
|
/*=============================== Attibute ==========================*/
|
||||||
|
|
||||||
@Post('admin/product/:id/attribute')
|
@Post('admin/product/:id/attribute')
|
||||||
// @UseGuards(AdminAuthGuard)
|
// @UseGuards(AdminAuthGuard)
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
|
|||||||
Reference in New Issue
Block a user