Source: models/warehouses.js

const Assets = require('./assets');
/**
 * Class represents warehouses and offers methods for dealing with warehouses in core database
 * @class
 */
class warehouses {
    /**
     * @constructor
     * @param {object} alogger Logger to be used by instance (usually req.app.logger)
     */
    constructor(alogger) {
        this.logger = alogger;
    }


    /**
     * Returns list of all warehouses
     * @param {function} callback rows or null
     */
    getListOfWarehouses(callback) {
        this.logger.debug('MODELS-WAREHOUSES | Reading warehouses');

        let query = "SELECT * FROM assets_warehouses WHERE state = 1 ORDER BY wareHousePath";
        global.coreDb.all(query, [], (err, rows) => {
            if (err) {
                return null;
            } else {
                return callback(rows);
            }
        });
    }

    /**
     * Returns a single warehouse with given warehouse id from core database
     * @param {integer} wId id of warehouse to load from core database
     * @param {*} callback row or null
     */
    getWarehouseWithId(wId, callback) {
        let query = "SELECT * FROM assets_warehouses WHERE id = ?";
        global.coreDb.all(query, [
            wId
        ], (err, rows) => {
            if (err) {
                console.log('MODELS-WAREHOUSES | Error loading Warehouse data: ' + err.message);
                return null;
            } else {
                console.log('MODELS-WAREHOUSES | Loaded Warehouse data and found count: ' + rows.length);
                return callback(rows);
            }
        });
    }

    /**
     * Returns list of all Warenhouses for list view in UI
     * @param {function} callback rows or null
     */
    getListOfWarehousesForTable(callback) {
        this.logger.debug('MODELS-WAREHOUSES | Reading warehouses');
        let query = "SELECT 	e.*, " +
            "organizations.name AS organizationname, " +
            "locations.name AS locationname, " +
            "m.name AS parentWareHouseName " +
            "FROM assets_warehouses e " +
            "LEFT JOIN organizations ON e.organizationId = organizations.id " +
            "LEFT JOIN locations ON e.locationId = locations.id " +
            "LEFT JOIN assets_warehouses m ON e.parentWareHouseId = m.id";

        global.coreDb.all(query, [], (err, rows) => {
            if (err) {
                return null;
            } else {
                return callback(rows);
            }
        });
    }

    /**
     * Returns warehouses for given location
     * @param {integer} locationId id of location object the warehouses should be returned for
     * @param {function} callback rows or null
     */
    getListOfWarehousesForLocationId(locationId, callback) {
        this.logger.debug('MODELS-WAREHOUSES | Reading warehouses');

        let query = "SELECT * FROM assets_warehouses WHERE state = 1 AND locationId = ?";
        global.coreDb.all(query, [
            locationId
        ], (err, rows) => {
            if (err) {
                return null;
            } else {
                return callback(rows);
            }
        });
    }

    /**
     * 
     * @param {integer} organizationId id of organization the warehouses should be returned for
     * @param {function} callback rows or null
     */
    getListOfWarehousesForOrganizationId(organizationId, callback) {
        this.logger.debug('MODELS-WAREHOUSES | Reading warehouses');

        let query = "SELECT warehouses * FROM assets_warehouses WHERE state = 1 AND organizationId = ?";
        global.coreDb.all(query, [
            organizationId
        ], (err, rows) => {
            if (err) {
                return null;
            } else {
                return callback(rows);
            }
        });
    }

    /**
     * Returns warehouse path of parent warehouse given in pwId
     * @param {integer} pwId id of parentWarehouse
     * @param {string} callback parent warehouse path as string
     */
    getWarehousePathFromParentWarehouse(pwId, callback) {
        let query = "SELECT * FROM assets_warehouses WHERE id = ?";
        global.coreDb.all(query, [
            pwId
        ], (err, rows) => {
            if (err) {
                return null;
            } else {
                if (rows.length > 0) {
                    return callback(rows[0].wareHousePath);
                } else {
                    return callback('');
                }
            }
        });
    }

