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

249 lines
8.1 KiB
JavaScript

/**
* Controller to manage the transactions functions
*/
'use strict';
var _ = require('lodash');
var httpStatus = require('http-status-codes');
var mongodb = require('mongodb');
var debug = require('debug')('webconsole-api:controllers:transactions');
var mainDB = require(global.pathPrefix + 'mainDB.js');
var swaggerUtils = require(global.pathPrefix + '../utils/swaggerUtils.js');
module.exports = {
getTransactions: getTransactions,
getTransaction: getTransaction
};
/**
* Get the transaction history
*
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
function getTransactions(req, res) {
//
// Get the query params from the request and the session
//
var clientID = req.session.data.clientID;
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 transactionTypes = req.swagger.params.transactionTypes.value;
var accountId = req.swagger.params.accountId.value;
var query = {
ClientID: clientID
};
//
// Add date limits if included
//
if (minDate || maxDate) {
query.SaleTime = {};
if (minDate) {
query.SaleTime.$gte = minDate;
}
if (maxDate) {
query.SaleTime.$lte = maxDate;
}
}
//
// Add accountId limits if any
//
if (accountId) {
query.AccountID = accountId;
}
//
// Limit to specific transaction types if requested
//
if (transactionTypes && _.isArray(transactionTypes)) {
query.TransactionType = {};
query.TransactionType.$in = transactionTypes;
}
//
// Define the projection based on the Swagger definition
//
var projection = swaggerUtils.swaggerToMongoProjection(
req.swagger.operation,
false // prevent _id being included
);
//
// Make the query. Not limit & skip have defaults defined in the
// swagger definition, so will always exist even if not requested
//
mainDB.collectionTransactionHistory.find(query, projection)
.skip(skip)
.limit(limit)
.sort({'SaleTime': -1}) // Hard-coded reverse sort by time
.toArray(function(err, items) {
if (err) {
debug('- failed to getTransactions', err);
res.status(httpStatus.BAD_GATEWAY).json({
code: 197,
info: 'Database offline'
});
} else {
//
// Move invoice number to the top level
//
for (var i = 0; i < items.length; ++i) {
if (!_.isUndefined(items[i].MerchantInvoiceNumber)) {
items[i].MerchantInvoiceNumber =
items[i].MerchantInvoiceNumber.InvoiceNumber;
}
}
res.status(httpStatus.OK).json(items);
}
});
}
/**
* Gets the transaction details for a specific transaction. The id is the
* `TransactionID` from the getTransactions() summary items.
*
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
function getTransaction(req, res) {
//
// Get the query params from the request and the session
//
var clientID = req.session.data.clientID;
var transactionId = 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 customer or merchant (for security, to protect
// against Insecure Direct Object References).
//
var query = {
_id: mongodb.ObjectID(transactionId),
$or: [
{CustomerClientID: clientID},
{MerchantClientID: clientID}
]
};
//
// Depending on whether the user is a customer or merchant we convert some
// of the parameters to different names. This table defines these
// conversions.
// Note: any items not in this table, but in the swagger definition are
// assumed to come direct from the database unchanged.
//
const IS_CUSTOMER_INDEX = 0;
const IS_MERCHANT_INDEX = 1;
var conversions = {
// Structure is:
// ResponseField: [IsCustomerDbField, IsMerchantDbField]
//
OtherDisplayName: ['MerchantDisplayName', 'CustomerDisplayName'],
OtherSubDisplayName: ['MerchantSubDisplayName', 'CustomerSubDisplayName'],
OtherImage: ['MerchantImage', 'CustomerImage'],
MyLocation: ['CustomerLocation', 'MerchantLocation']
};
//
// Define the fields based on the Swagger definition.
// When going through the swagger definitions we check in the conversion
// table above, and fill in both fields so we have the required data to
// later do the conversion.
// Note: we allow _id here because the user provided it to us so no point
// hiding it.
//
var projection = {
// Initialise with client names to match against later on
MerchantClientID: 1,
CustomerClientID: 1
};
_.forEach(
req.swagger.operation.responses['200'].schema.properties,
_.bind(function(value, key, collection) {
if (conversions.hasOwnProperty(key)) {
// Has a conversion: include both
this[conversions[key][IS_CUSTOMER_INDEX]] = 1;
this[conversions[key][IS_MERCHANT_INDEX]] = 1;
} else {
// Doesn't have a conversion: include this one directly
this[key] = 1;
}
}, projection)
);
//
// Build the options to encapsulate the projection
//
var options = {
fields: projection,
comment: 'WebConsole:getTransaction' // For profiler logs use
};
//
// Make the request
//
mainDB.findOneObject(mainDB.collectionTransaction, query, options, false,
function(err, item) {
if (err) {
debug('- failed to getTransaction', 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 {
//
// Need to handle the conversions. Three step process:
// 1. Am 'I' the customer or merchant?
// - Must be one or other due to the search condition
// 2. Copy appropriate value from the DB name to the response name
// 3. Delete all DB name items
//
var conversionIndex = IS_CUSTOMER_INDEX;
if (item.MerchantClientID === clientID) {
conversionIndex = IS_MERCHANT_INDEX;
}
_.forEach(
conversions,
function(value, key, collection) {
item[key] = item[value[conversionIndex]];
});
_.forEach(
conversions,
function(value, key, collection) {
delete item[value[IS_CUSTOMER_INDEX]];
delete item[value[IS_MERCHANT_INDEX]];
});
// Delete the two hard-coded names we got for matching above
delete item.CustomerClientID;
delete item.MerchantClientID;
//
// Move invoice number to the top level
//
if (!_.isUndefined(item.MerchantInvoiceNumber)) {
item.MerchantInvoiceNumber =
item.MerchantInvoiceNumber.InvoiceNumber;
}
res.status(httpStatus.OK).json(item);
}
});
}