feat: add payment module and factory

This commit is contained in:
mahyargdz
2025-02-03 15:41:53 +03:30
parent 8fb587f976
commit 31368610dd
48 changed files with 931 additions and 81 deletions
@@ -0,0 +1,96 @@
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<string, string> = { "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}`,
description: processParams.description,
currency: "IRT",
metadata: { email: processParams.email, mobile: processParams.mobile },
};
const { data } = await firstValueFrom(
this.httpService
.post<ZarinPalPGNewRequestData>(`${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<ZarinPalPGVerifyData>(`${this.config.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) {
this.logger.error(error);
throw new InternalServerErrorException(PaymentMessage.ERROR_IN_VERIFY_PAYMENT);
}
}
}