const { DB, DEFAULT_QUERY_OPTIONS } = require('../constants');
const OrderManager = require("./OrderManager");
const getStockManager = require("./StockManager");
const {Order} = require('../model');
const {toPage, paginate} = require("../../pdm-dsu-toolkit/managers/Page");
/**
* Received Order Manager Class - concrete OrderManager for receivedOrders.
*
* Manager Classes in this context should do the bridge between the controllers
* and the services exposing only the necessary api to the controllers while encapsulating <strong>all</strong> business logic.
*
* All Manager Classes should be singletons.
*
* This complete separation of concerts is very beneficial for 2 reasons:
* <ul>
* <li>Allows for testing since there's no browser dependent code (i think) since the DSUStorage can be 'mocked'</li>
* <li>Allows for different controllers access different business logic when necessary (while benefiting from the singleton behaviour)</li>
* </ul>
*
* @param {ParticipantManager} participantManager
* @param {function(err, Manager)} [callback] optional callback for when the assurance that the table has already been indexed is required.
* @class ReceivedOrderManager
* @extends OrderManager
* @memberOf Managers
*/
class ReceivedOrderManager extends OrderManager {
constructor(participantManager, callback) {
super(participantManager, DB.receivedOrders, ['orderId', 'requesterId', 'status'], (err, manager) => {
if (err)
return callback ? callback(err) : console.log(err);
manager.registerMessageListener((message, cb) => {
manager.processMessageRecord(message, (err) => {
manager.refreshController();
cb(err);
});
});
if (callback)
callback(undefined, manager);
});
this.stockManager = getStockManager(participantManager);
this.participantManager = participantManager;
}
/**
* Not necessary for this manager
* @override
*/
create(key, item, callback) {
callback(`This manager does not have this functionality`);
}
/**
* Must wrap the DB entry in an object like:
* <pre>
* {
* index1: ...
* index2: ...
* value: item
* }
* </pre>
* so the DB can be queried by each of the indexes and still allow for lazy loading
* @param {string} key
* @param {Order} item
* @param {string|object} record
* @return {object} the indexed object to be stored in the db
* @protected
* @override
*/
_indexItem(key, item, record) {
return {...super._indexItem(key, item, record), requesterId: item.requesterId}
};
/**
* Lists all received orders.
* @param {boolean} [readDSU] defaults to true. decides if the manager loads and reads from the dsu's {@link INFO_PATH} or not
* @param {object} [options] query options. defaults to {@link DEFAULT_QUERY_OPTIONS}
* @param {function(err, Order[])} callback
*/
getAll(readDSU, options, callback) {
const defaultOptions = () => Object.assign({}, DEFAULT_QUERY_OPTIONS);
if (!callback) {
if (!options) {
callback = readDSU;
options = defaultOptions();
readDSU = true;
}
if (typeof readDSU === 'boolean') {
callback = options;
options = defaultOptions();
}
if (typeof readDSU === 'object') {
callback = options;
options = readDSU;
readDSU = true;
}
}
options = options || defaultOptions();
super.getAll(readDSU, options, callback);
}
/**
* Processes the received messages, saves them to the the table and deletes the message
* @param {*} message
* @param {function(err)} callback
* @protected
* @override
*/
_processMessageRecord(message, callback) {
let self = this;
if (!message || typeof message !== "string")
return callback(`Message ${message} does not have non-empty string with keySSI. Skipping record.`);
const orderSReadSSIStr = message;
self._getDSUInfo(orderSReadSSIStr, (err, orderObj, orderDsu) => {
if (err)
return self._err(`Could not read DSU from message keySSI in record ${message}. Skipping record.`, err, callback);
console.log(`ReceivedOrder`, orderObj);
const orderId = orderObj.orderId;
if (!orderId)
return callback("ReceivedOrder doest not have an orderId. Skipping record.");
const dbKey = self._genCompostKey(orderObj.requesterId, orderId);
self.getOne(dbKey, false, (err, record) => {
if (err){
console.log(`Received new Order: `, orderObj);
return self.insertRecord(dbKey, self._indexItem(orderId, orderObj, orderSReadSSIStr), callback);
}
/**
* Message/ExtraInfo by default follows the model: `{SENDER_ID} {TIMESTAMP} {MESSAGE}`,
* so need to be sanitized to remove {SENDER_ID} and {TIMESTAMP}, because receiver
* just needs the message
* @param {Status} statusObj
* @returns {string}
*/
const getExtraInfoMsg = function (statusObj) {
const { status, extraInfo } = statusObj;
if (!extraInfo)
return '';
if (!extraInfo.hasOwnProperty(status))
return '';
const lastLog = statusObj.log[statusObj.log.length - 1]
const extraInfoUpdated = extraInfo[status].filter(_extraInfo => {
// verify if extraInfo.timestamp ===log.timestamp
return _extraInfo.split(' ')[1].trim() === lastLog.split(' ')[1].trim()
})
if (extraInfoUpdated.length > 0) {
return extraInfoUpdated[0].split(' ').slice(2).join(' ').trim(); // sanitized
} else {
return '';
}
}
orderObj.status['extraInfo'] = getExtraInfoMsg(orderObj.status);
console.log(`Updating order ${orderObj.orderId} with status ${orderObj.status.status}`)
self.updateRecord(dbKey, self._indexItem(orderId, orderObj, orderSReadSSIStr), (err) => {
if (err)
return self._err(`Could not update order`, err, callback);
if (!orderObj.shipmentId)
return callback(`Missing shipment Id`);
const {getIssuedShipmentManager} = require('./IssuedShipmentManager');
getIssuedShipmentManager(self.participantManager, (err, issuedShipmentManager) => {
if (err)
return self._err(`could not get issued shipment manager`, err, callback);
issuedShipmentManager.updateByOrder(orderObj.shipmentId, orderObj, callback);
});
});
});
});
};
/**
* updates an item
*
* @param {string} [key] key is optional so child classes can override them
* @param {Order} order
* @param {function(err, Order?, Archive?)} callback
*/
update(key, order, callback){
if (!callback){
callback = order;
order = key;
key = this._genCompostKey(order.requesterId, order.orderId);
}
super.update(key, order, callback);
}
}
/**
* @param {ParticipantManager} participantManager
* @param {function(err, Manager)} [callback] optional callback for when the assurance that the table has already been indexed is required.
* @returns {OrderManager}
* @memberOf Managers
*/
const getReceivedOrderManager = function (participantManager, callback) {
let manager;
try {
manager = participantManager.getManager(ReceivedOrderManager);
if (callback)
return callback(undefined, manager);
} catch (e){
manager = new ReceivedOrderManager(participantManager, callback);
}
return manager;
}
module.exports = getReceivedOrderManager;
Source