import { HttpService } from "@nestjs/axios"; import { Inject, Injectable, InternalServerErrorException, Logger } from "@nestjs/common"; import { AxiosError } from "axios"; import { catchError, firstValueFrom } from "rxjs"; import { PaymentMessage } from "../../../common/enums/message.enum"; import { IZarinpalConfig } from "../../../configs/zarinpal.config"; import { ZARINPAL_CONFIG } from "../constants"; import { GatewayEnum } from "../enums/gateway.enum"; import { IPaymentGateway, IPaymentVerifyParams, IProcessPaymentParams, ZarinPalPGNewArgs, ZarinPalPGNewRequestData, ZarinPalPGVerifyData, } from "../interfaces/IPayment"; @Injectable() export class ZarinpalGateway implements IPaymentGateway { private readonly logger = new Logger(ZarinpalGateway.name); private readonly gatewayApiUrl: string; private readonly requestHeader: Record = { "Content-Type": "application/json", Accept: "application/json" }; constructor( @Inject(ZARINPAL_CONFIG) private readonly config: IZarinpalConfig, private readonly httpService: HttpService, ) { this.gatewayApiUrl = `https://${this.config.ipgType}.${this.config.gatewayApiUrl}`; } //*************************************** */ async processPayment(processParams: IProcessPaymentParams) { try { const purchaseData: ZarinPalPGNewArgs = { merchant_id: this.config.merchantId, amount: processParams.amount, callback_url: `${this.config.callBackUrl}/${GatewayEnum.ZARINPAL}${processParams.invoiceId ? "/" + processParams.invoiceId : ""}`, description: processParams.description, currency: "IRT", metadata: { email: processParams.email, mobile: processParams.mobile }, }; const { data } = await firstValueFrom( this.httpService .post(`${this.gatewayApiUrl}/v4/payment/request.json`, purchaseData, { headers: this.requestHeader, }) .pipe( catchError((err: AxiosError) => { this.logger.error(err); throw new InternalServerErrorException(PaymentMessage.ERROR_IN_PROCESS_PAYMENT); }), ), ); return { redirectUrl: `${this.gatewayApiUrl}/StartPay/${data.data.authority}`, message: data.data.message, reference: data.data.authority, }; } catch (error) { this.logger.error(error); throw new InternalServerErrorException(PaymentMessage.ERROR_IN_PROCESS_PAYMENT); } } //********************************** */ async verifyPayment(verifyParams: IPaymentVerifyParams) { try { const verifyData = { authority: verifyParams.reference, amount: verifyParams.amount, merchant_id: this.config.merchantId, }; const { data } = await firstValueFrom( this.httpService .post(`${this.gatewayApiUrl}/v4/payment/verify.json`, verifyData, { headers: this.requestHeader }) .pipe( catchError((err: AxiosError) => { this.logger.error(err); throw new InternalServerErrorException(PaymentMessage.ERROR_IN_VERIFY_PAYMENT); }), ), ); return { code: data.data.code, message: data.data.message, card_hash: data.data.card_hash, card_pan: data.data.card_pan, ref_id: data.data.ref_id, fee_type: data.data.fee_type, fee: data.data.fee, }; } catch (error) { console.error({ error }); this.logger.error(error); throw new InternalServerErrorException(PaymentMessage.ERROR_IN_VERIFY_PAYMENT); } } }