refactor : payment

This commit is contained in:
2026-01-03 17:35:18 +03:30
parent 60f7b46779
commit a65ad8b5ff
15 changed files with 159 additions and 224 deletions
@@ -140,12 +140,11 @@ class PaymentService {
// extracted to handle payment creation
const { payment, paymentData } = await this.handlePaymentCreation(paymentMethod, price, user, description, session);
// create order and order items
const { order, orderItems } = await this.orderService.createOrder(user, payment, cartShipmentItems, session);
// clear cart and adjust stock
await this.finalizeOrder(user, cartShipmentItems, session);
// clear cart and adjust stock
await this.finalizeOrder(user, cartShipmentItems, session);
await session.commitTransaction();
await session.endSession();
return { paymentData, order, orderItems };
@@ -161,12 +160,22 @@ class PaymentService {
//##################################################################
//##################################################################
//verify callback of cart payment
async verifyCartPayment(gateway: GatewayProvider, verifyCallbackData: { authority: string; status: string }) {
const { status, authority } = verifyCallbackData;
async verifyCartPayment(gateway: GatewayProvider, verifyCallbackData: { status: string; authority?: string; refNum?: string }) {
const { status, authority, refNum } = verifyCallbackData;
const session = await startSession();
session.startTransaction();
try {
const paymentData = await this.cartPaymentRepo.model.findOne({ authority }).session(session);
// For SEP gateway, refNum is used as authority in database
const authorityToFind = gateway === GatewayProvider.SEP ? refNum : authority;
if (!authorityToFind) throw new BadRequestError(PaymentMessage.PaymentNotFound);
// For SEP gateway, check if refNum has already been used as transaction_id
if (gateway === GatewayProvider.SEP && refNum) {
const existingPayment = await this.cartPaymentRepo.model.findOne({ transaction_id: refNum }).session(session);
if (existingPayment) throw new BadRequestError(PaymentMessage.RefNumIsAlreadyUsed);
}
const paymentData = await this.cartPaymentRepo.model.findOne({ authority: authorityToFind }).session(session);
if (!paymentData) throw new BadRequestError(PaymentMessage.PaymentNotFound);
@@ -185,10 +194,16 @@ class PaymentService {
}
// Verify payment through gateway
const data = await this.paymentGateway.verifyPayment(gateway, { authority, amount: paymentData.totalPrice });
const verifyData =
gateway === GatewayProvider.SEP
? { refNum: authority, amount: paymentData.totalPrice }
: { authority, amount: paymentData.totalPrice };
const data = await this.paymentGateway.verifyPayment(gateway, verifyData);
if (data.code === 100 || data.code === 101) {
await this.handleSellerNotify(order._id, user, session);
await this.handleSuccessfulPayment(paymentData._id.toString(), order._id, data.ref_id, session);
// For SEP gateway, save refNum as transaction_id; for Zarinpal, save ref_id
const transactionId = gateway === GatewayProvider.SEP ? refNum : data.ref_id;
await this.handleSuccessfulPayment(paymentData._id.toString(), order._id, transactionId, session);
return this.buildPaymentResponse(status, PaymentMessage.PaymentSuccessful, paymentData._id.toString(), order._id);
}
@@ -279,8 +294,8 @@ class PaymentService {
}
//##################################################################
//##################################################################
private async handleSuccessfulPayment(paymentId: string, orderId: number, refId: number, session: ClientSession) {
await this.updatePaymentStatusAndReference(paymentId, refId, PaymentStatus.Completed, session);
private async handleSuccessfulPayment(paymentId: string, orderId: number, transactionId: string, session: ClientSession) {
await this.updatePaymentStatusAndReference(paymentId, transactionId, PaymentStatus.Completed, session);
await this.orderService.updateOrderStatus(orderId, OrdersStatus.process_by_seller, session);
@@ -385,8 +400,8 @@ class PaymentService {
}
//##################################################################
//##################################################################
private async updatePaymentStatusAndReference(paymentId: string, refId: number | null, status: PaymentStatus, session: ClientSession) {
return await this.cartPaymentRepo.model.findByIdAndUpdate(paymentId, { paymentStatus: status, transaction_id: refId }, { session });
private async updatePaymentStatusAndReference(paymentId: string, transactionId: string | null, status: PaymentStatus, session: ClientSession) {
return await this.cartPaymentRepo.model.findByIdAndUpdate(paymentId, { paymentStatus: status, transaction_id: transactionId }, { session });
}
}