Source

services/OrderService.js

const Utils = require('../../pdm-dsu-toolkit/services/utils');
const {STATUS_MOUNT_PATH, INFO_PATH, SHIPMENT_PATH, ORDER_MOUNT_PATH} = require('../constants');
const {OrderStatus, Batch} = require("../model");


/**
 * @param {string} domain: anchoring domain. defaults to 'default'
 * @param {strategy} strategy
 * @function OrderService
 * @memberOf Services
 */
function OrderService(domain, strategy) {
    const strategies = require("../../pdm-dsu-toolkit/services/strategy");
    const {Order, OrderStatus, utils} = require('../model');
    const endpoint = 'order';

    domain = domain || "default";
    const statusService = new (require('./StatusService'))(domain, strategy);

    let isSimple = strategies.SIMPLE === (strategy || strategies.SIMPLE);


    this.resolveMAH = function(orderLine, callback){
        const keyGen = require('../commands/setProductSSI').createProductSSI;
        const productSSI = keyGen({gtin: orderLine.gtin}, domain);
        Utils.getResolver().loadDSU(productSSI, (err, dsu) => {
            if (err)
                return callback(`Could not load Product DSU ${err}`);
            dsu.readFile(INFO_PATH, (err, data) => {
                if (err)
                    return callback(`Could not read product from dsu ${err}`);
                let product;
                try{
                    product = JSON.parse(data);
                } catch (e){
                    return callback(`Could not parse Product data ${err}`)
                }
                callback(undefined, product.manufName);
            });
        });
    }

    /**
     * Resolves the DSU and loads the Order object with all its properties, mutable or not
     * @param {KeySSI} keySSI
     * @param {function(err?, Order?, Archive?, KeySSI?)} callback
     */
    this.get = function(keySSI, callback){
        Utils.getResolver().loadDSU(keySSI, {skipCache: true}, (err, dsu) => {
            if (err)
                return callback(err);
            dsu.readFile(INFO_PATH, (err, data) => {
                if (err)
                    return callback(err);
                let order;
                try {
                    order = JSON.parse(data);
                } catch (e) {
                    return callback(`Could not parse order in DSU ${keySSI}`);
                }
                order = new Order(order.orderId, order.requesterId, order.senderId, order.shipToAddress, order.status, order.orderLines);
                console.log('## OrderService.get order=', order);
                Utils.getMounts(dsu, '/', STATUS_MOUNT_PATH, (err, mounts) => {
                    if (err)
                        return callback(err);
                    statusService.get(mounts[STATUS_MOUNT_PATH], (err, status) => {
                        if (err)
                            return callback(err);
                        order.status = status;

                        if (order.status.status === OrderStatus.CREATED)
                            return callback(undefined, order, dsu, keySSI);
                        dsu.readFile(`${SHIPMENT_PATH}${INFO_PATH}`, (err, data) => {
                            if (err || !data)
                                return callback(undefined, order, dsu);
                            let shipment;
                            try {
                                shipment = JSON.parse(data);
                            } catch (e) {
                                return callback(e);
                            }
                            order.shipmentId = shipment.shipmentId;
                            callback(undefined, order, dsu, keySSI);
                        });
                    });
                });
            });
        });
    }

    /**
     * Creates an order
     * @param {Order} order
     * @param {function(err, keySSI)} callback
     */
    this.create = function (order, callback) {
        // if product is invalid, abort immediatly.
        if(!(order instanceof Order))
            order = new Order(order);
        const _err = order.validate();
        if (_err)
            return callback(_err);

        if (isSimple) {
            createSimple(order, callback);
        } else {
            createAuthorized(order, callback);
        }
    }

    const validateUpdate = function(orderFromSSI, updatedOrder, callback){
        if (!utils.isEqual(orderFromSSI, updatedOrder, "status", "orderLines", "shipmentSSI"))
            return callback('invalid update');
        return callback();
    }

    /**
     * updates an order DSU
     * @param {KeySSI} keySSI
     * @param {Order} order
     * @param {function(err?)} callback
     */
    this.update = function (keySSI, order, callback) {
        // if product is invalid, abort immediatly.
        const self = this;

        self.get(keySSI, (err, orderFromSSI, orderDsu) => {
            if (err)
                return callback(err);

            if(!(order instanceof Order))
                order = new Order(order);
            err = order.validate(orderFromSSI.status.status);
            if (err)
                return callback(err);

            const cb = function(err, ...results){
                if (err)
                    return orderDsu.cancelBatch(err2 => {
                        callback(err);
                    });
                callback(undefined, ...results);
            }

            try{
                orderDsu.beginBatch();
            }catch(e){
                return callback(e);
            }

            validateUpdate(orderFromSSI, order, (err) => {
                if (err)
                    return cb(err);
                Utils.getMounts(orderDsu, '/', STATUS_MOUNT_PATH, SHIPMENT_PATH, (err, mounts) => {
                    if (err)
                        return cb(err);
                    if (!mounts[STATUS_MOUNT_PATH])
                        return cb(`Missing mount path ${STATUS_MOUNT_PATH}`);
                    statusService.update(mounts[STATUS_MOUNT_PATH], order.status, order.requesterId, (err) => {
                        if (err)
                            return cb(err);

                        if (!mounts[SHIPMENT_PATH] && order.shipmentSSI)
                            orderDsu.mount(SHIPMENT_PATH, order.shipmentSSI, (err) => {
                                if (err)
                                    return cb(err);
                                orderDsu.commitBatch((err) => {
                                    if(err)
                                        return cb(err);
                                    self.get(keySSI, callback);
                                });
                            });
                        else
                            self.get(keySSI, callback);
                    });
                });
            });
        });
    }

    /**
     * Creates the original OrderStatus DSU
     * @param {string} id
     * @param {OrderStatus} [status]: defaults to OrderStatus.CREATED
     * @param {function(err, keySSI, orderLinesSSI)} callback
     */
    let createOrderStatus = function (id, status, callback) {
        if (typeof status === 'function') {
            callback = status;
            status = OrderStatus.CREATED;
        }
        statusService.create(status, id, (err, keySSI) => {
            if (err)
                return callback(err);
            console.log(`OrderStatus DSU created with SSI ${keySSI.getIdentifier(true)}`);
            callback(undefined, keySSI);
        });
    }

    let createSimple = function (order, callback) {
        let keyGenFunction = require('../commands/setOrderSSI').createOrderSSI;
        let templateKeySSI = keyGenFunction({data: order.orderId + order.requesterId}, domain);
        Utils.selectMethod(templateKeySSI)(templateKeySSI, (err, dsu) => {
            if (err)
                return callback(err);

            const cb = function(err, ...results){
                if (err)
                    return dsu.cancelBatch(err2 => {
                        callback(err);
                    });
                callback(undefined, ...results);
            }

            try {
                dsu.beginBatch();
            } catch (e) {
                return callback(e);
            }

            dsu.writeFile(INFO_PATH, JSON.stringify(order), (err) => {
                if (err)
                    return cb(err);
                console.log("Order /info ", JSON.stringify(order));
                createOrderStatus(order.requesterId, order.status,(err, statusSSI) => {
                    if (err)
                        return cb(err);
                    // Mount must take string version of keyssi
                    dsu.mount(STATUS_MOUNT_PATH, statusSSI.getIdentifier(), (err) => {
                        if (err)
                            return cb(err);
                        console.log(`OrderStatus DSU (${statusSSI.getIdentifier(true)}) mounted at '/status'`);
                        dsu.commitBatch((err) => {
                            if (err)
                                return cb(err);
                            dsu.getKeySSIAsObject((err, keySSI) => {
                                if (err)
                                    return callback(err);
                                console.log("Finished creating Order " + keySSI.getIdentifier(true));
                                callback(undefined, keySSI, order.orderLines);
                            });
                        });
                    });
                });
            });
        });
    }

    let createAuthorized = function (order, callback) {
        let getEndpointData = function (order) {
            return {
                endpoint: endpoint,
                data: {
                    data: order.orderId + order.requesterId
                }
            }
        }

        Utils.getDSUService().create(domain, getEndpointData(order), (builder, cb) => {
            builder.addFileDataToDossier(INFO_PATH, JSON.stringify(order), (err) => {
                if (err)
                    return cb(err);
                createOrderStatus(order.requesterId, (err, statusSSI) => {
                    if (err)
                        return cb(err);
                    builder.mount(STATUS_MOUNT_PATH, statusSSI.getIdentifier(), (err) => {
                        if (err)
                            return cb(err); 
                        cb();    
                    });
                });
            });
        }, callback);
    }
}

module.exports = OrderService;