    /**
     * Adds a new warehouse to core database
     * @param {object} data form fields data (usually req.body)
     * @param {function} callback success (true or false)
     */
    addWarehouse(reqBody, callback) {
        this.logger.debug('MODELS-WAREHOUSES | adding Warehouse to database');

        let name = reqBody.warehousename;
        let organizationId = reqBody.organizaionId;
        let locationId = reqBody.locationId;
        let parentWarehouseId = reqBody.parentWarehouseId;
       
        if (Number.isInteger(parseInt(parentWarehouseId)) === false) {
            parentWarehouseId = null;
        }
        let description = reqBody.description;
        let wareHousePath = reqBody.warehousename;

        this.getWarehousePathFromParentWarehouse(parentWarehouseId, (parentWareHousePath) => {

            if (parentWareHousePath !== null) {
                if (parentWareHousePath.length > 0) {
                    wareHousePath  = parentWareHousePath + " | " + wareHousePath;
                }
            }

            let query = "INSERT INTO assets_warehouses " +
                "(`name`, " +
                "`locationId`, " +
                "`parentWarehouseId`, " +
                "`organizationId`, " +
                "`state`, " +
                "`description`, " +
                "`wareHousePath`) " +
                "VALUES " +
                "(?, ?, ?, ?, ?, ?, ?)";

            global.coreDb.run(query,
                [
                    name,
                    locationId,
                    parentWarehouseId,
                    organizationId,
                    1,
                    description,
                    wareHousePath
                ],
                function (err) {
                    if (err) {
                        console.log('ERROR Adding new basedata enty to core database: ' + err.message);
                        callback(false);
                    } else {
                        callback(true);
                    }
                });
        })
    }

    /**
     * 
     * @param {object} reqBody form fields data (usually req.body)
     * @param {integer} whId id of warehouse to be updated
     * @param {function} callback success (true or false)
     */
    editWarehouse(reqBody, whId, callback) {
        this.logger.debug('MODELS-WAREHOUSES | updating Warehouse in core database');

        let name = reqBody.warehousename;
        let organizationId = reqBody.organizaionId;
        let locationId = reqBody.locationId;
        let parentWarehouseId = reqBody.parentWarehouseId;
        
        if (Number.isInteger(parseInt(parentWarehouseId)) === false) {
            parentWarehouseId = null;
        }
        let description = reqBody.description;
        let wareHousePath = reqBody.warehousename;

        this.getWarehousePathFromParentWarehouse(parentWarehouseId, (parentWareHousePath) => {

            if (parentWareHousePath !== null) {
                if (parentWareHousePath.length > 0) {
                    wareHousePath  = parentWareHousePath + " | " + wareHousePath;
                }
            }

            let query = "UPDATE assets_warehouses SET " +
                "name = ?, " +
                "`locationId` = ?, " +
                "`parentWarehouseId` = ?, " +
                "`organizationId` = ?, " +
                "`state` = ?, " +
                "`description` = ?, " +
                "`wareHousePath` = ? " +
                "WHERE id = ?";

            global.coreDb.run(query,
                [
                    name,
                    locationId,
                    parentWarehouseId,
                    organizationId,
                    1,
                    description,
                    wareHousePath,
                    whId
                ],
                function (err) {
                    if (err) {
                        console.log('ERROR Updating warehouse enty in core database: ' + err.message);
                        callback(false);
                    } else {
                        callback(true);
                    }
                });
        })
    }

    /**
     * Checks if a warehouse can be deleted or not.
     * Can not be deleted if there exist referenced subwarehouses or assets are directly attached
     * @param {integer} whId 
     * @param {function} callback 
     */
    approveRemoveForWarehouse(whId, callback) {
        let query = "SELECT * FROM assets_warehouses WHERE parentWarehouseId = ?";
        global.coreDb.all(query, [
            whId
        ], (err, rows) => {
            if (err) {
                return null;
            } else {
                if (rows.length > 0) {
                    return callback(false);
                } else {
                    let assets = new Assets(this.logger);
                    assets.getAssetsForWarehouse(whId, (rowsAssets) => {
                        if (rowsAssets !== null) {
                            if (rowsAssets.length > 0) {
                                callback(false);
                            } else {
                                callback(true);
                            }
                        } else {
                            callback(false);
                        }
                    })
                    return callback(true);
                }
            }
        });
    }

    /**
     * Removes a warehouse from core database, checks upfront if the warehouse can be deleted (if it does not have referenced subwarehouses)
     * @param {integer} whId id of warehouse to be deleted from core database
     * @param {function} callback success (true or false)
     */
    removeWarehouse(whId, callback) {
        this.approveRemoveForWarehouse(whId, (approval) => {
            if (approval) {
                let query = "DELETE FROM assets_warehouses WHERE id = ?";
                global.coreDb.run(query,
                    [
                        whId
                    ],
                    function (err) {
                        if (err) {
                            console.log('ERROR Deleting warehouse enty in core database: ' + err.message);
                            callback(false);
                        } else {
                            callback(true);
                        }
                    });
            } else {
                callback(false);
            }
        })
    }
}

// export the class
module.exports = warehouses;