This commit is contained in:
2026-01-25 15:05:01 +03:30
parent bca1932ae3
commit 55856a40f1
6 changed files with 62 additions and 46 deletions
@@ -53,7 +53,7 @@ export class OrderController {
@UseGuards(AuthGuard)
@ApiOperation({ summary: 'create order as admin' })
createOrderAsAdmin(@AdminId() adminId: string, @Body() body: CreateOrderAsAdminDto) {
return this.orderService.createOrdeAsAdmin(adminId, body);
return this.orderService.createOrderAsAdmin(adminId, body);
}
@Delete('admin/orders/:orderId')
@@ -26,15 +26,19 @@ export class CreateOrderItemDto {
@IsNumber()
unitPrice: number
@ApiProperty()
@IsNumber()
discount: number
@ApiPropertyOptional({ example: 'توضیحات' })
@IsString()
content: string
description: string
@ApiPropertyOptional({ example: [] })
@IsArray()
@IsString({ each: true })
attachments: { url: string, type: string }[]
}
}
export class CreateOrderAsAdminDto {
@ApiPropertyOptional({ example: 'توضیحات' })
+6 -2
View File
@@ -37,12 +37,16 @@ export class CreateOrderDto {
{
productId: 1,
quantity: 100,
attributesValues: []
attributesValues: [],
attachments: [
{ url: '', type: '' }
],
description: ''
}
]
})
@IsNotEmpty()
@ArrayMinSize(1, { message: 'At least one product is required' })
@ArrayMinSize(1, { message: 'At least one item is required' })
@Type(() => CreateOrderItemDto)
items: CreateOrderItemDto[];
}
@@ -1,4 +1,4 @@
import { Entity, Enum, Index, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core';
import { Entity, Index, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core';
import { BaseEntity } from '../../../common/entities/base.entity';
import { Order } from './order.entity';
import { Product } from 'src/modules/product/entities/product.entity';
@@ -6,7 +6,6 @@ import { Product } from 'src/modules/product/entities/product.entity';
@Entity({ tableName: 'order_items' })
@Index({ properties: ['order'] })
@Index({ properties: ['product'] })
export class OrderItem extends BaseEntity {
@PrimaryKey({ type: 'bigint', autoincrement: true })
id: bigint
@@ -37,17 +36,15 @@ export class OrderItem extends BaseEntity {
return Number(this.subTotal) - Number(this.discount || 0)
}
@Property({ nullable: true })
@Property({type:'text', nullable: true })
description?: string;
@Property({ nullable: true })
@Property({type:'text', nullable: true })
adminDescription?: string;
@Property({ type: 'json', nullable: true })
attachments?: { type: string, url: string }[] // user attachments like voice and photos
// @Enum(() => OrderItemStatus)
// status!: OrderItemStatus;
@Property({ nullable: true, columnType: 'timestamptz' })
confirmedAt?: Date;
}
+32 -35
View File
@@ -15,6 +15,8 @@ import { TicketRepository } from 'src/modules/ticket/repositories/tickets.reposi
import { CreateInvoiceDto } from '../dto/create-invoice.dto';
import { AdminRepository } from 'src/modules/admin/repositories/admin.repository';
import { CreateOrderAsAdminDto } from '../dto/create-order-as-admin.dto';
import { Order } from '../entities/order.entity';
import { PaymentRepository } from 'src/modules/payment/repositories/payment.repository';
@Injectable()
@@ -33,6 +35,7 @@ export class OrderService {
private readonly ticketService: TicketService,
private readonly eventEmitter: EventEmitter2,
private readonly adminRepository: AdminRepository,
private readonly paymentRepository: PaymentRepository,
) { }
async createNewOrder(userId: string, dto: CreateOrderDto) {
@@ -94,7 +97,7 @@ export class OrderService {
return order
}
async createOrdeAsAdmin(adminId: string, dto: CreateOrderAsAdminDto) {
async createOrderAsAdmin(adminId: string, dto: CreateOrderAsAdminDto) {
const { items, userPhone } = dto
const user = await this.userService.findByPhone(userPhone)
@@ -131,7 +134,6 @@ export class OrderService {
throw new BadRequestException("some products not found")
}
items.forEach(item => {
const product = products.find(p => p.id == item.productId)
@@ -146,8 +148,10 @@ export class OrderService {
quantity: item.quantity,
unitPrice: item.unitPrice,
total: item.unitPrice * item.quantity,
discount: 0,
subTotal: 0
discount: item.discount,
subTotal: item.unitPrice * item.quantity - item.discount,
attachments: item.attachments,
description: item.description
})
em.persist(orderItem)
@@ -155,6 +159,8 @@ export class OrderService {
// TODO : calculation must be done after create order
await this.calculateOrder(order, em)
await em.flush()
return order
@@ -178,42 +184,33 @@ export class OrderService {
return order
}
async calculateOrder(orderId: string, em: EntityManager) {
async calculateOrder(order: Order, em: EntityManager) {
const targetOrder = await this.findOneOrFail(orderId)
// calculate order financials
let subTotal = 0
let totalDiscount = 0
const order = await this.em.transactional(async (em) => {
// TODO : use reduce
for (let orderItem of order.items) {
subTotal += orderItem.total
totalDiscount += orderItem.discount
}
// calculate order financials
let subTotal = 0
let totalDiscount = 0
const totalBeforeTax = subTotal - totalDiscount
let tax = 0
// TODO : use reduce
if (order.enableTax) {
tax = 0.1 * totalBeforeTax
}
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
})
const total = totalBeforeTax + tax
const paidAmount = await this.paymentRepository.getActualPaidAmount(order.id)
// Update Order financial values
order.subTotal = subTotal
order.discount = totalDiscount
order.taxAmount = tax
order.total = total
order.balance = total - paidAmount
return order
}
@@ -106,4 +106,18 @@ export class PaymentRepository extends EntityRepository<Payment> {
},
};
}
async getActualPaidAmount(orderId: string): Promise<number> {
const raw = await this.em.createQueryBuilder(Payment, 'p')
.select('COALESCE(SUM(p.amount), 0) as total')
.where({
order: { id: orderId },
status: PaymentStatusEnum.Paid
})
.execute('get')
const row = raw as unknown as { total: string } | undefined;
return Number(row?.total ?? 0);
}
}