From d3fee32439c6d9085b9b4ce56e3cbaea6006ff74 Mon Sep 17 00:00:00 2001 From: lomamech Date: Tue, 19 Jan 2021 09:23:09 +0100 Subject: [PATCH] Implement API for aggregate consumption --- client/src/i18n/en/stock.json | 6 ++ client/src/i18n/fr/stock.json | 5 + client/src/js/services/StockService.js | 4 + .../aggregated_consumption.html | 23 ++-- .../aggregated_consumption.js | 42 ++++---- .../templates/days_stock_out.tmpl.html | 3 +- .../templates/quantity_remaining.tmpl.html | 11 -- .../inventory-adjustment.js | 1 + server/config/routes.js | 1 + server/controllers/stock/core.js | 1 + server/controllers/stock/index.js | 102 ++++++++++++++++++ server/models/bhima.sql | 3 +- 12 files changed, 155 insertions(+), 47 deletions(-) delete mode 100644 client/src/modules/stock/aggregated_consumption/templates/quantity_remaining.tmpl.html diff --git a/client/src/i18n/en/stock.json b/client/src/i18n/en/stock.json index 3dc402c3af..c83101a8f4 100644 --- a/client/src/i18n/en/stock.json +++ b/client/src/i18n/en/stock.json @@ -2,6 +2,10 @@ "ALERT" : "Alert", "ADJUSTMENT" : "Adjustment", "ADJUSTMENT_TYPE" : "Adjustment Type", + "AGGREGATED_STOCK_CONSUMPTION": { + "DESCRIPTION": "This aggregated stock consumption module makes it possible to define for a warehouse and for a period the quantity of stock consumed by product but especially by batch, while specifying for each product the number of days of out of stock", + "TITLE": "Aggregate stock Consumption" + }, "AMOUNT" : "Amount", "APPROVISIONING" : "Quantity to order", "AT_LEAST_ONE_CHECKED" : "At least one option must be checked", @@ -150,6 +154,7 @@ "QUANTITY_RECEIVED" : "Received Quantity", "QUANTITY_DIFFERENCE" : "Difference", "QUANTITY_CONSUMED" : "Quantity Consumed", + "QUANTITY_IN_STOCK" : "Quantity in stock", "QUANTITY_LOST" : "Quantity Lost", "QUANTITY_REMAINING" : "Quantity Remaining", "INITIAL_QUANTITY" : "Initial Quantity", @@ -221,6 +226,7 @@ "ENABLE_STRICT_DEPOT_DISTRIBUTION_HELP_TEXT" : "Limits the depots a user can interact with to the depots that the user has access to. Thus, if a user cannot distribute stock from a depot, they also cannot transfer stock to that depot." }, "STOCK_FLUX" : { + "AGGREGATE_CONSUMPTION" : "Aggregate consumption", "FROM_PURCHASE" : "From Purchase Order", "FROM_OTHER_DEPOT" : "From Depot", "FROM_ADJUSTMENT" : "Adjustment (Positive)", diff --git a/client/src/i18n/fr/stock.json b/client/src/i18n/fr/stock.json index 48221662a2..b280fa8646 100644 --- a/client/src/i18n/fr/stock.json +++ b/client/src/i18n/fr/stock.json @@ -3,6 +3,10 @@ "ALERT" : "Alert", "ADJUSTMENT" : "Ajustement", "ADJUSTMENT_TYPE" : "Type d'Ajustement", + "AGGREGATED_STOCK_CONSUMPTION": { + "DESCRIPTION": "Ce module de consommation de stock aggregée permet de definir pour un dépôt et pour une période la quantité de stock consommée par produits mais surtout par lot, tout en précisant pour chaque produit le nombre de jour de rupture de stock", + "TITLE": "Consommation de stock aggregée" + }, "AMOUNT" : "Montant", "APPROVISIONING" : "Quantité à commander", "AT_LEAST_ONE_CHECKED" : "Au moins une option doit être coché", @@ -222,6 +226,7 @@ "ENABLE_STRICT_DEPOT_DISTRIBUTION_HELP_TEXT" : "Limite les dépôts qui peuvent recevoir du stock à partir d'un dépôt donné; lors de la sortie de stock vers un dépôt, seul les dépôts autorisés peuvent s'afficher pour le dépôt donné afin de recevoir du stock" }, "STOCK_FLUX" : { + "AGGREGATE_CONSUMPTION" : "Consommation aggregée", "FROM_PURCHASE" : "Commande d'achat", "FROM_OTHER_DEPOT" : "En provenance d'un dépôt", "FROM_ADJUSTMENT" : "Ajustement (Positif)", diff --git a/client/src/js/services/StockService.js b/client/src/js/services/StockService.js index 57b142df4f..acaecc05cb 100644 --- a/client/src/js/services/StockService.js +++ b/client/src/js/services/StockService.js @@ -66,6 +66,9 @@ function StockService(Api, StockFilterer, HttpCache, util, Periods) { // API for stock requisition const stockRequestorType = new Api('/stock/requestor_type/'); + // API for stock Aggregated Consumption + const aggregatedConsumption = new Api('/stock/aggregated_consumption'); + // Overide the stock assign api stockAssign.remove = uuid => { return stockAssign.$http.put(`/stock/assign/${uuid}/remove`) @@ -208,5 +211,6 @@ function StockService(Api, StockFilterer, HttpCache, util, Periods) { statusLabelMap, downloadTemplate, status, + aggregatedConsumption, }; } diff --git a/client/src/modules/stock/aggregated_consumption/aggregated_consumption.html b/client/src/modules/stock/aggregated_consumption/aggregated_consumption.html index 89b74a8c39..1722e8b0de 100644 --- a/client/src/modules/stock/aggregated_consumption/aggregated_consumption.html +++ b/client/src/modules/stock/aggregated_consumption/aggregated_consumption.html @@ -3,7 +3,7 @@
  1. TREE.STOCK
  2. - INVENTORY_ADJUSTMENT.TITLE + STOCK.AGGREGATED_STOCK_CONSUMPTION.TITLE
  3. {{ StockCtrl.depot.text }} @@ -31,11 +31,16 @@
    - - - + + + + +
    -

    INVENTORY_ADJUSTMENT.TITLE

    -

    INVENTORY_ADJUSTMENT.DESC

    +

    STOCK.AGGREGATED_STOCK_CONSUMPTION.TITLE

    +

    STOCK.AGGREGATED_STOCK_CONSUMPTION.DESCRIPTION

    @@ -88,7 +93,7 @@

    INVENTORY_ADJUSTMENT.TITLE

    diff --git a/client/src/modules/stock/aggregated_consumption/aggregated_consumption.js b/client/src/modules/stock/aggregated_consumption/aggregated_consumption.js index fc80582fa2..dc9c101072 100644 --- a/client/src/modules/stock/aggregated_consumption/aggregated_consumption.js +++ b/client/src/modules/stock/aggregated_consumption/aggregated_consumption.js @@ -25,9 +25,16 @@ function StockAggregatedConsumptionController( // global variables vm.Stock = new StockForm('StockInventoryAdjustment'); vm.movement = {}; + vm.stockOut = {}; - vm.onDateChange = date => { - vm.movement.date = date; + vm.onSelectFiscalYear = (fiscalYear) => { + setupStock(); + vm.movement.fiscal_id = fiscalYear.id; + }; + + vm.onSelectPeriod = (period) => { + vm.movement.date = period.end_date; + vm.movement.period_id = period.id; loadInventories(vm.depot); }; @@ -63,13 +70,13 @@ function StockAggregatedConsumptionController( headerCellFilter : 'translate', }, { field : 'label', - width : 90, + width : 120, displayName : 'TABLE.COLUMNS.LOT', headerCellFilter : 'translate', enableSorting : true, }, { field : 'old_quantity', - width : 90, + width : 120, displayName : 'STOCK.QUANTITY_IN_STOCK', headerCellFilter : 'translate', enableFiltering : false, @@ -89,14 +96,6 @@ function StockAggregatedConsumptionController( cellTemplate : 'modules/stock/aggregated_consumption/templates/quantity_lost.tmpl.html', aggregationType : uiGridConstants.aggregationTypes.sum, enableFiltering : false, - }, { - field : 'quantity_remaining', - width : 150, - displayName : 'STOCK.QUANTITY_REMAINING', - headerCellFilter : 'translate', - cellTemplate : 'modules/stock/aggregated_consumption/templates/quantity_remaining.tmpl.html', - aggregationType : uiGridConstants.aggregationTypes.sum, - enableFiltering : false, }, { field : 'days_stock_out', width : 150, @@ -123,7 +122,6 @@ function StockAggregatedConsumptionController( vm.grouping = new Grouping(vm.gridOptions, true, 'text', true, true); - // register api function onRegisterApiFn(gridApi) { vm.gridApi = gridApi; @@ -141,10 +139,6 @@ function StockAggregatedConsumptionController( } function startup() { - vm.movement = { - date : new Date(), - }; - setupStock(); } @@ -154,6 +148,8 @@ function StockAggregatedConsumptionController( }; function loadInventories(depot) { + if (!vm.movement.date) { return 0; } + vm.loading = true; setupStock(); @@ -209,6 +205,9 @@ function StockAggregatedConsumptionController( is_exit : 0, flux_id : INVENTORY_ADJUSTMENT, user_id : Session.user.id, + stock_out : vm.stockOut, + fiscal_id : vm.movement.fiscal_id, + period_id : vm.movement.period_id, }; const lots = vm.Stock.store.data.map((row) => { @@ -217,15 +216,10 @@ function StockAggregatedConsumptionController( }); movement.lots = lots.filter(lot => { - return lot.quantity !== lot.oldQuantity; + return (lot.quantity_consumed > 0 || lot.quantity_lost > 0); }); - if (!movement.lots.length) { - Notify.warn('INVENTORY_ADJUSTMENT.NO_CHANGE'); - return 0; - } - - return Stock.inventoryAdjustment.create(movement) + return Stock.aggregatedConsumption.create(movement) .then(() => { // since we have effectively performed an inventory, instead of rendering a receipt, // we will render the "Articles in Stock" report for this depot. diff --git a/client/src/modules/stock/aggregated_consumption/templates/days_stock_out.tmpl.html b/client/src/modules/stock/aggregated_consumption/templates/days_stock_out.tmpl.html index e94c4bb69e..e9df38692b 100644 --- a/client/src/modules/stock/aggregated_consumption/templates/days_stock_out.tmpl.html +++ b/client/src/modules/stock/aggregated_consumption/templates/days_stock_out.tmpl.html @@ -6,6 +6,5 @@ type="number" class="form-control" style="padding-left : 5px !important;text-align: right;" - ng-model="row.entity.days_stock_out" - ng-change="row.entity.valdiate()" required> + ng-model="grid.appScope.stockOut[row.treeNode.children[0].row.entity.inventory_uuid]" required>
    diff --git a/client/src/modules/stock/aggregated_consumption/templates/quantity_remaining.tmpl.html b/client/src/modules/stock/aggregated_consumption/templates/quantity_remaining.tmpl.html deleted file mode 100644 index fc0f5376f0..0000000000 --- a/client/src/modules/stock/aggregated_consumption/templates/quantity_remaining.tmpl.html +++ /dev/null @@ -1,11 +0,0 @@ -
    - -
    diff --git a/client/src/modules/stock/inventory-adjustment/inventory-adjustment.js b/client/src/modules/stock/inventory-adjustment/inventory-adjustment.js index 6ab1200cae..79b0362bf3 100644 --- a/client/src/modules/stock/inventory-adjustment/inventory-adjustment.js +++ b/client/src/modules/stock/inventory-adjustment/inventory-adjustment.js @@ -25,6 +25,7 @@ function StockInventoryAdjustmentController( // global variables vm.Stock = new StockForm('StockInventoryAdjustment'); vm.movement = {}; + vm.stockOut = {}; vm.onDateChange = date => { vm.movement.date = date; diff --git a/server/config/routes.js b/server/config/routes.js index 9b2ae2401d..c97dbc48b1 100644 --- a/server/config/routes.js +++ b/server/config/routes.js @@ -824,6 +824,7 @@ exports.configure = function configure(app) { // stock integration app.post('/stock/integration', stock.createIntegration); app.post('/stock/inventory_adjustment', stock.createInventoryAdjustment); + app.post('/stock/aggregated_consumption', stock.createAggregatedConsumption); // stock settings API app.get('/stock/setting/:id?', stockSetting.list); diff --git a/server/controllers/stock/core.js b/server/controllers/stock/core.js index 9f69d8ae13..d79bde65a5 100644 --- a/server/controllers/stock/core.js +++ b/server/controllers/stock/core.js @@ -33,6 +33,7 @@ const flux = { FROM_INTEGRATION : 13, INVENTORY_RESET : 14, INVENTORY_ADJUSTMENT : 15, + AGGREGATE_CONSUMPTION : 16, }; // exports diff --git a/server/controllers/stock/index.js b/server/controllers/stock/index.js index 2d91cbf071..46c72fe1f3 100644 --- a/server/controllers/stock/index.js +++ b/server/controllers/stock/index.js @@ -39,6 +39,7 @@ exports.assign = assign; exports.requisition = requisition; exports.requestorType = requestorType; exports.createInventoryAdjustment = createInventoryAdjustment; +exports.createAggregatedConsumption = createAggregatedConsumption; exports.listStatus = core.listStatus; // stock consumption @@ -975,3 +976,104 @@ function getStockTransfers(req, res, next) { .catch(next) .done(); } + + +/** + * POST /stock/aggregated_consumption + * Stock Aggregated Consumption + */ +async function createAggregatedConsumption(req, res, next) { + try { + const movement = req.body; + + console.log('NEWWWWWW'); + console.log(movement); + + if (!movement.depot_uuid) { + throw new Error('No defined depot'); + } + + // only consider lots that have consumed or lost. + const lots = movement.lots + .filter(l => (l.quantity_consumed > 0 || l.quantity_lost > 0)); + + const periodId = movement.period_id; + + // pass reverse operations + const trx = db.transaction(); + + const consumptionUuid = uuid(); + const lossUuid = uuid(); + + // get all lots with positive quantity_consumed + const stockConsumptionQuantities = lots.filter(lot => lot.quantity_consumed > 0); + + // get all lots with negative quantity_lost + const stockLossQuantities = lots.filter(lot => lot.quantity_lost > 0); + + stockConsumptionQuantities.forEach(lot => { + const consumptionMovementObject = { + uuid : db.bid(uuid()), + lot_uuid : db.bid(lot.uuid), + depot_uuid : db.bid(movement.depot_uuid), + document_uuid : db.bid(consumptionUuid), + quantity : lot.quantity_consumed, + unit_cost : lot.unit_cost, + date : new Date(movement.date), + entity_uuid : movement.entity_uuid, + is_exit : 1, + flux_id : core.flux.AGGREGATE_CONSUMPTION, + description : movement.description, + user_id : req.session.user.id, + period_id : periodId, + }; + trx.addQuery('INSERT INTO stock_movement SET ?', consumptionMovementObject); + }); + + stockLossQuantities.forEach(lot => { + const lossMovementObject = { + uuid : db.bid(uuid()), + lot_uuid : db.bid(lot.uuid), + depot_uuid : db.bid(movement.depot_uuid), + document_uuid : db.bid(consumptionUuid), + quantity : lot.quantity_lost, + unit_cost : lot.unit_cost, + date : new Date(movement.date), + entity_uuid : movement.entity_uuid, + is_exit : 1, + flux_id : core.flux.TO_LOSS, + description : movement.description, + user_id : req.session.user.id, + period_id : periodId, + }; + trx.addQuery('INSERT INTO stock_movement SET ?', lossMovementObject); + }); + + const stockConsumptionParams = [ + db.bid(consumptionUuid), 1, req.session.project.id, req.session.enterprise.currency_id, + ]; + + const stockLossParams = [ + db.bid(lossUuid), 1, req.session.project.id, req.session.enterprise.currency_id, + ]; + + if (req.session.stock_settings.enable_auto_stock_accounting) { + if (stockConsumptionQuantities.length > 0) { + trx.addQuery('CALL PostStockMovement(?)', [stockConsumptionParams]); + } + + if (stockLossQuantities.length > 0) { + trx.addQuery('CALL PostStockMovement(?)', [stockLossParams]); + } + } + + console.log('ICI NOUS SOMMMES : NA ZO MEKA MAIS NA ZO KOMA TE'); + + await trx.execute(); + + res.status(201).json({}); + } catch (err) { + next(err); + } +} + diff --git a/server/models/bhima.sql b/server/models/bhima.sql index 653288508d..d80c2cc857 100644 --- a/server/models/bhima.sql +++ b/server/models/bhima.sql @@ -324,7 +324,8 @@ INSERT INTO `flux` VALUES (12, 'STOCK_FLUX.TO_ADJUSTMENT'), (13, 'STOCK_FLUX.FROM_INTEGRATION'), (14, 'STOCK_FLUX.INVENTORY_RESET'), - (15, 'STOCK_FLUX.INVENTORY_ADJUSTMENT'); + (15, 'STOCK_FLUX.INVENTORY_ADJUSTMENT'), + (16, 'STOCK_FLUX.AGGREGATE_CONSUMPTION'); -- Roles Actions