Skip to content

Commit

Permalink
Added behpardakht (mellat) driver
Browse files Browse the repository at this point in the history
  • Loading branch information
alitnk committed Oct 15, 2021
1 parent 816663c commit 505a087
Show file tree
Hide file tree
Showing 4 changed files with 423 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/drivers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Driver as BaseDriver } from './driver';
import { Behpardakht } from './drivers/behpardakht';
import * as BehpardakhtAPI from './drivers/behpardakht/api';
import { IdPay } from './drivers/idpay';
import * as IdPayAPI from './drivers/idpay/api';
import { NextPay } from './drivers/nextpay';
Expand All @@ -16,6 +18,7 @@ import * as ZarinpalAPI from './drivers/zarinpal/api';
import { Zibal } from './drivers/zibal';
import * as ZibalAPI from './drivers/zibal/api';

export { Behpardakht } from './drivers/behpardakht';
export { IdPay } from './drivers/idpay';
export { NextPay } from './drivers/nextpay';
export { PayPing } from './drivers/payping';
Expand All @@ -24,6 +27,7 @@ export { Saman } from './drivers/saman';
export { Zarinpal } from './drivers/zarinpal';
export { Zibal } from './drivers/zibal';
interface ConfigMap {
behpardakht: BehpardakhtAPI.Config;
idpay: IdPayAPI.Config;
nextpay: NextPayAPI.Config;
payir: PayirAPI.Config;
Expand All @@ -39,6 +43,7 @@ export type ConfigObject = Partial<ConfigMap>;
export type DriverName = keyof ConfigMap;

const drivers = {
behpardakht: Behpardakht,
idpay: IdPay,
nextpay: NextPay,
payir: Payir,
Expand Down
228 changes: 228 additions & 0 deletions src/drivers/behpardakht/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
import * as t from 'io-ts';
import { BaseReceipt, ErrorList, LinksObject, tBaseRequestOptions, tBaseVerifyOptions } from '../../types';

/*
* Behpardakht's API
* Currency: IRR
*/

export const links: LinksObject = {
default: {
REQUEST: 'https://bpm.shaparak.ir/pgwchannel/services/pgw?wsdl',
VERIFICATION: 'https://bpm.shaparak.ir/pgwchannel/services/pgw?wsdl',
PAYMENT: 'https://bpm.shaparak.ir/pgwchannel/startpay.mellat',
},
};

/**
* Request of `bpPayRequest`
*/
export interface RequestPaymentReq {
/**
* شماره پایانه پذیرنده
*/
terminalId: number;

/**
* نام کاربری پذیرنده
*/
userName: string;

/**
* کلمه عبور پذیرنده
*/
userPassword: string;

/**
* (پرداخت) ‫درخواست‬ ‫شماره
* باید یکتا باشد‬
*/
orderId: number;

/**
* ‫خريد‬ ‫مبلغ‬
*/
amount: number;

/**
* ‫‪YYYYMMDD‬‬ ‫درخواست‬ ‫تاريخ‬
* @example "20091008‬"
*/
localDate: string;

/**
* ‫‪HH:MM:SS‬‬ ‫درخواست‬ ‫ساعت‬
* @example "‫‪102003"
*/
localTime: string;

/**
* اطلاعات توضیحی که پذیرنده مایل به حفظ آن‌ها برای هر تراکنش می‌باشد
*/
additionalData: string;

/**
* آدرس برگشت به سایت پذیرنده
*/
callBackUrl: string;
/**
* ‫پرداخت‬ ‫شناسه‬ ‫كنند‬
*/
payerId: number;
}

/**
* Response of `bpPayRequest`, a string containing two parameters, separated with a `,`
*
* - First part is a ResCode
* - Second part is a hashcode called RefId
*
* @example `‫‪0,‬‬ ‫‪AF82041a2Bf6989c7fF9‬‬`
*/
export type RequestPaymentRes = string;

/**
* NOTE: this gets sent on POST method
*/
export interface CallbackParams {
/**
* کدر مرجع درخواست پرداخت که همراه با درخواست bpPayRequest تولید شده و به پذیرنده اختصاص یافته است
*/
RefId: string;

/**
* وضعیت خرید با توجه به جدول شماره ۷
*/
ResCode: string;

/**
* شماره درخواست پرداخت
*/
saleOrderId: number;

/**
* کد مرجع تراکنش خرید که از سایت بانک به پذیرنده داده می‌شود
*/
SaleReferenceId: number;

/**
* Either this one is not documented or my documentation is outdated.
*/
CardHolderPan: string;
}

export interface VerifyPaymentReq {
/**
* شماره پایانه پذیرنده
*/
terminalId: number;

/**
* نام کاربری پذیرنده
*/
userName: string;

/**
* کلمه عبور پذیرنده
*/
userPassword: string;

/**
* (پرداخت) ‫درخواست‬ ‫شماره
* باید یکتا باشد‬
*/
orderId: number;

/**
* شماره درخواست خرید
*
* همان orderId در مرحله قبل
*/
saleOrderId: number;

/**
* کد مرجع تراکنش خرید
*/
saleReferenceId: number;
}

/**
* The response of `bpVerifyRequest`
*
* a ResCode
*/
export type VerifyPaymentRes = string;

export const errors: ErrorList = {
'‫‪11‬‬': '‫است‬ ‫نامعتبر‬ ‫كارت‬ ‫شماره‬',
'‫‪12‬‬': '‫نيست‬ ‫كافي‬ ‫موجودي‬',
'‫‪13‬‬': '‫است‬ ‫نادرست‬ ‫رمز‬',
'‫‪14‬‬': '‫است‬ ‫مجاز‬ ‫حد‬ ‫از‬ ‫بيش‬ ‫رمز‬ ‫كردن‬ ‫وارد‬ ‫دفعات‬ ‫تعداد‬',
'‫‪15‬‬': '‫است‬ ‫نامعتبر‬ ‫كارت‬',
'‫‪16‬‬': '‫است‬ ‫مجاز‬ ‫حد‬ ‫از‬ ‫بيش‬ ‫وجه‬ ‫برداشت‬ ‫دفعات‬',
'‫‪17‬‬': '‫است‬ ‫شده‬ ‫منصرف‬ ‫تراكنش‬ ‫انجام‬ ‫از‬ ‫كاربر‬',
'‫‪18‬‬': '‫است‬ ‫گذشته‬ ‫كارت‬ ‫انقضاي‬ ‫تاريخ‬',
'‫‪19‬‬': '‫است‬ ‫مجاز‬ ‫حد‬ ‫از‬ ‫بيش‬ ‫وجه‬ ‫برداشت‬ ‫مبلغ‬',
'‫‪111‬‬': '‫است‬ ‫نامعتبر‬ ‫كارت‬ ‫كننده‬ ‫صادر‬',
'‫‪112‬‬': '‫كارت‬ ‫كننده‬ ‫صادر‬ ‫سوييچ‬ ‫خطاي‬',
'‫‪113‬‬': '‫نشد‬ ‫دريافت‬ ‫كارت‬ ‫كننده‬ ‫صادر‬ ‫از‬ ‫پاسخي‬',
'‫‪114‬‬': '‫نيست‬ ‫تراكنش‬ ‫اين‬ ‫انجام‬ ‫به‬ ‫مجاز‬ ‫كارت‬ ‫دارنده‬',
'‫‪21‬‬': '‫است‬ ‫نامعتبر‬ ‫پذيرنده‬',
'‫‪23‬‬': '‫است‬ ‫داده‬ ‫رخ‬ ‫امنيتي‬ ‫خطاي‬',
'‫‪24‬‬': '‫است‬ ‫نامعتبر‬ ‫پذيرنده‬ ‫كاربري‬ ‫اطلاعات‬',
'‫‪25‬‬': '‫است‬ ‫نامعتبر‬ ‫مبلغ‬',
'‫‪31‬‬': '‫است‬ ‫نامعتبر‬ ‫پاسخ‬',
'‫‪32‬‬': '‫باشد‬ ‫نمي‬ ‫صحيح‬ ‫شده‬ ‫وارد‬ ‫اطلاعات‬ ‫فرمت‬',
'‫‪33‬‬': '‫است‬ ‫نامعتبر‬ ‫حساب‬',
'‫‪34‬‬': '‫سيستمي‬ ‫خطاي‬',
'‫‪35‬‬': '‫است‬ ‫نامعتبر‬ ‫تاريخ‬',
'‫‪41‬‬': '‫است‬ ‫تكراري‬ ‫درخواست‬ ‫شماره‬',
'‫‪42‬‬': '‫نشد‬ ‫يافت‬ ‫‪Sale‬‬ ‫تراكنش‬',
'‫‪43‬‬': '‫است‬ ‫شده‬ ‫داده‬ ‫‪Verify‬‬ ‫درخواست‬ ‫قبلا‬',
'‫‪44‬‬': '‫نشد‬ ‫يافت‬ ‫‪Verfiy‬‬ ‫درخواست‬',
'‫‪45‬‬': '‫است‬ ‫شده‬ ‫‪Settle‬‬ ‫تراكنش‬',
'‫‪46‬‬': '‫است‬ ‫نشده‬ ‫‪Settle‬‬ ‫تراكنش‬',
'‫‪47‬‬': '‫نشد‬ ‫يافت‬ ‫‪Settle‬‬ ‫تراكنش‬',
'‫‪48‬‬': '‫است‬ ‫شده‬ ‫‪Reverse‬‬ ‫تراكنش‬',
'‫‪49‬‬': '‫نشد‬ ‫يافت‬ ‫‪Refund‬‬ ‫تراكنش‬',
'‫‪412‬‬': '‫است‬ ‫نادرست‬ ‫قبض‬ ‫شناسه‬',
'‫‪413‬‬': '‫است‬ ‫نادرست‬ ‫پرداخت‬ ‫شناسه‬',
'‫‪414‬‬': '‫است‬ ‫نامعتبر‬ ‫قبض‬ ‫كننده‬ ‫صادر‬ ‫سازمان‬',
'‫‪415‬‬': '‫است‬ ‫رسيده‬ ‫پايان‬ ‫به‬ ‫كاري‬ ‫جلسه‬ ‫زمان‬',
'‫‪416‬‬': '‫اطلاعات‬ ‫ثبت‬ ‫در‬ ‫خطا‬',
'‫‪417‬‬': '‫است‬ ‫نامعتبر‬ ‫كننده‬ ‫پرداخت‬ ‫شناسه‬',
'‫‪418‬‬': '‫مشتري‬ ‫اطلاعات‬ ‫تعريف‬ ‫در‬ ‫اشكال‬',
'‫‪419‬‬': '‫است‬ ‫گذشته‬ ‫مجاز‬ ‫حد‬ ‫از‬ ‫اطلاعات‬ ‫ورود‬ ‫دفعات‬ ‫تعداد‬',
'‫‪421‬‬': '‫است‬ ‫نامعتبر‬ ‫‪IP‬‬',
'‫‪51‬‬': '‫است‬ ‫تكراري‬ ‫تراكنش‬',
'‫‪54‬‬': '‫نيست‬ ‫موجود‬ ‫مرجع‬ ‫تراكنش‬',
'‫‪55‬‬': '‫است‬ ‫نامعتبر‬ ‫تراكنش‬',
'‫‪61‬‬': '‫واريز‬ ‫در‬ ‫خطا‬',
};

/*
* Package's API
*/

export const tConfig = t.interface({
terminalId: t.number,
username: t.string,
password: t.string,
});

export type Config = t.TypeOf<typeof tConfig>;

export const tRequestOptions = t.intersection([
t.partial({
payerId: t.number,
}),
tBaseRequestOptions,
]);

export type RequestOptions = t.TypeOf<typeof tRequestOptions>;

export const tVerifyOptions = t.intersection([t.interface({}), tBaseVerifyOptions]);

export type VerifyOptions = t.TypeOf<typeof tVerifyOptions>;

export type Receipt = BaseReceipt<CallbackParams>;
111 changes: 111 additions & 0 deletions src/drivers/behpardakht/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import soap from 'soap';
import { Driver } from '../../driver';
import { PaymentException, RequestException, VerificationException } from '../../exceptions';
import * as API from './api';

export class Behpardakht extends Driver<API.Config> {
constructor(config: API.Config) {
super(config, API.tConfig);
}

protected links = API.links;

requestPayment = async (options: API.RequestOptions) => {
options = this.getParsedData(options, API.tRequestOptions);

const { amount, callbackUrl, description, payerId } = options;
const { terminalId, username, password } = this.config;
const client = await soap.createClientAsync(this.getLinks().REQUEST);

const requestFields: API.RequestPaymentReq = {
terminalId,
userName: username,
userPassword: password,
amount,
callBackUrl: callbackUrl,
orderId: this.generateId(),
localDate: this.dateFormat(),
localTime: this.timeFormat(),
payerId: payerId || 0,
additionalData: description || '',
};

const response: API.RequestPaymentRes = client.bpPayRequest(requestFields);
const splittedResponse = response.split(', ');
const ResCode = splittedResponse[0];
const RefId = splittedResponse[1];

if (ResCode.toString() !== '0') {
throw new RequestException(API.errors[response[0]]);
}

return this.makeRequestInfo(RefId, 'POST', this.getLinks().PAYMENT, {
RefId,
});
};

verifyPayment = async (_options: API.VerifyOptions, params: API.CallbackParams): Promise<API.Receipt> => {
const { RefId, ResCode, saleOrderId, SaleReferenceId, CardHolderPan } = params;
const { terminalId, username, password } = this.config;

if (ResCode !== '0') {
throw new PaymentException(API.errors[ResCode]);
}

const soapClient = await soap.createClientAsync(this.getLinks().VERIFICATION);

const requestFields: API.VerifyPaymentReq = {
terminalId,
userName: username,
userPassword: password,
orderId: saleOrderId,
saleOrderId: saleOrderId,
saleReferenceId: SaleReferenceId,
};

// 1. Verify
const verifyResponse: API.VerifyPaymentRes = soapClient.bpVerifyRequest(requestFields);

if (verifyResponse.toString() !== '0') {
if (verifyResponse.toString() !== '43') {
soapClient.bpReversalRequest(requestFields);
}
throw new VerificationException(API.errors[verifyResponse]);
}

// 2. Settle
const settleResponse = soapClient.bpSettleRequest(requestFields);
if (settleResponse.toString() !== '0') {
if (settleResponse.toString() !== '45' && settleResponse.toString() !== '48') {
soapClient.bpReversalRequest(requestFields);
}
throw new VerificationException(API.errors[verifyResponse]);
}

return {
transactionId: RefId,
cardPan: CardHolderPan,
raw: params,
};
};

/**
* ‫‪YYYYMMDD‬‬
*/
dateFormat(date = new Date()) {
const yyyy = date.getFullYear();
const mm = date.getMonth() + 1;
const dd = date.getDate();
return yyyy.toString() + mm.toString() + dd.toString();
}

/**
* HHMMSS
*/
timeFormat(date = new Date()) {
const hh = date.getHours();
const mm = date.getMonth();
const ss = date.getSeconds();
return hh.toString() + mm.toString() + ss.toString();
}
}
Loading

0 comments on commit 505a087

Please sign in to comment.