From 06c32e8302023836590da41f941fac21c18b9903 Mon Sep 17 00:00:00 2001 From: reza rezaei Date: Thu, 21 Dec 2023 18:03:57 +0330 Subject: [PATCH] feat: add atipay driver --- src/drivers/atipay/atipay.driver.ts | 126 +++++++++++++++++++++++++++ src/drivers/atipay/atipay.receipt.ts | 4 + src/drivers/atipay/atipay.type.ts | 50 +++++++++++ 3 files changed, 180 insertions(+) create mode 100644 src/drivers/atipay/atipay.driver.ts create mode 100644 src/drivers/atipay/atipay.receipt.ts create mode 100644 src/drivers/atipay/atipay.type.ts diff --git a/src/drivers/atipay/atipay.driver.ts b/src/drivers/atipay/atipay.driver.ts new file mode 100644 index 0000000..f0a3af1 --- /dev/null +++ b/src/drivers/atipay/atipay.driver.ts @@ -0,0 +1,126 @@ +import Invoice from "../../invoice"; +import { Driver } from "../../abstracts"; +import { AxiosError, AxiosResponse } from "axios"; +import { Gateway } from "../../gateway"; +import { + AtipayDetail, + PurchaseDataType, + PurchaseResponseType, + VerifyDataType, + VerifyResponseType, +} from "./atipay.type"; +import { AtipayReceipt } from "./atipay.receipt"; +import { Setting } from "../../contracts/interface"; + +export class Atipay extends Driver> { + public settings: Setting = { + apiPaymentUrl: "https://mipg.atipay.net/v1/redirect-to-gateway", + apiPurchaseUrl: "https://mipg.atipay.net/v1/get-token", + apiVerificationUrl: "https://mipg.atipay.net/v1/verify-payment", + callbackUrl: "http://yoursite.com/path/to", + merchantId: "", + }; + constructor() { + super(new Invoice()); + } + + /** + * + */ + async purchase(): Promise { + try { + let data: PurchaseDataType = { + apiKey: this.settings.merchantId, + amount: this.getInvoice().getAmount(), + redirectUrl: this.settings.callbackUrl, + description: this.getInvoice().getDetail().description, + invoiceNumber: this.getInvoice().getUuid(), + cellNumber: this.getInvoice().getDetail().cellNumber, + scatteredSettlementItems: + this.getInvoice().getDetail().scatteredSettlementItems, + }; + + const response: AxiosResponse = + await this.client.post(this.settings.apiPurchaseUrl, data); + + if (response.data.errorCode) { + throw this.translateStatus(response.data.errorCode); + } + + this.invoice.setTransactionId(response.data.token); + + return this.invoice.getTransactionId(); + } catch (error: any) { + if (error instanceof AxiosError) { + throw this.translateStatus(error.response.data.errorCode); + } + throw error; + } + } + + /** + * + */ + pay(): Gateway { + return new Gateway(this.settings.apiPaymentUrl, "POST", [ + { + key: "token", + value: this.invoice.getTransactionId(), + }, + ]); + } + + /** + * + */ + async verify( + res?: Omit, + ): Promise { + try { + if (res.status != "2") { + throw this.translateStatus(res.status); + } + + let data: VerifyDataType = { + referenceNumber: this.getInvoice().getTransactionId(), + apiKey: this.settings.merchantId, + }; + + const response: AxiosResponse = + await this.client.post(this.settings.apiVerificationUrl, data); + + if (!response.data.amount) { + throw this.translateStatus("0"); + } + + return new AtipayReceipt(this.getInvoice().getTransactionId(), { + ...res, + amount: response.data.amount, + }); + } catch (error: any) { + if (error instanceof AxiosError) { + throw this.translateStatus(error.response.data.error_code); + } + throw error; + } + } + + private translateStatus(status: string) { + const translations: Record = { + "1": "کاربر انصراف داده است", + "2": "پرداخت با موفقیت انجام شد", + "3": "پرداخت انجام نشد", + "4": "کاربر در بازه زمانی تعیین شده پاسخی ارسال نکرده است", + "5": "پارامترهای ارسالی نامعتبر است", + "8": "آدرس سرور پذیرنده نامعتبر است", + "10": "توکن ارسال شده یافت نشد", + "11": "با این شماره ترمینال فقط تراکنش های توکنی قابل پرداخت هستند", + "12": "شماره ترمینال ارسال شده یافت نشد", + }; + + const unknownError = + "خطای ناشناخته رخ داده است. در صورت کسر مبلغ از حساب حداکثر پس از 72 ساعت به حسابتان برمیگردد"; + + return translations[status] ?? unknownError; + } +} diff --git a/src/drivers/atipay/atipay.receipt.ts b/src/drivers/atipay/atipay.receipt.ts new file mode 100644 index 0000000..a97f1b9 --- /dev/null +++ b/src/drivers/atipay/atipay.receipt.ts @@ -0,0 +1,4 @@ +import { Receipt } from "../../abstracts"; +import { VerifyResponseType } from "./atipay.type"; + +export class AtipayReceipt extends Receipt {} diff --git a/src/drivers/atipay/atipay.type.ts b/src/drivers/atipay/atipay.type.ts new file mode 100644 index 0000000..eddb1ea --- /dev/null +++ b/src/drivers/atipay/atipay.type.ts @@ -0,0 +1,50 @@ +import { DetailInterface } from "../../contracts/interface"; + +export interface AtipayDetail extends DetailInterface { + amount: number; + invoiceNumber: string; + redirectUrl: string; + description?: string; + cellNumber?: string; + scatteredSettlementItems?: ScatteredSettlementItem[]; +} + +type ScatteredSettlementItem = { + amount: number; + iban: string; +}; + +export type PurchaseDataType = { + apiKey: string; + amount: number; + invoiceNumber: string; + redirectUrl: string; + description?: string; + cellNumber?: string; + scatteredSettlementItems?: ScatteredSettlementItem[]; +}; + +export type PurchaseResponseType = { + status: string; + token: string; + errorCode: string; + errorDescription: string; +}; + +export type VerifyDataType = { + apiKey: string; + referenceNumber: string; +}; + +export type VerifyResponseType = { + amount: number; + // + state: string; + status: string; + referenceNumber: string; + reservationNumber: string; + terminalId: string; + traceNumber: string; + maskedPan: string; + rrn: string; +};