894 lines
29 KiB
JavaScript
894 lines
29 KiB
JavaScript
/**
|
|
* Controller to manage the accounts functions
|
|
*/
|
|
'use strict';
|
|
|
|
var _ = require('lodash');
|
|
var Q = require('q');
|
|
var httpStatus = require('http-status-codes');
|
|
var mongodb = require('mongodb');
|
|
var debug = require('debug')('webconsole-api:controllers:accounts');
|
|
var mainDB = require(global.pathPrefix + 'mainDB.js');
|
|
var utils = require(global.pathPrefix + 'utils.js');
|
|
var log = require(global.pathPrefix + 'log.js');
|
|
var swaggerUtils = require(global.pathPrefix + '../utils/swaggerUtils.js');
|
|
var anon = require(global.pathPrefix + '../utils/anon.js');
|
|
var referenceUtils = require(global.pathPrefix + '../utils/references.js');
|
|
var acquirerUtils = require(global.pathPrefix + '../utils/acquirers/acquirer.js');
|
|
var responsesUtils = require(global.pathPrefix + '../utils/responses.js');
|
|
const deleteAccountImpl = require(global.pathPrefix + '../impl/delete_account.js');
|
|
|
|
module.exports = {
|
|
getAccounts: getAccounts,
|
|
getAccount: getAccount,
|
|
|
|
updateAccount: updateAccount,
|
|
deleteAccount: deleteAccount,
|
|
|
|
addAccountCredorax: addAccountCredorax,
|
|
addAccountWorldpay: addAccountWorldpay,
|
|
addAccountDemo: addAccountDemo
|
|
};
|
|
|
|
/**
|
|
* Get the account history
|
|
*
|
|
* @param {Object} req - Express request object
|
|
* @param {Object} res - Express response object
|
|
*/
|
|
function getAccounts(req, res) {
|
|
//
|
|
// Get the query params from the request and the session
|
|
//
|
|
var clientID = req.session.data.clientID;
|
|
var isMerchant = req.session.data.isMerchant;
|
|
var limit = req.swagger.params.limit.value;
|
|
var skip = req.swagger.params.skip.value;
|
|
var minDate = req.swagger.params.minDate.value;
|
|
var maxDate = req.swagger.params.maxDate.value;
|
|
var includeDeleted = req.swagger.params.includeDeleted.value;
|
|
|
|
var query = {
|
|
ClientID: clientID
|
|
};
|
|
|
|
//
|
|
// Exclude deleted items unless we have been asked to keep them
|
|
//
|
|
if (!includeDeleted) {
|
|
// Ignore items with the AccountDelete or API created bits set
|
|
// jshint -W016
|
|
query.AccountStatus = {
|
|
$bitsAllClear: utils.AccountDeleted | utils.AccountApiCreated
|
|
};
|
|
// jshint +W016
|
|
}
|
|
|
|
//
|
|
// Add date limits if included
|
|
//
|
|
if (minDate || maxDate) {
|
|
query.LastUpdate = {};
|
|
if (minDate) {
|
|
query.LastUpdate.$gte = minDate;
|
|
}
|
|
if (maxDate) {
|
|
query.LastUpdate.$lte = maxDate;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the user is not a merchant then prevent listing any merchant accounts
|
|
//
|
|
if (!isMerchant) {
|
|
query.AccountType = {$ne: 'Credit/Debit Receiving Account'};
|
|
}
|
|
|
|
//
|
|
// Define the projection based on the Swagger definition
|
|
//
|
|
var projection = swaggerUtils.swaggerToMongoProjection(
|
|
req.swagger.operation,
|
|
true // include _id so we know how to select an individual device.
|
|
);
|
|
|
|
//
|
|
// Make the query. Note limit & skip have defaults defined in the
|
|
// swagger definition, so will always exist even if not requested
|
|
//
|
|
mainDB.collectionAccount.find(query, projection)
|
|
.skip(skip)
|
|
.limit(limit)
|
|
.sort({LastUpdate: -1}) // Hard-coded reverse sort by time
|
|
.toArray(function(err, items) {
|
|
if (err) {
|
|
debug('- failed to getAccounts', err);
|
|
res.status(httpStatus.BAD_GATEWAY).json({
|
|
code: 121,
|
|
info: 'Database offline'
|
|
});
|
|
} else {
|
|
//
|
|
// Anonymise all the accounts before sending them out
|
|
//
|
|
_.forEach(
|
|
items,
|
|
function(value, index, collection) {
|
|
//
|
|
// Anonymise all the account before sending them out
|
|
//
|
|
anon.anonymiseAccount(value);
|
|
//
|
|
// Rename _id to AccountId
|
|
//
|
|
value.AccountID = value._id;
|
|
delete value._id;
|
|
});
|
|
|
|
//
|
|
// Null any nullable fields
|
|
//
|
|
swaggerUtils.getAndApplyNullableFields(req.swagger.operation, items);
|
|
|
|
res.status(httpStatus.OK).json(items);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Gets the account details for a specific account.
|
|
*
|
|
* @param {Object} req - Express request object
|
|
* @param {Object} res - Express response object
|
|
*/
|
|
function getAccount(req, res) {
|
|
//
|
|
// Get the query params from the request and the session
|
|
//
|
|
var clientID = req.session.data.clientID;
|
|
var isMerchant = req.session.data.isMerchant;
|
|
var accountId = req.swagger.params.objectId.value;
|
|
|
|
//
|
|
// Build the query. The limits are:
|
|
// - Must match the id of the item we are looking for
|
|
// - Current user must be the account owner (to protect against Insecure
|
|
// Direct Object References).
|
|
//
|
|
var query = {
|
|
_id: mongodb.ObjectID(accountId),
|
|
ClientID: clientID
|
|
};
|
|
|
|
//
|
|
// If the user is not a merchant then prevent listing any merchant accounts
|
|
//
|
|
if (!isMerchant) {
|
|
query.AccountType = {$ne: 'Credit/Debit Receiving Account'};
|
|
}
|
|
|
|
//
|
|
// Define the fields based on the Swagger definition.
|
|
//
|
|
var projection = swaggerUtils.swaggerToMongoProjection(
|
|
req.swagger.operation,
|
|
true
|
|
);
|
|
|
|
//
|
|
// Build the options to encapsulate the projection
|
|
//
|
|
var options = {
|
|
fields: projection,
|
|
comment: 'WebConsole:getAccount' // For profiler logs use
|
|
};
|
|
|
|
//
|
|
// Make the request
|
|
//
|
|
mainDB.findOneObject(mainDB.collectionAccount, query, options, false,
|
|
function(err, item) {
|
|
if (err) {
|
|
debug('- failed to getAccount', err);
|
|
res.status(httpStatus.BAD_GATEWAY).json({
|
|
code: 197,
|
|
info: 'Database offline'
|
|
});
|
|
} else if (item === null) {
|
|
//
|
|
// Nothing found
|
|
//
|
|
res.status(httpStatus.NOT_FOUND).json({
|
|
code: 192,
|
|
info: 'Not found'
|
|
});
|
|
} else {
|
|
//
|
|
// Anonymise all the account before sending them out
|
|
//
|
|
anon.anonymiseAccount(item);
|
|
//
|
|
// Rename _id to AccountId
|
|
//
|
|
item.AccountID = item._id;
|
|
delete item._id;
|
|
|
|
//
|
|
// Null any nullable fields
|
|
//
|
|
swaggerUtils.getAndApplyNullableFields(req.swagger.operation, item);
|
|
|
|
res.status(httpStatus.OK).json(item);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Updates billing address or customer name for a specific account.
|
|
*
|
|
* @param {Object} req - Express request object
|
|
* @param {Object} res - Express response object
|
|
*/
|
|
function updateAccount(req, res) {
|
|
//
|
|
// Get the query params from the request and the session
|
|
//
|
|
var clientID = req.session.data.clientID;
|
|
var accountId = req.swagger.params.objectId.value;
|
|
|
|
//
|
|
// Get the optional parameters for the update
|
|
//
|
|
var accountName = req.swagger.params.body.value.ClientAccountName;
|
|
var billingAddress = req.swagger.params.body.value.BillingAddress;
|
|
var lock = req.swagger.params.body.value.Lock;
|
|
|
|
if (accountName === undefined &&
|
|
billingAddress === undefined &&
|
|
lock === undefined) {
|
|
//
|
|
// Nothing to update
|
|
//
|
|
res.status(httpStatus.BAD_REQUEST).json({
|
|
code: 30004,
|
|
info: 'No update parameters included'
|
|
});
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If we have been given a new billing address we need to check it actually
|
|
// belongs to the user. This requires a database lookup so we use a
|
|
// promise to wait for the result.
|
|
//
|
|
var validAddressPromise;
|
|
const FAILED_UPDATE = 'BRIDGE: FAILED UPDATE';
|
|
const NULL_ADDRESS = 'BRIDGE: ADDR CANT BE NULL';
|
|
|
|
if (billingAddress) {
|
|
validAddressPromise = referenceUtils.isValidAddressRef(
|
|
clientID,
|
|
billingAddress,
|
|
'WebConsole:updateAccount'
|
|
);
|
|
} else {
|
|
//
|
|
// Haven't asked to update billing address, so nothing to check
|
|
//
|
|
validAddressPromise = Q.resolve();
|
|
}
|
|
|
|
//
|
|
// Also check that we don't have an account with the same name already
|
|
//
|
|
var validAccountPromise = Q.resolve();
|
|
const SAME_NAME = 'Bridge: Account with the same name';
|
|
if (accountName) {
|
|
var options = {
|
|
fields: {
|
|
_id: true
|
|
},
|
|
comment: 'WebConsole:updateAccount'
|
|
};
|
|
var uniqueNameQuery = {
|
|
ClientID: clientID,
|
|
ClientAccountName: accountName
|
|
};
|
|
|
|
validAccountPromise = Q.nfcall(
|
|
mainDB.findOneObject,
|
|
mainDB.collectionAccount,
|
|
uniqueNameQuery,
|
|
options,
|
|
false
|
|
).then(function(result) {
|
|
if (result !== null && result._id.toString() !== accountId) {
|
|
// Some other account has this name
|
|
return Q.reject({name: SAME_NAME});
|
|
}
|
|
return Q.resolve();
|
|
});
|
|
}
|
|
|
|
//
|
|
// Update the account, after checking the billing address is valid
|
|
//
|
|
var updatePromise = Q.all([validAddressPromise, validAccountPromise]).then(function() {
|
|
var query = {
|
|
_id: mongodb.ObjectID(accountId), // The account to update
|
|
ClientID: clientID, // Must be *my* account
|
|
AccountStatus: {
|
|
$bitsAllClear: utils.AccountDeleted // Must not be "deleted"
|
|
}
|
|
};
|
|
|
|
var updates = {
|
|
$set: {
|
|
LastUpdate: new Date()
|
|
},
|
|
$inc: {
|
|
LastVersion: 1
|
|
}
|
|
};
|
|
if (accountName !== undefined) {
|
|
updates.$set.ClientAccountName = accountName;
|
|
}
|
|
if (billingAddress !== undefined) {
|
|
//
|
|
// Special case: can't set the billing address to NULL (but this
|
|
// isn't checked by validation because we could *return* a null
|
|
// billing address for legacy accunts.
|
|
//
|
|
if (billingAddress === null) {
|
|
return Q.reject({name: NULL_ADDRESS});
|
|
}
|
|
updates.$set.BillingAddress = billingAddress;
|
|
}
|
|
|
|
//
|
|
// Update the locked status of the account
|
|
// jshint -W016
|
|
//
|
|
if (lock !== undefined) {
|
|
if (lock) {
|
|
updates.$bit = {
|
|
AccountStatus: {or: utils.AccountLocked}
|
|
};
|
|
} else {
|
|
updates.$bit = {
|
|
AccountStatus: {and: ~utils.AccountLocked}
|
|
};
|
|
}
|
|
}
|
|
// jshint +W016
|
|
|
|
var options = {
|
|
upsert: false,
|
|
multi: false
|
|
};
|
|
|
|
return Q.nfcall(
|
|
mainDB.updateObject,
|
|
mainDB.collectionAccount,
|
|
query,
|
|
updates,
|
|
options,
|
|
false
|
|
).then(function(results) {
|
|
if (results.result.n === 0) {
|
|
return Q.reject({name: FAILED_UPDATE});
|
|
} else {
|
|
return Q.resolve();
|
|
}
|
|
});
|
|
});
|
|
|
|
//
|
|
// Run all the promises and check they pass
|
|
//
|
|
Q.all([validAddressPromise, validAccountPromise, updatePromise])
|
|
.then(function() {
|
|
// All good
|
|
res.status(200).json();
|
|
})
|
|
.catch(function(error) {
|
|
debug('-- error updating account: ', error);
|
|
if (
|
|
error &&
|
|
error.hasOwnProperty('name')
|
|
) {
|
|
switch (error.name) {
|
|
case referenceUtils.ERRORS.INVALID_ADDRESS:
|
|
// Billing address is not valid
|
|
res.status(httpStatus.NOT_FOUND).json({
|
|
code: 393,
|
|
info: 'Billing address not found'
|
|
});
|
|
break;
|
|
|
|
case NULL_ADDRESS:
|
|
// Billing address is not valid
|
|
res.status(httpStatus.BAD_REQUEST).json({
|
|
code: 393,
|
|
info: 'Billing address can\'t be null'
|
|
});
|
|
break;
|
|
|
|
case FAILED_UPDATE:
|
|
// Couldn't update - probably not *my* account
|
|
res.status(httpStatus.NOT_FOUND).json({
|
|
code: 395,
|
|
info: 'Account not found'
|
|
});
|
|
break;
|
|
|
|
case SAME_NAME:
|
|
// Can't have an account with the same name
|
|
res.status(httpStatus.CONFLICT).json({
|
|
code: 30107,
|
|
info: 'Account with the same name already exists'
|
|
});
|
|
break;
|
|
|
|
case 'MongoError':
|
|
// Mongo Error
|
|
res.status(httpStatus.BAD_GATEWAY).json({
|
|
code: 392,
|
|
info: 'Database Unavailable'
|
|
});
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Unknown error
|
|
//
|
|
res.status(httpStatus.INTERNAL_SERVER_ERROR).json({
|
|
code: -1,
|
|
info: 'Unexpected error'
|
|
});
|
|
break;
|
|
}
|
|
} else {
|
|
//
|
|
// Unknown error
|
|
//
|
|
res.status(httpStatus.INTERNAL_SERVER_ERROR).json({
|
|
code: -1,
|
|
info: 'Unexpected error'
|
|
});
|
|
}
|
|
})
|
|
.done(); // Catch all
|
|
}
|
|
|
|
/**
|
|
* Base function to adds a new merchant account. All merchant accounts are added
|
|
* in the same basic way, but may have different requirements for the format
|
|
* of parameters (particualarly MerchantID and ClientKey). Any validation
|
|
* of format, or liveness of account, should be done before calling this function,
|
|
* which assumes everything is correct.
|
|
*
|
|
* @param {Object} req - Express request object
|
|
* @param {Object} res - Express response object
|
|
* @param {Object} extData - additional info to set in the account
|
|
* @param {String} extData.VendorAccountName - name of account at aquirer
|
|
* @param {String} extData.AcquirerName - Name of acquirer (e.g. "Demo")
|
|
* @param {String} extData.VendorID - ID acquirer in our system (e.g. "Bridge")
|
|
* @param {String} extData.IconLocation - Name of the icon for this acquirer
|
|
*
|
|
* @return {Promise} - A promise for the result of adding the account
|
|
*/
|
|
function addAccountBase(req, res, extData) {
|
|
//
|
|
// Get the query params from the request and the session
|
|
//
|
|
var clientID = req.session.data.clientID;
|
|
var isMerchant = req.session.data.isMerchant;
|
|
|
|
//
|
|
// Precondition 0: Must be able to encrypt the account ID and cipher
|
|
//
|
|
let encryptP = Q.resolve();
|
|
let encMerchantID = '';
|
|
let encCipher = '';
|
|
const ENCRYPTION_FAILED = 'BRIDGE: Encryption failed';
|
|
if (extData.VendorID !== 'Bridge') {
|
|
encMerchantID = utils.encryptDataV1(req.swagger.params.body.value.AcquirerMerchantID);
|
|
encCipher = utils.encryptDataV1(req.swagger.params.body.value.AcquirerCipher);
|
|
|
|
if (!_.isString(encMerchantID) || !_.isString(encCipher)) {
|
|
encryptP = Q.reject({name: ENCRYPTION_FAILED});
|
|
}
|
|
}
|
|
|
|
//
|
|
// Merge the default blank account plus the parameters from the request
|
|
//
|
|
var newAccount = _.assign(
|
|
mainDB.blankAccount(),
|
|
{
|
|
// Base items
|
|
AccountType: 'Credit/Debit Receiving Account',
|
|
ReceivingAccount: 1,
|
|
PaymentsAccount: 0,
|
|
AcquirerName: extData.AcquirerName,
|
|
VendorID: extData.VendorID,
|
|
IconLocation: extData.IconLocation,
|
|
UserImage: 'CompanyLogo0',
|
|
AccountStatus: utils.AccountLocked, // Prevents the account being deleted
|
|
VendorAccountName: extData.VendorAccountName,
|
|
|
|
// Items from the request
|
|
NameOnAccount: req.swagger.params.body.value.NameOnAccount,
|
|
ClientAccountName: req.swagger.params.body.value.ClientAccountName,
|
|
BillingAddress: req.swagger.params.body.value.BillingAddress,
|
|
AcquirerMerchantID: encMerchantID,
|
|
AcquirerCipher: encCipher,
|
|
|
|
// Calculated items
|
|
ClientID: clientID,
|
|
LastUpdate: new Date(),
|
|
LastVersion: 1
|
|
});
|
|
|
|
//
|
|
// Precondition 1: Must be a merchant
|
|
//
|
|
const NOT_A_MERCHANT = 'BRIDGE: Client is not a registered merchant';
|
|
const isAMerchantP = isMerchant ? Q.resolve() : Q.reject({name: NOT_A_MERCHANT});
|
|
|
|
//
|
|
// Precondition 2: Merchant must be configured (have CompanyName and
|
|
// CompanyAlias).
|
|
//
|
|
var merchantConfigQuery = {
|
|
ClientID: clientID,
|
|
'Merchant.0.CompanyName': {$ne: ''},
|
|
'Merchant.0.CompanyAlias': {$ne: ''}
|
|
};
|
|
var options = {
|
|
fields: {}, // Don't want any fields, just checking existence
|
|
comment: 'WebConsole:addAccountCredorax'
|
|
};
|
|
const MERCHANT_NOT_CONFIGURED = 'Bridge: Merchant is not configured';
|
|
var merchantConfiguredP = isAMerchantP.then(() => {
|
|
return Q.nfcall(
|
|
mainDB.findOneObject,
|
|
mainDB.collectionClient,
|
|
merchantConfigQuery,
|
|
options,
|
|
false
|
|
).then(function(result) {
|
|
if (!result) {
|
|
return Q.reject({name: MERCHANT_NOT_CONFIGURED});
|
|
}
|
|
return Q.resolve();
|
|
});
|
|
});
|
|
|
|
//
|
|
// Precondition 3: Client must have a device registered before
|
|
//
|
|
var deviceQuery = {
|
|
ClientID: clientID,
|
|
DeviceStatus: {
|
|
$bitsAllSet: utils.DeviceFullyRegistered
|
|
}
|
|
};
|
|
|
|
const NO_DEVICE = 'Bridge: No devices on account';
|
|
var hasDeviceP = merchantConfiguredP.then(function() {
|
|
return Q.nfcall(
|
|
mainDB.findOneObject,
|
|
mainDB.collectionDevice,
|
|
deviceQuery,
|
|
options,
|
|
false).then(function(result) {
|
|
if (!result) {
|
|
return Q.reject({name: NO_DEVICE});
|
|
}
|
|
return Q.resolve();
|
|
});
|
|
});
|
|
|
|
//
|
|
// Precondition 4: Must not have an active account with the same name already
|
|
//
|
|
const SAME_NAME = 'Bridge: Account with the same name';
|
|
var uniqueNameQuery = {
|
|
ClientID: clientID,
|
|
ClientAccountName: newAccount.ClientAccountName,
|
|
AccountStatus: {
|
|
$bitsAllClear: utils.AccountDeleted
|
|
}
|
|
};
|
|
|
|
var checkUniqueNameP = hasDeviceP.then(function() {
|
|
return Q.nfcall(
|
|
mainDB.findOneObject,
|
|
mainDB.collectionAccount,
|
|
uniqueNameQuery,
|
|
options,
|
|
false
|
|
).then(function(result) {
|
|
if (result !== null) {
|
|
return Q.reject({name: SAME_NAME});
|
|
}
|
|
return Q.resolve();
|
|
});
|
|
});
|
|
|
|
//
|
|
// Precondition 5: Address must exist and belong to me
|
|
//
|
|
var addressExistsP = checkUniqueNameP.then(function() {
|
|
return referenceUtils.isValidAddressRef(
|
|
clientID,
|
|
newAccount.BillingAddress,
|
|
'WebConsole:addAccountBase'
|
|
);
|
|
});
|
|
|
|
//
|
|
// Precondition 6: Account must be validated with the acquirer
|
|
//
|
|
var validateP = addressExistsP.then(
|
|
() => acquirerUtils.validateMerchantAccount(newAccount)
|
|
);
|
|
|
|
//
|
|
// Add the account details to the database
|
|
//
|
|
var addP = validateP.then(function() {
|
|
return Q.nfcall(
|
|
mainDB.addObject,
|
|
mainDB.collectionAccount,
|
|
newAccount,
|
|
undefined,
|
|
false
|
|
);
|
|
});
|
|
|
|
//
|
|
// Run all the promises and return the result
|
|
//
|
|
return Q.all([encryptP, isAMerchantP, merchantConfiguredP, hasDeviceP, checkUniqueNameP, addressExistsP, validateP, addP])
|
|
.then(function(results) {
|
|
var newAccountResult = results[7][0];
|
|
res.status(201).json({
|
|
id: newAccountResult._id
|
|
});
|
|
return;
|
|
})
|
|
.catch(function(error) {
|
|
debug('-- error adding account: ', error);
|
|
const responses = [
|
|
[
|
|
'MongoError',
|
|
// Mongo Error
|
|
httpStatus.BAD_GATEWAY, 30104, 'Database Unavailable',
|
|
true
|
|
],
|
|
[
|
|
referenceUtils.ERRORS.INVALID_ADDRESS,
|
|
httpStatus.NOT_FOUND, 30102, 'Billing address not found',
|
|
true
|
|
],
|
|
[
|
|
ENCRYPTION_FAILED,
|
|
httpStatus.BAD_REQUEST, -1, 'Invalid AcquirerMerchantID or AcquirerCipher',
|
|
true
|
|
],
|
|
[
|
|
NOT_A_MERCHANT,
|
|
httpStatus.FORBIDDEN, 30101, 'Client is not a merchant',
|
|
true
|
|
],
|
|
[
|
|
MERCHANT_NOT_CONFIGURED,
|
|
httpStatus.PRECONDITION_FAILED, 30106,
|
|
'Company details must be configured before adding a merchant account',
|
|
true
|
|
],
|
|
|
|
[
|
|
SAME_NAME,
|
|
httpStatus.CONFLICT, 30103, 'An account with the same description already exists',
|
|
true
|
|
],
|
|
|
|
[
|
|
NO_DEVICE,
|
|
httpStatus.PRECONDITION_FAILED, 30105,
|
|
'Client must have a registered device before adding a merchant account',
|
|
true
|
|
],
|
|
//
|
|
// Errors from the acquirer validation
|
|
//
|
|
[
|
|
acquirerUtils.ERRORS.UNKNOWN_ACQUIRER,
|
|
httpStatus.BAD_REQUEST, 30109, 'Merchant acquirer unknown',
|
|
true
|
|
],
|
|
[
|
|
acquirerUtils.ERRORS.ACQUIRER_DOWN,
|
|
httpStatus.BAD_GATEWAY, 30110, 'Cannot connect to acquirer',
|
|
true
|
|
],
|
|
[
|
|
acquirerUtils.ERRORS.INVALID_MERCHANT_ACCOUNT_DETAILS,
|
|
httpStatus.BAD_REQUEST, 30111, 'Receiving account information unreadable',
|
|
true
|
|
],
|
|
[
|
|
acquirerUtils.ERRORS.ACQUIRER_UNKNOWN_ERROR,
|
|
httpStatus.BAD_GATEWAY, 30112, 'Unknown acquirer error',
|
|
true
|
|
],
|
|
[
|
|
acquirerUtils.ERRORS.ACQUIRER_BAD_REQUEST,
|
|
httpStatus.INTERNAL_SERVER_ERROR, 30113, 'Bad request to acquirer',
|
|
true
|
|
],
|
|
[
|
|
acquirerUtils.ERRORS.ACQUIRER_UNAUTHORIZED,
|
|
httpStatus.BAD_REQUEST, 30114, 'Merchant account details invalid.',
|
|
true
|
|
],
|
|
[
|
|
acquirerUtils.ERRORS.ACQUIRER_MERCHANT_DISABLED,
|
|
httpStatus.BAD_REQUEST, 30115, 'Merchant account disabled. Re-enable before adding',
|
|
true
|
|
],
|
|
[
|
|
acquirerUtils.ERRORS.ACQUIRER_INTERNAL_SERVER_ERROR,
|
|
httpStatus.BAD_GATEWAY, 30116, 'Internal server error at enquirer',
|
|
true
|
|
]
|
|
];
|
|
|
|
const responseHandler = new responsesUtils.ErrorResponses(responses);
|
|
responseHandler.respond(res, error);
|
|
})
|
|
.done();
|
|
}
|
|
|
|
/**
|
|
* Adds a new Credorax merchant account. This can only be done for clients who
|
|
* have been enabled as merchants, and do not already have the max number of
|
|
* accounts
|
|
*
|
|
* @param {Object} req - Express request object
|
|
* @param {Object} res - Express response object
|
|
*/
|
|
function addAccountCredorax(req, res) {
|
|
//
|
|
// TODO: Validate account against Credorax
|
|
//
|
|
|
|
//
|
|
// Call the base function to add it to the database
|
|
//
|
|
return addAccountBase(req, res, {
|
|
VendorAccountName: 'Merchant Card Account', // Not used by Credorax so hardcode
|
|
AcquirerName: 'Credorax',
|
|
VendorID: 'Credorax',
|
|
IconLocation: 'credorax-account.png'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Adds a new Worldpay merchant account. This can only be done for clients who
|
|
* have been enabled as merchants, and do not already have the max number of
|
|
* accounts
|
|
*
|
|
* @param {Object} req - Express request object
|
|
* @param {Object} res - Express response object
|
|
*/
|
|
function addAccountWorldpay(req, res) {
|
|
//
|
|
// TODO: Validate account against Worldpay
|
|
//
|
|
|
|
//
|
|
// Call the base function to add it to the database
|
|
//
|
|
return addAccountBase(req, res, {
|
|
VendorAccountName: 'Merchant Card Account', // Not used by worldpay so hardcode
|
|
AcquirerName: 'Worldpay',
|
|
VendorID: 'Worldpay',
|
|
IconLocation: 'worldpay-account.png'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Adds a new Demo merchant account. This can only be done for clients who
|
|
* have been enabled as merchants, and do not already have the max number of
|
|
* accounts.
|
|
* This is an internal demo account that will never perform a real charge against
|
|
* a card.
|
|
*
|
|
* @param {Object} req - Express request object
|
|
* @param {Object} res - Express response object
|
|
*/
|
|
function addAccountDemo(req, res) {
|
|
//
|
|
// Add (Demo) to the client account name, to help make it more obvious
|
|
//
|
|
req.swagger.params.body.value.ClientAccountName += ' (Demo)';
|
|
|
|
//
|
|
// Call the base function to add it to the database
|
|
//
|
|
return addAccountBase(req, res, {
|
|
VendorAccountName: 'Standard Merchant Account', // Not used, so hardcode
|
|
AcquirerName: 'Demo',
|
|
VendorID: 'Bridge',
|
|
IconLocation: 'BRIDGE_MERCHANT.png'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Deletes an account from the system by setting the "deleted" status. It also
|
|
* attempts to disable the token on the merchant aquirer system if appropriate.
|
|
*
|
|
* @param {Object} req - Express request object.
|
|
* @param {Object} res - Express response object.
|
|
*/
|
|
function deleteAccount(req, res) {
|
|
//
|
|
// Get the query params from the request and the session
|
|
//
|
|
const clientID = req.session.data.clientID;
|
|
const accountId = req.swagger.params.objectId.value;
|
|
|
|
//
|
|
// Call the implementation and return the properly formatted
|
|
//
|
|
return deleteAccountImpl.deleteAccount(clientID, accountId)
|
|
.then(function() {
|
|
return res.status(200).json();
|
|
})
|
|
.catch(function(error) {
|
|
debug('-- error deleting account: ', error);
|
|
const responses = [
|
|
[
|
|
deleteAccountImpl.ERRORS.RELATED_INVOICES,
|
|
httpStatus.CONFLICT, 30108, 'Account can\'t be deleted while related active invoices exist', true
|
|
],
|
|
[
|
|
deleteAccountImpl.ERRORS.NOT_FOUND,
|
|
// AccountID is not valid (or doesn't belong to *me*)
|
|
httpStatus.NOT_FOUND, 153, 'Account not found', true
|
|
],
|
|
[
|
|
deleteAccountImpl.ERRORS.FAILED_UPDATE,
|
|
// AccountID is not valid (or doesn't belong to *me*)
|
|
httpStatus.NOT_FOUND, 153, 'Account not found', true
|
|
],
|
|
[
|
|
deleteAccountImpl.ERRORS.LOCKED,
|
|
httpStatus.FORBIDDEN, 243, 'Account is locked and cant be deleted', true
|
|
],
|
|
[
|
|
acquirerUtils.ERRORS.UNKNOWN_ACQUIRER,
|
|
httpStatus.INTERNAL_SERVER_ERROR, 241, 'Unknown acquirer', true
|
|
],
|
|
[
|
|
acquirerUtils.ERRORS.ACQUIRER_DOWN,
|
|
httpStatus.BAD_GATEWAY, 244, 'Cannot connect to acquiring bank', true
|
|
],
|
|
[
|
|
'MongoError',
|
|
// Mongo Error
|
|
httpStatus.BAD_GATEWAY, 30104, 'Database Unavailable'
|
|
]
|
|
];
|
|
const responseHandler = new responsesUtils.ErrorResponses(responses);
|
|
|
|
return responseHandler.respond(res, error);
|
|
})
|
|
.done();
|
|
}
|