From 8d679dc5e07434833ab2d888fc77ffcb8fbf227f Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Mon, 29 Jun 2026 09:13:10 +0330 Subject: [PATCH] fix bug in order --- .../orders/providers/orders.service.ts | 23 +++++++++++++++++++ src/modules/payments/payments.module.ts | 3 ++- .../payments/services/payments.service.ts | 19 +++++++++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/modules/orders/providers/orders.service.ts b/src/modules/orders/providers/orders.service.ts index f35bbb1..bb4fd0d 100644 --- a/src/modules/orders/providers/orders.service.ts +++ b/src/modules/orders/providers/orders.service.ts @@ -28,6 +28,7 @@ import { getMinQuantity, isValidProductQuantity, roundQuantity } from '../../pro import { CouponService } from 'src/modules/coupons/providers/coupon.service'; import { CouponType } from 'src/modules/coupons/interface/coupon'; import { roundMoney } from 'src/common/utils/money.utils'; +import { WalletTransactionRepository } from 'src/modules/users/repositories/wallet-transaction.repository'; type OrderItemData = { variant: Variant; quantity: number; unitPrice: number; discount: number }; @@ -65,6 +66,7 @@ export class OrdersService { private readonly eventEmitter: EventEmitter2, private readonly userService: UserService, private readonly couponService: CouponService, + private readonly walletTransactionRepository: WalletTransactionRepository, ) { } async checkout(userId: string, shopId: string) { @@ -154,6 +156,10 @@ export class OrdersService { const paymentMethod = await this.paymentMethodService.findOneOrFail(cart.paymentMethodId!); this.assertPaymentMethodEnabled(paymentMethod); + if (paymentMethod.method === PaymentMethodEnum.Wallet) { + await this.assertWalletHasEnoughBalance(userId, shopId, cart.total || 0); + } + const orderItemsData = await this.buildOrderItemsData(cart, shopId); return { @@ -238,6 +244,15 @@ export class OrdersService { this.assertStatusTransitionAllowed(order, toStatus, ref); + if (previousStatus === OrderStatus.NEED_CONFIRMATION && toStatus === OrderStatus.PENDING_PAYMENT) { + await this.em.populate(order, ['items']); + for (const item of order.items) { + if (item.status === OrderItemStatus.needConfirmation) { + item.status = OrderItemStatus.confirmed; + } + } + } + order.status = toStatus; order.history.push({ status: toStatus, changedAt: new Date(), desc: desc || null }); await this.em.persistAndFlush(order); @@ -507,6 +522,14 @@ export class OrdersService { } } + private async assertWalletHasEnoughBalance(userId: string, shopId: string, amount: number): Promise { + const balance = await this.walletTransactionRepository.getCurrentWalletBalance(userId, shopId); + + if (balance < amount) { + throw new BadRequestException(CartMessage.WALLET_INSUFFICIENT); + } + } + private async buildOrderItemsData(cart: Cart, shopId: string): Promise { const orderItemsData: OrderItemData[] = []; const productQuantityMap = new Map(); diff --git a/src/modules/payments/payments.module.ts b/src/modules/payments/payments.module.ts index f10b092..7dd0f76 100644 --- a/src/modules/payments/payments.module.ts +++ b/src/modules/payments/payments.module.ts @@ -16,11 +16,12 @@ import { PaymentListeners } from './listeners/payment.listeners'; import { AdminModule } from '../admin/admin.module'; import { NotificationsModule } from '../notifications/notifications.module'; import { OrdersModule } from '../orders/orders.module'; +import { UserModule } from '../users/user.module'; @Module({ imports: [MikroOrmModule.forFeature([PaymentMethod, Payment, Shop]), AuthModule, JwtModule, AdminModule, NotificationsModule, - forwardRef(() => OrdersModule)], + forwardRef(() => OrdersModule), UserModule], controllers: [PaymentsController], providers: [PaymentsService, PaymentMethodService, PaymentMethodRepository, PaymentRepository, ZarinpalGateway, GatewayManager, PaymentListeners], diff --git a/src/modules/payments/services/payments.service.ts b/src/modules/payments/services/payments.service.ts index 5a6f563..45bc9ab 100644 --- a/src/modules/payments/services/payments.service.ts +++ b/src/modules/payments/services/payments.service.ts @@ -15,6 +15,7 @@ import { onlinePaymentSucceedEvent, paymentSucceedEvent } from '../events/paymen import { WalletTransactionReason, WalletTransactionType } from 'src/modules/users/interface/wallet'; import { PaymentRepository } from '../repositories/payment.repository'; import { roundMoney } from 'src/common/utils/money.utils'; +import { WalletTransactionRepository } from 'src/modules/users/repositories/wallet-transaction.repository'; @Injectable() export class PaymentsService { @@ -25,6 +26,7 @@ export class PaymentsService { private readonly gatewayManager: GatewayManager, private readonly eventEmitter: EventEmitter2, private readonly paymentRepository: PaymentRepository, + private readonly walletTransactionRepository: WalletTransactionRepository, ) { } async payOrder(orderId: string): Promise<{ paymentUrl: string | null }> { @@ -39,6 +41,10 @@ export class PaymentsService { throw new BadRequestException('سفارش به تایید نیاز دارد'); } + if (ctx.method === PaymentMethodEnum.Wallet) { + await this.assertWalletHasEnoughBalance(ctx.order.user.id, ctx.order.shop.id, ctx.amount); + } + switch (ctx.method) { case PaymentMethodEnum.Cash: await this.handleCashPayment(ctx); @@ -56,6 +62,14 @@ export class PaymentsService { } } + private async assertWalletHasEnoughBalance(userId: string, shopId: string, amount: number): Promise { + const balance = await this.walletTransactionRepository.getCurrentWalletBalance(userId, shopId); + + if (balance < amount) { + throw new BadRequestException(PaymentMessage.INSUFFICIENT_WALLET_BALANCE); + } + } + private async loadAndValidateOrder(orderId: string): Promise { const order = await this.em.findOne( Order, @@ -121,11 +135,12 @@ export class PaymentsService { throw new NotFoundException(PaymentMessage.WALLET_NOT_FOUND); } - if (walletTransaction.balance < ctx.amount) { + const currentBalance = Number(walletTransaction.balance) || 0; + if (currentBalance < ctx.amount) { throw new BadRequestException(PaymentMessage.INSUFFICIENT_WALLET_BALANCE); } - const newBalance = walletTransaction.balance - ctx.amount; + const newBalance = currentBalance - ctx.amount; const payment = await this.getOrCreateLatestPendingPayment(order.id, {