Martin Donnelly 57bd6c8e6a init
2018-06-24 21:15:03 +01:00

206 lines
7.3 KiB
JavaScript

/**
* Functions to interact with 3rd party merchanct aquirers
*/
'use strict';
var Q = require('q');
var errors = require(global.pathPrefix + '../utils/acquirers/acquirer_errors.js');
var credorax = require(global.pathPrefix + '../utils/acquirers/credorax.js');
var utils = require(global.pathPrefix + 'utils.js');
var config = require(global.configFile);
var testAcquirer = require(global.pathPrefix + '../utils/acquirers/test_acquirer.js');
var worldpayAcquirer = require(global.pathPrefix + '../utils/acquirers/worldpay_acquirer.js');
var demoAcquirer = require(global.pathPrefix + '../utils/acquirers/demo_acquirer.js');
var forceAcquirer = null; // Set to 'Test' to force use of Test acquirer
module.exports = {
invalidateMerchantAccount: invalidateMerchantAccount,
payTokenised: payTokenised,
payTransaction: payTransaction,
tokeniseCard: tokeniseCard,
validateMerchantAccount: validateMerchantAccount,
ERRORS: errors
};
/**
* Define the list of acquirers we have available
*/
const ACQUIRERS = {
Test: testAcquirer,
Worldpay: worldpayAcquirer,
Demo: demoAcquirer
};
/**
* Generic function to call the appropriate implementation based on the given
* acquirer name and function name.
*
* @param {string} acquirer - the acquirer that should be used
* @param {string} functionName - the name of the function to call
* @param {any[]} params - array of parameters for the function to be called
* @returns {Promise} - the result of the function or rejects with UNKNOWN_ACQUIRER
*/
function callImplIfExists(acquirer, functionName, params) {
const acquirerName = forceAcquirer || acquirer;
const acquirerImpl = ACQUIRERS[acquirerName];
if (!acquirerImpl || !acquirerImpl[functionName]) {
return Q.reject({name: errors.UNKNOWN_ACQUIRER});
}
return acquirerImpl[functionName].apply(null, params);
}
/**
* Attempts to invalidate the token with the merchant enquirer
*
* @param {string} acquirer - The merchant acquirer's name
* @param {string} token - The token to be invalidated
* @param {string} merchantID - The merchant ID for the merchant account
* @param {string} cipher - The merchant cipher for the merchant account
* @param {string} accountID - The accountID for creating a tracking id
*
* @returns {promise} - A promise that resolves on success, or rejects on fail
*/
function invalidateMerchantAccount(acquirer, token, merchantID, cipher, accountID) {
const acquirerName = forceAcquirer || acquirer;
const acquirerImpl = ACQUIRERS[acquirerName];
if (!acquirerImpl || !acquirerImpl.invalidateMerchantAccount) {
return Q.reject({name: errors.UNKNOWN_ACQUIRER});
}
return acquirerImpl.invalidateMerchantAccount(token, merchantID, cipher, accountID);
}
/**
* Makes a payment from customer to merchant using the specified acquirer. This
* requires the card to be pre-tokenised by the selected acquirer.
*
* @param {Object} transaction - The transaction being completed
* @param {Object} customerAccount - The customer's payment account
* @param {string} customerIP - The IP address the customer is connected from
* @param {Object} merchantAccount - The merchant's payment account
*
* @returns {Promise} - A promise that resolves on success, or rejects on fail
*/
function payTokenised(
transaction,
customerAccount,
customerIP,
merchantAccount
) {
//
// Check the token exists
//
if (!customerAccount.Token) {
return Q.reject({name: errors.NO_TOKEN});
}
//
// Check the merchant display name is long enough
//
if (utils.MinDisplayNameLength > transaction.MerchantDisplayName.length) {
return Q.reject({name: errors.INVALID_MERCHANT_NAME});
}
switch (forceAcquirer || merchantAccount.AcquirerName) {
case 'Credorax':
return credorax.payTokenised(
transaction,
customerAccount,
customerIP,
merchantAccount
);
case 'Test':
// Run the test version. Note that `testAcquirer` will be undefined
// unless this is in dev mode.
return testAcquirer.payTokenised(
transaction,
customerAccount,
customerIP,
merchantAccount
);
// Else fall through to default.
default:
return Q.reject({name: errors.UNKNOWN_ACQUIRER});
}
}
/**
* Makes a payment from customer to merchant using the appropriate acquirer
*
* @param {Object} client - the client making the payment
* @param {Object} device - the device making the payment
* @param {Object} data - various neccessary data
* @param {String} data.ClientKey - the client key required to decrypt the payment details
* @param {String} data.ipAddress - ipAddress of the client
* @param {Object} [data.cardDetails] - optional decrypted card details
* @param {Object} transaction - The transaction object with the payment info
* @param {Object} merchantInfo - Merchant account and address info
* @param {Object} customerInfo - Customer account and address info
*
* @returns {Promise} - Resolves to payment info, or rejects ERRORS value
*/
function payTransaction(
client,
device,
data,
transaction,
merchantInfo,
customerInfo
) {
//
// Check the merchant display name is long enough
//
if (utils.MinDisplayNameLength > transaction.MerchantDisplayName.length) {
return Q.reject({name: errors.INVALID_MERCHANT_NAME});
}
const acquirerName = forceAcquirer || merchantInfo.account.AcquirerName;
const acquirer = ACQUIRERS[acquirerName];
if (!acquirer || !acquirer.payTransaction) {
return Q.reject({name: errors.UNKNOWN_ACQUIRER});
}
//
// Call the specific aquirer to process the transaction
//
return acquirer.payTransaction(client, device, data, transaction, merchantInfo, customerInfo);
}
/**
* Validates that a merchant account is valid with the given acquirer
*
* @param {Object} account - the account to validate
* @returns {Promise} - resolves on succes or rejects with ERRORS value
*/
function validateMerchantAccount(account) {
const acquirerName = forceAcquirer || account.AcquirerName;
const acquirer = ACQUIRERS[acquirerName];
if (!acquirer || !acquirer.validateMerchantAccount) {
return Q.reject({name: errors.UNKNOWN_ACQUIRER});
}
//
// Call the specific aquirer to process the transaction
//
return acquirer.validateMerchantAccount(account);
}
/**
* Tokenises the card and returns some interesting information about it, along
* with the encrypted token (assuming the appropriate keys are provided).
*
* @param {string} acquirer - the acquirer to use to tokenise
* @param {Object} cardDetails - the card details to tokenise
* @param {string?} clientKey - the client Key (to encrypt the token)
* @param {string?} clientID - the client ID (to encrypt the token)
* @returns {Promise} - a promise for the successful tokenisation
*/
function tokeniseCard(acquirer, cardDetails, clientKey, clientID) {
return callImplIfExists(acquirer, 'tokeniseCard', [cardDetails, clientKey, clientID]);
}