diff --git a/src/IOC/ioc.config.ts b/src/IOC/ioc.config.ts index 264acdf..9a54bb4 100644 --- a/src/IOC/ioc.config.ts +++ b/src/IOC/ioc.config.ts @@ -69,6 +69,7 @@ import { FineRepo, createFineRepo } from "../modules/fine/repository/fine.reposi import { FineRuleRepo, createFineRuleRepo } from "../modules/fine/repository/fineRule.repository"; import { AsanPardakhtGateway } from "../modules/IPG/gateways/asanpardakht"; import { ZarinPalGateway } from "../modules/IPG/gateways/zarinpal"; +import { SepGateway } from "../modules/IPG/gateways/sep"; import { PaymentGateway } from "../modules/IPG/PaymentGateway"; import { JobService } from "../modules/job/job.service"; import { JobRepo, createJobRepo } from "../modules/job/repository/job.repo"; @@ -159,6 +160,7 @@ const containerModules = new AsyncContainerModule(async (bind) => { bind(IOCTYPES.PaymentGateway).to(PaymentGateway).inSingletonScope(); bind(IOCTYPES.ZarinPalGateway).to(ZarinPalGateway).inSingletonScope(); bind(IOCTYPES.AsanPardakhtGateway).to(AsanPardakhtGateway).inSingletonScope(); + bind(IOCTYPES.SEPGateway).to(SepGateway).inSingletonScope(); // #region services bind(IOCTYPES.CategoryService).to(CategoryService).inSingletonScope(); bind(IOCTYPES.ThemeService).to(ThemeService).inSingletonScope(); diff --git a/src/IOC/ioc.types.ts b/src/IOC/ioc.types.ts index a5ef2b7..21efde4 100644 --- a/src/IOC/ioc.types.ts +++ b/src/IOC/ioc.types.ts @@ -140,5 +140,6 @@ export const IOCTYPES = { Logger: Symbol.for("Logger"), ZarinPalGateway: Symbol.for("ZarinPalGateway"), AsanPardakhtGateway: Symbol.for("AsanPardakhtGateway"), + SEPGateway: Symbol.for("SEPGateway"), PaymentGateway: Symbol.for("PaymentGateway"), }; diff --git a/src/common/enums/payment.enum.ts b/src/common/enums/payment.enum.ts index 6799f3e..7245994 100644 --- a/src/common/enums/payment.enum.ts +++ b/src/common/enums/payment.enum.ts @@ -1,6 +1,7 @@ export enum GatewayProvider { Zarinpal = "Zarinpal", Asanpardakht = "asanPardakht", + SEP = "SEP", } export enum PaymentMethodType { diff --git a/src/modules/IPG/PaymentGateway.ts b/src/modules/IPG/PaymentGateway.ts index 89d296d..abdab25 100644 --- a/src/modules/IPG/PaymentGateway.ts +++ b/src/modules/IPG/PaymentGateway.ts @@ -2,6 +2,7 @@ import { inject, injectable } from "inversify"; import { AsanPardakhtGateway } from "./gateways/asanpardakht"; import { ZarinPalGateway } from "./gateways/zarinpal"; +import { SepGateway } from "./gateways/sep"; import { IPaymentGateway, NewPaymentData, VerifyPaymentData } from "./interface/IPG"; import { GatewayProvider } from "../../common/enums/payment.enum"; import { BadRequestError } from "../../core/app/app.errors"; @@ -11,6 +12,7 @@ import { IOCTYPES } from "../../IOC/ioc.types"; class PaymentGateway implements IPaymentGateway { @inject(IOCTYPES.ZarinPalGateway) zarinPalGateway: ZarinPalGateway; @inject(IOCTYPES.AsanPardakhtGateway) asanpardakhtGateway: AsanPardakhtGateway; + @inject(IOCTYPES.SEPGateway) sepGateway: SepGateway; public async requestPayment(gatewayType: GatewayProvider, data: NewPaymentData): Promise { switch (gatewayType) { @@ -19,6 +21,10 @@ class PaymentGateway implements IPaymentGateway { case GatewayProvider.Asanpardakht: //TODO:fix this return this.asanpardakhtGateway.token(); + case GatewayProvider.SEP: { + console.log("SEP", data.amount, data.description, data.email, data.mobile, data.callbackPath); + return await this.sepGateway.processPayment(data.amount, data.description, data.email, data.mobile, data.callbackPath); + } default: throw new BadRequestError(`Payment provider ${gatewayType} is not supported`); } @@ -31,6 +37,8 @@ class PaymentGateway implements IPaymentGateway { case GatewayProvider.Asanpardakht: //TODO:fix this return this.asanpardakhtGateway.time(); + case GatewayProvider.SEP: + return await this.sepGateway.verifyPayment(data.authority, data.amount); default: throw new BadRequestError(`Payment provider ${gatewayType} is not supported`); } @@ -43,6 +51,8 @@ class PaymentGateway implements IPaymentGateway { case GatewayProvider.Asanpardakht: //TODO:fix this return this.asanpardakhtGateway.token(); + case GatewayProvider.SEP: + return await this.sepGateway.retryPayment(authority); default: throw new BadRequestError(`Payment provider ${gatewayType} is not supported`); } diff --git a/src/modules/IPG/gateways/sep.ts b/src/modules/IPG/gateways/sep.ts new file mode 100644 index 0000000..2aa74cc --- /dev/null +++ b/src/modules/IPG/gateways/sep.ts @@ -0,0 +1,83 @@ +import axios from "axios"; +import { injectable } from "inversify"; + +import { InternalError } from "../../../core/app/app.errors"; +import { Logger } from "../../../core/logging/logger"; +interface SepRequestPaymentResponse { + status: 1 | -1; + errorCode?: string; + errorDesc?: string; + token?: string; +} + +@injectable() +class SepGateway { + private logger = new Logger(SepGateway.name); + + private gatewayApiUrl: string = process.env.SEP_HOST || ""; + private callBackURL = `${process.env.SITE_URL}/payment/verify/SEP/`; + private TERMINAL_ID: string = process.env.SEP_TERMINAL_ID || ""; + private requestHeader = { "Content-Type": "application/json", Accept: "application/json" }; + + async processPayment(amount: number, description: string, email: string, mobile: string, callBackPath: string) { + if (!this.gatewayApiUrl || !this.TERMINAL_ID) { + throw new InternalError(["SEP gateway is not configured"]); + } + const requesturl = `${this.gatewayApiUrl}/onlinepg/onlinepg`; + + console.log("SEP Gateway processPayment called", email); + try { + const purchaseData = { + Action: "Token", + TerminalId: this.TERMINAL_ID, + Amount: amount, // ریال + OrderId: description, + RedirectUrl: `${this.callBackURL}${callBackPath}`, + ResNum: "1qaz@WSX", + CellNumber: mobile, + }; + + const response = await axios.post(requesturl, purchaseData, { headers: this.requestHeader }); + const data = response.data; + + console.log("response data", data); + if (data.status == -1) { + throw new InternalError(data.errorCode + " " + data.errorDesc); + } + + return { + redirectUrl: this.callBackURL, + message: "successfull", + authority: data.token, + }; + } catch (error) { + this.logger.error("error in SEP payment process", error); + throw new InternalError(["error processing SEP payment"]); + } + } + + async verifyPayment(authority: string, amount: number) { + if (!this.gatewayApiUrl || !this.TERMINAL_ID) { + throw new InternalError(["SEP gateway is not configured"]); + } + // https://sep.shaparak.ir/verifyTxnRandomSessionkey/ipg/VerifyTransaction + + try { + const verifyData = { authority, amount, terminal_id: this.TERMINAL_ID }; + const response = await axios.post(`${this.gatewayApiUrl}/payment/verify`, verifyData, { headers: this.requestHeader }); + return response.data; + } catch (error) { + this.logger.error("error in SEP payment verification", error); + throw new InternalError(["error in SEP payment verification"]); + } + } + + async retryPayment(authority: string) { + return { + redirectUrl: `${this.gatewayApiUrl}/pay/${authority}`, + authority: authority, + }; + } +} + +export { SepGateway };