fix: the bug in the payment service

This commit is contained in:
Mahyargdz
2025-05-21 10:06:29 +03:30
parent 858f55bb0b
commit 9b3b5b41d7
10 changed files with 454 additions and 103 deletions
@@ -5,12 +5,12 @@ import { PaymentMessage } from "../../../common/enums/message.enum";
export class CheckoutPaymentDto {
@IsNotEmpty({ message: PaymentMessage.GATEWAY_REQUIRED })
@IsUUID("4", { message: PaymentMessage.GATEWAY_ID_SHOULD_BE_UUID })
@IsUUID("7", { message: PaymentMessage.GATEWAY_ID_SHOULD_BE_UUID })
@ApiProperty({ description: "Gateway id to pay", example: "e6fdce2a-9f91-47c4-8561-48368fc275b5" })
gatewayId: string;
@IsNotEmpty({ message: PaymentMessage.INVOICE_ID_REQUIRED })
@IsUUID("4", { message: PaymentMessage.INVOICE_ID_SHOULD_BE_UUID })
@IsUUID("7", { message: PaymentMessage.INVOICE_ID_SHOULD_BE_UUID })
@ApiProperty({ description: "Invoice id to pay", example: "e6fdce2a-9f91-47c4-8561-48368fc275b5" })
invoiceId: string;
}
@@ -205,7 +205,7 @@ export class PaymentProcessor extends WorkerProcessor {
const verifyData = await gateway.verifyPayment({
reference: payment.reference,
amount: payment.amount,
merchantId: payment.business.zarinpalMerchantId || this.zarinpalMerchantId,
merchantId: payment.business.zarinpalMerchantId ?? this.zarinpalMerchantId,
});
const result = await this.paymentsService.processVerificationResult(verifyData, payment, em);
@@ -58,17 +58,17 @@ export class PaymentsService {
if (invoice.company.user.id !== user.id) throw new BadRequestException(InvoiceMessage.NOT_FOUND_BY_ID_OR_NOT_BELONG_TO_USER);
const gatewayData = await this.processPayment(paymentGateway.name, {
amount: invoice.totalPrice.toNumber(),
amount: new Decimal(invoice.totalPrice).toNumber(),
description: PaymentMessage.CHECKOUT_INVOICE_MESSAGE.replace("[invoiceNumber]", invoice.numericId.toString()),
email: user.email,
mobile: user.phone,
callBackPath: invoice.business.slug,
merchantId: invoice.business.zarinpalMerchantId || this.zarinpalMerchantId,
merchantId: invoice.business.zarinpalMerchantId ?? this.zarinpalMerchantId,
});
const payment = await this.createGatewayPaymentForUser(
user,
invoice.totalPrice.toNumber(),
new Decimal(invoice.totalPrice).toNumber(),
gatewayData.reference,
paymentGateway.id,
invoice.business.id,
@@ -84,6 +84,7 @@ export class PaymentsService {
} catch (error) {
await em.rollback();
if (error instanceof HttpException) throw error;
this.logger.error("Payment checkout failed:", error);
throw new InternalServerErrorException(PaymentMessage.ERROR_IN_PAYMENT);
}
}
@@ -113,7 +114,7 @@ export class PaymentsService {
const verifyData = await paymentGateway.verifyPayment({
reference: queryDto.Authority,
amount: payment.amount,
merchantId: payment.business.zarinpalMerchantId || this.zarinpalMerchantId,
merchantId: payment.business.zarinpalMerchantId ?? this.zarinpalMerchantId,
});
return await this.handlePaymentVerificationWithResponse(verifyData, payment, rep, frontUrl, em);
@@ -289,8 +290,12 @@ export class PaymentsService {
//===============================================
private async getPaymentByReference(reference: string, em: EntityManager): Promise<Payment> {
const payment = await em.findOne(Payment, { reference }, { populate: ["user", "invoice", "business"], lockMode: LockMode.PESSIMISTIC_WRITE });
// First get the payment with a lock, but without joins
const payment = await em.findOne(Payment, { reference }, { lockMode: LockMode.PESSIMISTIC_WRITE });
if (!payment) throw new BadRequestException(PaymentMessage.PAYMENT_NOT_FOUND_WITH_REF);
// Then populate relations after acquiring the lock
await em.populate(payment, ["user", "invoice", "business"]);
return payment;
}