/** * 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]); }