Source

managers/ParticipantManager.js

const BaseManager = require('../../pdm-dsu-toolkit/managers/BaseManager');
const {EVENTS} = require('../constants');

/**
 * Participant Manager Class - Extension of Base Manager
 *
 * 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 {DSUStorage} DSUStorage
 * @param {function(err, Manager)} [callback] optional callback for when the assurance that the table has already been indexed is required.
 * @class ParticipantManager
 * @extends BaseManager
 * @memberOf Managers
 * @see BaseManager
 */
class ParticipantManager extends BaseManager{
    constructor(dsuStorage, callback) {
        super(dsuStorage, (err, manager) => {
            if (err)
                return callback(err);
            require('./DirectoryManager')(this, (err, directoryManager) => {
                if (err)
                    return callback(err);
                manager.directoryManager = directoryManager;
                require('./StockManager')(this, true, (err, stockManager) => {
                    if (err)
                        return callback(err);
                    manager.stockManager = stockManager;
                    require('./TraceabilityManager')(this, (err, traceabilityManager) => {
                        if (err)
                            return callback(err);
                        manager.traceabilityManager = traceabilityManager;
                        require('./NotificationManager')(this, (err, notificationManager) => {
                            if (err)
                                return callback(err);
                            manager.notificationManager = notificationManager;
                            callback(undefined, manager);
                        });
                    });
                });
            });
        });
        this.directoryManager = this.directoryManager || undefined;
        this.stockManager = this.stockManager || undefined;
        this.traceabilityManager = this.traceabilityManager || undefined;
        this.notificationManager = this.notificationManager || undefined;
    };

    setController(controller) {
        const self = this;
        super.setController(controller);

        // We use the body because popovers are attached to the doc, not the element
        const listenerElement = controller.element.closest('body');

        listenerElement.addEventListener(EVENTS.STOCK_TRACE, async (evt) => {
            const sendError = async function(msg, err){
                await loader.dismiss();
                controller.showErrorToast(msg, err);
            }
            const { gtin, batch, manufName } = evt.detail;
            const loader = controller._getLoader(`Requesting stock from Partners for ${gtin} Batch: ${batch}`);
            await loader.present();
            self.stockManager.getStockTraceability(gtin, {manufName, batch}, async (err, stockTrace) => {
                if (err)
                    return await sendError(err)
                await loader.dismiss();
                console.log('# StockManagement stockTrace=', stockTrace)
            })
        })

        listenerElement.addEventListener(EVENTS.TRACK.REQUEST, async (evt) => {
            evt.preventDefault();
            evt.stopImmediatePropagation();

            const product = evt.detail;

            const serialNumberMsg = !!product.serialNumber ? controller.translate('tracking.serial', product.serialNumber) : '';
            const loader = controller._getLoader(controller.translate('tracking.loading', product.gtin + serialNumberMsg));

            await loader.present();

            const sendError = async function(msg, err){
                await loader.dismiss();
                controller.showErrorToast(controller.translate('loading.error', err), err);
            }

            self.traceabilityManager.getOne(product, async (err, startNode, endNode, nodeList) => {
                if (err)
                    return await sendError(`Could not perform tracking...`, err);
                controller.showToast(controller.translate('tracking.success'));
                const event = new Event(EVENTS.TRACK.RESPONSE, {
                    bubbles: true,
                    cancelable: true
                });
                event.detail = {
                    title: controller.translate(
                        'tracking.title',
                        product.gtin,
                        product.batchNumber,
                        serialNumberMsg
                    ), // controller.translate("tracking.serial", product.serialNumber) || ""),
                    startNode: startNode,
                    endNode: endNode,
                    nodeList: nodeList
                }
                await loader.dismiss();
                evt.target.dispatchEvent(event);
            });
        });

        listenerElement.addEventListener(EVENTS.TRACK.RESPONSE, async (evt) => {
            evt.preventDefault();
            evt.stopImmediatePropagation();
            const popOver = controller.element.querySelector('tracking-pop-over');
            if (!popOver)
                return console.log(`Could not find display element for traceability tree`);
            await popOver.present(evt.detail);
        });
        //
        // controller.on(EVENTS.TRACK.REQUEST, async (evt) => {
        //     evt.preventDefault();
        //     evt.stopImmediatePropagation();
        //
        //     const product = evt.detail;
        //
        //     const loader = controller._getLoader(controller.translate('tracking.loading',
        //         product.gtin + controller.translate('tracking.serial', product.serialNumber)));
        //
        //     await loader.present();
        //
        //     const sendError = async function(msg, err){
        //         await loader.dismiss();
        //         controller.showErrorToast(controller.translate('loading.error', err), err);
        //     }
        //
        //     self.traceabilityManager.getOne(product, async (err, startNode, endNode, nodeList) => {
        //         if (err)
        //             return await sendError(`Could not perform tracking...`, err);
        //         controller.showToast(controller.translate('tracking.success'));
        //         const event = new Event(EVENTS.TRACK.RESPONSE, {
        //             bubbles: true,
        //             cancelable: true
        //         });
        //         event.detail = {
        //             title: controller.translate('tracking.title',
        //                 product.gtin,
        //                 product.batchNumber,
        //                 controller.translate("tracking.serial", product.serialNumber) || ""),
        //             startNode: startNode,
        //             endNode: endNode,
        //             nodeList: nodeList
        //         }
        //         await loader.dismiss();
        //         evt.target.dispatchEvent(event);
        //     });
        // });
        // controller.on(EVENTS.TRACK.RESPONSE, async (evt) => {
        //     evt.preventDefault();
        //     evt.stopImmediatePropagation();
        //     const popOver = controller.element.querySelector('tracking-pop-over');
        //     if (!popOver)
        //         return console.log(`Could not find display element for traceability tree`);
        //     await popOver.present(evt.detail);
        // });
    }

    /**
     * Must return the string to be used to generate the DID
     * @param {object} identity
     * @param {string} participantConstSSI
     * @param {function(err, string)}callback
     * @protected
     * @override
     */
    _getDIDString(identity, participantConstSSI, callback){
        callback(undefined, identity.id + '');
    }
}

let participantManager;

/**
 * @param {DSUStorage} [dsuStorage] only required the first time, if not forced
 * @param {boolean} [force] defaults to false. overrides the singleton behaviour and forces a new instance.
 * Makes DSU Storage required again!
 * @param {function(err, ParticipantManager)} [callback]
 * @returns {ParticipantManager}
 * @memberOf Managers
 */
const getParticipantManager = function (dsuStorage, force, callback) {
    if (!callback){
        if (typeof force === 'function'){
            callback = force;
            force = false;
        }
    }
    if (!participantManager || force) {
        if (!dsuStorage)
            throw new Error("No DSUStorage provided");
        participantManager = new ParticipantManager(dsuStorage, callback);
    }
    return participantManager;
}

module.exports = getParticipantManager;