alfabank-wrapper
Version:
Unified wrapper for Alfabank e-commerce banking functions
215 lines (198 loc) • 6.52 kB
JavaScript
/*
Alfabank wrapper v.1.0.x
Allow send command execution to Alfabank server with desired parameters
For more information about operations and its parameters look at:
https://pay.alfabank.ru/ecommerce/instructions/merchantManual/pages/index/rest.html
*/
/*Define dependencies*/
const axios = require('axios');
/*Error mesages*/
const messages = {
ru : {
operation_error : 'Указанная операция не определена в документации банка',
params_invalid : 'Параметры должны быть переданы в виде объекта',
callback_invalid : 'Требуется функция обратного вызова',
value_invalid : 'Параметр должен быть указан',
value_type_invalid : 'Некорректный тип данных ',
auth_invalid : 'Некорректные данные для авторизации, необходим либо токен либо имя пользователя и пароль. Для операции возврата имя пользователя и пароль обязательны.'
},
en : {
operation_error : 'The specified operation is not defined in the banks documentation',
params_invalid : 'Parameters must be passed as an object',
callback_invalid : 'Callback function required',
value_invalid : 'Value must be specified',
value_type_invalid : 'Value type is incorrect ',
auth_invalid : 'Incorrect authorization data token or userName and password must be provided. For refund operation userName and password required.'
}
}
const commands = [
'registerPreAuth',
'register',
'getOrderStatusExtended',
'getLastOrdersForMerchants',
'getBindingsByCardOrId',
'getBindings',
'getOrderStatus',
'verifyEnrollment',
'paymentOrderBinding',
'reverse',
'paymentotherway',
'deposit',
'addParams',
'unBindCard',
'refund',
'bindCard'
];
/*Main class*/
class Alfabank {
#token;
#username;
#password;
#language;
/*Default REST point of Alfabank*/
execURLPrefix = `https://pay.alfabank.ru/payment/rest/`;
execURLSuffix = `.do`;
/*Initialise class with "new"*/
constructor (token, language, userName, password, execURLPrefix, execURLSuffix) {
this.#language = language;
if (!token && (!userName || !password)) {
throw messages[this.#language].auth_invalid;
}
this.#token = token;
this.#username = userName;
this.#password = password;
/*If URLs not defines use default values*/
if (execURLPrefix) {
this.execURLPrefix = execURLPrefix;
};
if (execURLSuffix) {
this.execURLSuffix = execURLSuffix;
};
};
/*Simple detectors of Objects and Arrays*/
isObject = (a) => {
return (!!a) && (a.constructor === Object);
};
isArray = (a) => {
return (!!a) && (a.constructor === Array);
};
/*Unified execute action with callback*/
execute(operation, params, callback) {
if (!callback instanceof Function) {
throw messages[this.#language].callback_invalid;
} else if (!this.isObject(params) || this.isArray(params)) {
callback(messages[this.#language].params_invalid, false);
} else if (
!commands.includes(operation)
) {
callback(messages[this.#language].operation_error, false);
} else {
/*Extend parameters by adding authorization token*/
if (this.#token) {
params.token = this.#token;
}
if (this.#username && this.#password) {
params.userName = this.#username;
params.password = this.#password;
}
/*Send data to server*/
axios({
method : 'POST', //as described in documentation (link above)
url : `${this.execURLPrefix}${operation}${this.execURLSuffix}`,
params : params //That's correct. Parameters from request string are reading only. Bank's server does not recognize any parameters in body (!!! Why they require POST?)
}).then(
(result) => {
/*If operation succeeded on bank's side return data*/
if (!parseInt(result.data.errorCode, 10)) {
callback(false, result.data);
} else {
/*Else return data with description as error*/
callback(result.data, false);
}
}
).catch(
(error) => {
callback(error, false);
}
)
}
}
/*Promisified execution for those who used a single thread application and uses await*/
executePromise(operation, params) {
return new Promise((resolve, reject) => {
this.execute(operation, params, (error, data) => {
if (error) {
reject(error);
} else {
resolve(data);
}
});
});
}
/*Basic promisified functions for most popular commands*/
register (paymentID, paymentAmount, paymentDetails, successURL, failURL, options = {}) {
if (typeof paymentAmount != 'number') {
throw messages[this.#language].value_type_invalid + 'paymentAmount';
} else if (!successURL) {
throw messages[this.#language].value_invalid + 'successURL';
} else if (!paymentDetails) {
throw messages[this.#language].value_invalid + 'paymentDetails';
}
let params = {
returnUrl : successURL,
failUrl : failURL || successURL,
orderNumber : paymentID,
amount : Math.round(paymentAmount*100),
description : paymentDetails
};
params = Object.assign(params, options);
return new Promise ((resolve, reject) => {
this.execute('register', params, (error, data) => {
if (error) {
reject(error);
} else {
resolve(data);
}
});
});
}
getOrderStatus (orderID) {
if (!orderID) {
throw messages[this.#language].value_invalid + 'orderID';
}
let params = {
orderId : orderID
};
return new Promise ((resolve, reject) => {
this.execute('getOrderStatus', params, (error, data) => {
if (error) {
reject(error);
} else {
resolve(data);
}
});
});
}
refund (orderID, paymentAmount) {
if (typeof paymentAmount != 'number') {
throw messages[this.#language].value_type_invalid + 'paymentAmount';
} else if (!orderID) {
throw messages[this.#language].value_invalid + 'orderID';
}
let params = {
orderId : orderID,
amount : Math.round(paymentAmount*100)
};
return new Promise ((resolve, reject) => {
this.execute('refund', params, (error, data) => {
if (error) {
reject(error);
} else {
resolve(data);
}
});
});
}
}
/*Export class to outside*/
exports.Alfabank = Alfabank;