order entity modification

This commit is contained in:
2026-01-27 10:05:35 +03:30
parent 028b670a04
commit b858cbed38
3 changed files with 119 additions and 82 deletions
+54 -17
View File
@@ -10,19 +10,23 @@ import {
PrimaryKey, PrimaryKey,
BeforeCreate, BeforeCreate,
type EventArgs, type EventArgs,
OptionalProps
} from '@mikro-orm/core'; } from '@mikro-orm/core';
import { BaseEntity } from '../../../common/entities/base.entity';
import { OrderStatusEnum } from '../interface/order.interface'; import { OrderStatusEnum } from '../interface/order.interface';
import { User } from '../../user/entities/user.entity'; import { User } from '../../user/entities/user.entity';
import { OrderItem } from './order-item.entity'; import { OrderItem } from './order-item.entity';
import { Payment } from 'src/modules/payment/entities/payment.entity'; import { Payment } from 'src/modules/payment/entities/payment.entity';
import { ulid } from 'ulid'; import { ulid } from 'ulid';
import { Admin } from 'src/modules/admin/entities/admin.entity'; import { Admin } from 'src/modules/admin/entities/admin.entity';
import { PaymentStatusEnum } from 'src/modules/payment/interface/payment';
@Entity({ tableName: 'orders' }) @Entity({ tableName: 'orders' })
@Index({ properties: ['user', 'status'] }) @Index({ properties: ['user', 'status'] })
@Index({ properties: ['status'] }) @Index({ properties: ['status'] })
export class Order extends BaseEntity { export class Order {
[OptionalProps]?: 'createdAt' | 'deletedAt' | 'balance' | 'paidAmount'
| 'discount' | 'subTotal' | 'total' | 'taxAmount';
@PrimaryKey({ type: 'string', columnType: 'char(26)' }) @PrimaryKey({ type: 'string', columnType: 'char(26)' })
id: string = ulid() id: string = ulid()
@@ -55,33 +59,60 @@ export class Order extends BaseEntity {
orderNumber?: number; orderNumber?: number;
@Property({ type: 'decimal', precision: 10, scale: 0, default: null, nullable: true }) // @Property({ type: 'decimal', precision: 10, scale: 0, default: null, nullable: true })
discount?: number; // discount?: number;
get discount(): number {
if (!this.items.isInitialized()) return 0;
return this.items
.getItems()
.reduce((sum, p) => sum + Number(p.discount), 0);
}
@Property({ type: 'decimal', precision: 10, scale: 0, default: null, nullable: true }) // @Property({ type: 'decimal', precision: 10, scale: 0, default: null, nullable: true })
subTotal?: number; // subTotal?: number;
get subTotal(): number {
if (!this.items.isInitialized()) return 0;
return this.items
.getItems()
.reduce((sum, p) => sum + Number(p.subTotal), 0)
}
@Property({ type: 'decimal', precision: 10, scale: 0, default: null, nullable: true }) // @Property({ type: 'decimal', precision: 10, scale: 0, default: null, nullable: true })
taxAmount?: number; // taxAmount?: number;
get taxAmount(): number {
return this.enableTax ? this.total * 0.1 : 0
}
@Property({ type: 'decimal', precision: 10, scale: 0, default: null, nullable: true }) // @Property({ type: 'decimal', precision: 10, scale: 0, default: null, nullable: true })
total?: number; // total?: number;
get total(): number {
return this.subTotal - this.discount + Number(this.taxAmount)
}
@Property({ type: 'decimal', precision: 10, scale: 0, default: null, nullable: true }) // @Property({ type: 'decimal', precision: 10, scale: 0, default: null, nullable: true })
paidAmount?: number; // paidAmount?: number;
// private _balance!: number; // private _balance!: number;
// get balance(): number {
// return this._balance
// }
// set balance(value) { // set balance(value) {
// this._balance = this.total - this.paidAmount // this._balance = this.total - this.paidAmount
// } // }
@Property({ type: 'decimal', precision: 10, scale: 0, default: null, nullable: true })
balance?: number; get paidAmount(): number {
if (!this.payments.isInitialized()) return 0;
return this.payments
.getItems()
.filter(p => p.status == PaymentStatusEnum.Paid)
.reduce((sum, p) => sum + Number(p.amount), 0);
}
get balance(): number {
const total = Number(this.total ?? 0);
return total - this.paidAmount;
}
@Property({ type: 'int', nullable: true }) @Property({ type: 'int', nullable: true })
estimatedDays?: number; // number of days to be done estimatedDays?: number; // number of days to be done
@@ -105,6 +136,12 @@ export class Order extends BaseEntity {
@Property({ type: 'boolean', default: false }) @Property({ type: 'boolean', default: false })
enableTax?: Boolean = false enableTax?: Boolean = false
@Property({ defaultRaw: 'now()', columnType: 'timestamptz' })
createdAt: Date = new Date();
@Property({ nullable: true, columnType: 'timestamptz' })
deletedAt?: Date;
@BeforeCreate() @BeforeCreate()
async generateOrderNumber(args: EventArgs<Order>) { async generateOrderNumber(args: EventArgs<Order>) {
const em = args.em; const em = args.em;
+59 -59
View File
@@ -42,14 +42,16 @@ export class OrderService {
async createOrderAsAdmin(adminId: string, dto: CreateOrderAsAdminDto) { async createOrderAsAdmin(adminId: string, dto: CreateOrderAsAdminDto) {
const order = await this.createOrder({ ...dto, adminId }) const order = await this.createOrder({ ...dto, adminId })
await this.calculateOrder(order) // await this.calculateOrder(order)
this.em.flush() // this.em.flush()
this.logger.log("Order created as admin")
return order return order
} }
async createOrderAsUser(userId: string, dto: CreateOrderDto) { async createOrderAsUser(userId: string, dto: CreateOrderDto) {
const order = await this.createOrder({ ...dto, userId, status: OrderStatusEnum.CREATED }) const order = await this.createOrder({ ...dto, userId, status: OrderStatusEnum.CREATED })
this.logger.log("Order created as admin")
return order return order
} }
@@ -101,13 +103,13 @@ export class OrderService {
throw new BadRequestException("some products not found") throw new BadRequestException("some products not found")
} }
items.forEach(item => { for (const item of items) {
this.persistOrderItem(order, item) this.persistOrderItem(order, item)
}); }
// TODO : calculation must be done after create order // TODO : calculation must be done after create order
await this.calculateOrder(order) // await this.calculateOrder(order)
// await em.flush() // await em.flush()
@@ -131,7 +133,7 @@ export class OrderService {
} }
if (adminId) { if (adminId != undefined) {
const admin = await this.adminRepository.findOne({ id: adminId }) const admin = await this.adminRepository.findOne({ id: adminId })
if (!admin) { if (!admin) {
throw new BadRequestException("Admin not found") throw new BadRequestException("Admin not found")
@@ -140,7 +142,7 @@ export class OrderService {
} }
if (designerId) { if (designerId != undefined) {
const designer = await this.adminRepository.findOne({ id: designerId }) const designer = await this.adminRepository.findOne({ id: designerId })
if (!designer) { if (!designer) {
throw new BadRequestException("designer not found") throw new BadRequestException("designer not found")
@@ -148,31 +150,27 @@ export class OrderService {
order.designer = designer order.designer = designer
} }
if (attachments) { if (attachments != undefined) {
order.attachments = attachments order.attachments = attachments
} }
if (typeof enableTax !== 'undefined') { if (enableTax != undefined) {
order.enableTax = enableTax order.enableTax = enableTax
} }
if (estimatedDays) { if (estimatedDays != undefined) {
order.estimatedDays = estimatedDays order.estimatedDays = estimatedDays
} }
if (paymentMethod) { if (paymentMethod != undefined) {
order.paymentMethod = paymentMethod order.paymentMethod = paymentMethod
} }
if (status) { if (status != undefined) {
order.status = status order.status = status
} }
this.em.persist(order) await this.em.persistAndFlush(order)
await this.calculateOrder(order)
await this.em.flush()
return order return order
} }
@@ -180,11 +178,13 @@ export class OrderService {
async updateOrderAsAdmin(orderId: string, dto: IUpdateOrder) { async updateOrderAsAdmin(orderId: string, dto: IUpdateOrder) {
const order = await this.findOneOrFail(orderId) const order = await this.findOneOrFail(orderId)
await this.updateOrder(order, dto) const updateOrder= await this.updateOrder(order, dto)
const updateOrder = await this.calculateOrder(order) // const updateOrder = await this.calculateOrder(order)
await this.em.flush() // await this.em.flush()
this.logger.log("Order updated as admin")
return updateOrder return updateOrder
} }
@@ -216,9 +216,9 @@ export class OrderService {
await this.em.flush() await this.em.flush()
await this.calculateOrder(undefined, orderId) // await this.calculateOrder(undefined, orderId)
await this.em.flush() // await this.em.flush()
return orderItem return orderItem
} }
@@ -276,9 +276,9 @@ export class OrderService {
const orderItem = await this.updateOrderItem(itemId, dto) const orderItem = await this.updateOrderItem(itemId, dto)
await this.calculateOrder(undefined, orderId) // await this.calculateOrder(undefined, orderId)
await this.em.flush() // await this.em.flush()
return orderItem return orderItem
} }
@@ -337,9 +337,9 @@ export class OrderService {
await this.removeOrderItem(itemId) await this.removeOrderItem(itemId)
await this.calculateOrder(undefined, orderId) // await this.calculateOrder(undefined, orderId)
await this.em.flush() // await this.em.flush()
return true return true
} }
@@ -391,44 +391,44 @@ export class OrderService {
return order return order
} }
async calculateOrder(inputOrder?: Order, orderId?: string) { // async calculateOrder(inputOrder?: Order, orderId?: string) {
let order: undefined | Order = inputOrder // let order: undefined | Order = inputOrder
if (!order && orderId) { // if (!order && orderId) {
order = await this.findOneOrFail(orderId) // order = await this.findOneOrFail(orderId)
} // }
if (!order) { // if (!order) {
throw new BadRequestException("Order not found") // throw new BadRequestException("Order not found")
} // }
// calculate order financials // // calculate order financials
let subTotal = 0 // const subTotal = order.items.reduce((sum, item) => {
let totalDiscount = 0 // return sum + item.subTotal
// }, 0)
// TODO : use reduce // const totalDiscount = order.items.reduce((sum, item) => {
for (let orderItem of order.items) { // return sum + Number(item.discount)
subTotal += orderItem.total // }, 0)
totalDiscount += Number(orderItem.discount)
}
const totalBeforeTax = subTotal - totalDiscount
let tax = 0
if (order.enableTax) { // const totalBeforeTax = subTotal - totalDiscount
tax = 0.1 * totalBeforeTax // let tax = 0
}
const total = totalBeforeTax + tax // if (order.enableTax) {
const paidAmount = await this.paymentRepository.getActualPaidAmount(order.id) // tax = 0.1 * totalBeforeTax
// Update Order financial values // }
order.subTotal = subTotal
order.discount = totalDiscount
order.taxAmount = tax
order.total = total
order.balance = total - paidAmount
return order // const total = totalBeforeTax + tax
}
// // Update Order financial values
// // order.subTotal = subTotal
// // order.discount = totalDiscount
// // order.taxAmount = tax
// // order.total = total
// // order.balance = total - paidAmount
// return order
// }
async confirmOrderItem(userId: string, orderId: string, orderItemId: number) { async confirmOrderItem(userId: string, orderId: string, orderItemId: number) {
@@ -477,7 +477,7 @@ export class OrderService {
throw new BadRequestException("Order not found") throw new BadRequestException("Order not found")
} }
if (![OrderStatusEnum.CREATED, 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 Draft or Invoiced")
} }
if (order.payments.length > 0) { if (order.payments.length > 0) {
throw new BadRequestException("order with payments can not be deleted!") throw new BadRequestException("order with payments can not be deleted!")
@@ -522,7 +522,7 @@ export class OrderService {
async createInvoice(orderId: string) { async createInvoice(orderId: string) {
const order = await this.findOneOrFail(orderId) const order = await this.findOneOrFail(orderId)
await this.updateStatus(orderId, OrderStatusEnum.INVOICED) await this.updateStatus(orderId, OrderStatusEnum.INVOICED)
await this.calculateOrder(order) // await this.calculateOrder(order)
await this.em.flush() await this.em.flush()
} }
} }
@@ -222,8 +222,8 @@ export class PaymentService {
payment.transactionId = referenceId; payment.transactionId = referenceId;
// TODO : use decimal js // TODO : use decimal js
// does need persist or not // does need persist or not
payment.order.paidAmount! += payment.amount // payment.order.paidAmount! += payment.amount
payment.order.balance! -= payment.amount // payment.order.balance! -= payment.amount
await em.flush(); await em.flush();
return payment; return payment;
@@ -261,8 +261,8 @@ export class PaymentService {
payment.failedAt = null; payment.failedAt = null;
// TODO : use decimal js // TODO : use decimal js
payment.order.paidAmount! += payment.amount // payment.order.paidAmount! += payment.amount
payment.order.balance! -= payment.amount // payment.order.balance! -= payment.amount
em.persist(payment); em.persist(payment);
em.persist(payment.order); em.persist(payment.order);
@@ -286,8 +286,8 @@ export class PaymentService {
} }
if (payment.status == PaymentStatusEnum.Paid) { if (payment.status == PaymentStatusEnum.Paid) {
payment.order.paidAmount! -= payment.amount // payment.order.paidAmount! -= payment.amount
payment.order.balance! += payment.amount // payment.order.balance! += payment.amount
em.persistAndFlush(payment.order) em.persistAndFlush(payment.order)
} }