Skip to content

Commit

Permalink
feat: add atipay driver
Browse files Browse the repository at this point in the history
  • Loading branch information
rrez2002 committed Dec 21, 2023
1 parent 3062109 commit 06c32e8
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 0 deletions.
126 changes: 126 additions & 0 deletions src/drivers/atipay/atipay.driver.ts
Original file line number Diff line number Diff line change
@@ -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<Invoice<AtipayDetail>> {
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<string> {
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<PurchaseResponseType, PurchaseDataType> =
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<VerifyResponseType, "amount">,
): Promise<AtipayReceipt> {
try {
if (res.status != "2") {
throw this.translateStatus(res.status);
}

let data: VerifyDataType = {
referenceNumber: this.getInvoice().getTransactionId(),
apiKey: this.settings.merchantId,
};

const response: AxiosResponse<VerifyResponseType, VerifyDataType> =
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<string, string> = {
"1": "کاربر انصراف داده است",
"2": "پرداخت با موفقیت انجام شد",
"3": "پرداخت انجام نشد",
"4": "کاربر در بازه زمانی تعیین شده پاسخی ارسال نکرده است",
"5": "پارامترهای ارسالی نامعتبر است",
"8": "آدرس سرور پذیرنده نامعتبر است",
"10": "توکن ارسال شده یافت نشد",
"11": "با این شماره ترمینال فقط تراکنش های توکنی قابل پرداخت هستند",
"12": "شماره ترمینال ارسال شده یافت نشد",
};

const unknownError =
"خطای ناشناخته رخ داده است. در صورت کسر مبلغ از حساب حداکثر پس از 72 ساعت به حسابتان برمیگردد";

return translations[status] ?? unknownError;
}
}
4 changes: 4 additions & 0 deletions src/drivers/atipay/atipay.receipt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Receipt } from "../../abstracts";
import { VerifyResponseType } from "./atipay.type";

export class AtipayReceipt extends Receipt<VerifyResponseType> {}
50 changes: 50 additions & 0 deletions src/drivers/atipay/atipay.type.ts
Original file line number Diff line number Diff line change
@@ -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;
};

0 comments on commit 06c32e8

Please sign in to comment.