diff --git a/client/src/modules/stock/lots/registry.js b/client/src/modules/stock/lots/registry.js index b98067695e..8e20657787 100644 --- a/client/src/modules/stock/lots/registry.js +++ b/client/src/modules/stock/lots/registry.js @@ -124,9 +124,10 @@ function StockLotsController(Stock, Notify, if($state.params.filters) { var changes = [{ key : $state.params.filters.key, value : $state.params.filters.value }] - stockLotFilters.replaceFilters(changes); + stockLotFilters.replaceFilters(changes); Stock.cacheFilters(filterKey); } + load(stockLotFilters.formatHTTP(true)); vm.latestViewFilters = stockLotFilters.formatView(); } @@ -160,14 +161,14 @@ function StockLotsController(Stock, Notify, toggleLoadingIndicator(); Stock.lots.read(null, filters) - .then(function(lots){ - vm.gridOptions.data = lots; - vm.grouping.unfoldAllGroups(); - }) - .catch(errorHandler) - .finally(function (){ - toggleLoadingIndicator(); - }); + .then(function (lots) { + vm.gridOptions.data = lots; + vm.grouping.unfoldAllGroups(); + }) + .catch(errorHandler) + .finally(function (){ + toggleLoadingIndicator(); + }); } // remove a filter with from the filter object, save the filters and reload diff --git a/client/src/modules/stock/movements/modals/search.modal.html b/client/src/modules/stock/movements/modals/search.modal.html index 141b028010..a3380ea461 100644 --- a/client/src/modules/stock/movements/modals/search.modal.html +++ b/client/src/modules/stock/movements/modals/search.modal.html @@ -20,13 +20,13 @@
@@ -59,27 +59,16 @@
- + {{$select.selected.label}} - +
- - -
- FORM.LABELS.DATE - - -
@@ -91,7 +80,7 @@
-
- + diff --git a/client/src/modules/stock/movements/modals/search.modal.js b/client/src/modules/stock/movements/modals/search.modal.js index 4b2d88b623..a315fabcf1 100644 --- a/client/src/modules/stock/movements/modals/search.modal.js +++ b/client/src/modules/stock/movements/modals/search.modal.js @@ -1,32 +1,32 @@ angular.module('bhima.controllers') -.controller('SearchMovementsModalController', SearchMovementsModalController); + .controller('SearchMovementsModalController', SearchMovementsModalController); SearchMovementsModalController.$inject = [ - 'data', 'NotifyService', '$uibModalInstance', 'FluxService', - '$translate', 'PeriodService', 'Store', 'util' + 'data', 'NotifyService', '$uibModalInstance', 'FluxService', + '$translate', 'PeriodService', 'Store', 'util', ]; function SearchMovementsModalController(data, Notify, Instance, Flux, $translate, Periods, Store, util) { var vm = this; - var changes = new Store({ identifier : 'key'}); + var changes = new Store({ identifier : 'key' }); + + var searchQueryOptions = [ + 'is_exit', 'depot_uuid', 'inventory_uuid', 'label', 'flux_id', 'dateFrom', 'dateTo', + ]; vm.filters = data; vm.searchQueries = {}; vm.defaultQueries = {}; - var searchQueryOptions = [ - 'is_exit', 'depot_uuid', 'inventory_uuid', 'label', 'flux_id', 'dateFrom', 'dateTo' - ]; - - // load flux + // load flux Flux.read() - .then(function (rows) { + .then(function (rows) { vm.fluxes = rows.map(function (row) { row.label = $translate.instant(row.label); return row; }); - }) - .catch(Notify.handleError); + }) + .catch(Notify.handleError); // default filter period - directly write to changes list vm.onSelectPeriod = function onSelectPeriod(period) { @@ -50,7 +50,7 @@ function SearchMovementsModalController(data, Notify, Instance, Flux, $translate // assign already defined custom filters to searchQueries object vm.searchQueries = util.maskObjectFromKeys(data, searchQueryOptions); - if(data.limit) { + if (data.limit) { vm.defaultQueries.limit = data.limit; } @@ -58,11 +58,11 @@ function SearchMovementsModalController(data, Notify, Instance, Flux, $translate vm.onSelectLimit = function onSelectLimit(value) { // input is type value, this will only be defined for a valid number if (angular.isDefined(value)) { - changes.post({ key: 'limit', value: value }); + changes.post({ key : 'limit', value : value }); } }; - // deletes a filter from the custom filter object, + // deletes a filter from the custom filter object, // this key will no longer be written to changes on exit vm.clear = function clear(key) { delete vm.searchQueries[key]; @@ -70,16 +70,16 @@ function SearchMovementsModalController(data, Notify, Instance, Flux, $translate vm.cancel = function cancel() { Instance.close(); }; - vm.submit = function submit(form) { + vm.submit = function submit() { // push all searchQuery values into the changes array to be applied angular.forEach(vm.searchQueries, function (value, key) { if (angular.isDefined(value)) { - changes.post({ key: key, value: value }); + changes.post({ key : key, value : value }); } }); var loggedChanges = changes.getAll(); - + return Instance.close(loggedChanges); }; } diff --git a/client/src/modules/stock/movements/registry.js b/client/src/modules/stock/movements/registry.js index 9287acec7a..b44cd9353b 100644 --- a/client/src/modules/stock/movements/registry.js +++ b/client/src/modules/stock/movements/registry.js @@ -4,7 +4,7 @@ angular.module('bhima.controllers') StockMovementsController.$inject = [ 'StockService', 'NotifyService', 'uiGridConstants', '$translate', 'StockModalService', 'LanguageService', 'SessionService', 'FluxService', - 'ReceiptModal', 'GridGroupingService', '$state', 'GridColumnService', 'GridStateService' + 'ReceiptModal', 'GridGroupingService', '$state', 'GridColumnService', 'GridStateService', ]; /** @@ -21,129 +21,114 @@ function StockMovementsController(Stock, Notify, var state; var gridColumns; - vm.gridApi = {}; - // bind flux id with receipt var mapFlux = { - 1: { receipt: ReceiptModal.stockEntryPurchaseReceipt }, - 2: { receipt: ReceiptModal.stockEntryDepotReceipt }, - 3: { receipt: ReceiptModal.stockAdjustmentReceipt }, - 8: { receipt: ReceiptModal.stockExitDepotReceipt }, - 9: { receipt: ReceiptModal.stockExitPatientReceipt }, - 10: { receipt: ReceiptModal.stockExitServiceReceipt }, - 11: { receipt: ReceiptModal.stockExitLossReceipt }, - 12: { receipt: ReceiptModal.stockAdjustmentReceipt }, - 13: { receipt: ReceiptModal.stockEntryIntegrationReceipt }, + 1 : { receipt : ReceiptModal.stockEntryPurchaseReceipt }, + 2 : { receipt : ReceiptModal.stockEntryDepotReceipt }, + 3 : { receipt : ReceiptModal.stockAdjustmentReceipt }, + 8 : { receipt : ReceiptModal.stockExitDepotReceipt }, + 9 : { receipt : ReceiptModal.stockExitPatientReceipt }, + 10 : { receipt : ReceiptModal.stockExitServiceReceipt }, + 11 : { receipt : ReceiptModal.stockExitLossReceipt }, + 12 : { receipt : ReceiptModal.stockAdjustmentReceipt }, + 13 : { receipt : ReceiptModal.stockEntryIntegrationReceipt }, }; // grouping box vm.groupingBox = [ - { label: 'STOCK.INVENTORY', value: 'text' }, - { label: 'STOCK.IO', value: 'io' }, - { label: 'STOCK.LOT', value: 'label' }, + { label : 'STOCK.INVENTORY', value : 'text' }, + { label : 'STOCK.IO', value : 'io' }, + { label : 'STOCK.LOT', value : 'label' }, ]; + vm.gridApi = {}; + // global variables vm.enterprise = Session.enterprise; // grid columns - var columns = [ - { - field: 'depot_text', - displayName: 'STOCK.DEPOT', - headerCellFilter: 'translate', - aggregationType: uiGridConstants.aggregationTypes.count - }, - - { - field: 'io', - displayName: 'STOCK.IO', - headerCellFilter: 'translate', - cellTemplate: 'modules/stock/movements/templates/io.cell.html' - }, - - { - field: 'text', - displayName: 'STOCK.INVENTORY', - headerCellFilter: 'translate' - }, - - { - field: 'label', - displayName: 'STOCK.LOT', - headerCellFilter: 'translate' - }, - - { - field: 'quantity', - displayName: 'STOCK.QUANTITY', - headerCellFilter: 'translate', - aggregationType: uiGridConstants.aggregationTypes.sum, - cellClass: 'text-right', - footerCellClass: 'text-right' - }, - - { - field: 'unit_type', - width: 75, - displayName: 'TABLE.COLUMNS.UNIT', - headerCellFilter: 'translate', - cellTemplate: 'modules/stock/inventories/templates/unit.tmpl.html' - }, - - { - field: 'unit_cost', - displayName: 'STOCK.UNIT_COST', - headerCellFilter: 'translate', - cellFilter: 'currency:grid.appScope.enterprise.currency_id', - cellClass: 'text-right' - }, - - { - field: 'cost', - displayName: 'STOCK.COST', - headerCellFilter: 'translate', - aggregationType: totalCost, - cellClass: 'text-right', - cellTemplate: 'modules/stock/movements/templates/cost.cell.html', - footerCellFilter: 'currency:grid.appScope.enterprise.currency_id', - footerCellClass: 'text-right' - }, - - { - field: 'date', - displayName: 'FORM.LABELS.DATE', - headerCellFilter: 'translate', - cellFilter: 'date', - cellClass: 'text-right' - }, - - { - field: 'flux_id', - displayName: 'STOCK.FLUX', - headerCellFilter: 'translate', - cellTemplate: 'modules/stock/movements/templates/flux.cell.html' - }, - - { - field: 'action', - displayName: '', - enableFiltering: false, - enableSorting: false, - cellTemplate: 'modules/stock/movements/templates/action.cell.html' - }, - ]; + var columns = [{ + field : 'depot_text', + displayName : 'STOCK.DEPOT', + headerCellFilter : 'translate', + aggregationType : uiGridConstants.aggregationTypes.count, + aggregationHideLabel : true, + }, { + field : 'io', + displayName : 'STOCK.IO', + headerCellFilter : 'translate', + cellTemplate : 'modules/stock/movements/templates/io.cell.html', + }, { + field : 'text', + displayName : 'STOCK.INVENTORY', + headerCellFilter : 'translate', + }, { + field : 'label', + displayName : 'STOCK.LOT', + headerCellFilter : 'translate', + }, { + field : 'quantity', + type: 'number', + displayName : 'STOCK.QUANTITY', + headerCellFilter : 'translate', + aggregationType : uiGridConstants.aggregationTypes.sum, + aggregationHideLabel : true, + cellClass : 'text-right', + footerCellClass : 'text-right', + }, { + field : 'unit_type', + width : 75, + displayName : 'TABLE.COLUMNS.UNIT', + headerCellFilter : 'translate', + cellTemplate : 'modules/stock/inventories/templates/unit.tmpl.html', + }, { + field : 'unit_cost', + type : 'number', + displayName : 'STOCK.UNIT_COST', + headerCellFilter : 'translate', + cellFilter : 'currency:grid.appScope.enterprise.currency_id', + cellClass : 'text-right', + }, { + field : 'cost', + type : 'number', + displayName : 'STOCK.COST', + headerCellFilter : 'translate', + aggregationType : totalCost, + aggregationHideLabel : true, + cellFilter : 'currency:grid.appScope.enterprise.currency_id', + cellClass : 'text-right', + footerCellFilter : 'currency:grid.appScope.enterprise.currency_id', + footerCellClass : 'text-right', + }, { + field : 'date', + type: 'date', + displayName : 'FORM.LABELS.DATE', + headerCellFilter : 'translate', + cellFilter : 'date', + cellClass : 'text-right', + }, { + field : 'flux_id', + displayName : 'STOCK.FLUX', + headerCellFilter : 'translate', + cellTemplate : 'modules/stock/movements/templates/flux.cell.html', + }, { + field : 'action', + displayName : '', + enableFiltering : false, + enableSorting : false, + cellTemplate : 'modules/stock/movements/templates/action.cell.html', + }]; // options for the UI grid vm.gridOptions = { - appScopeProvider: vm, - enableColumnMenus: false, - columnDefs: columns, - enableSorting: true, - showColumnFooter: true, - onRegisterApi: onRegisterApi, - fastWatch: true, - flatEntityAccess: true, + appScopeProvider : vm, + enableColumnMenus : false, + columnDefs : columns, + enableSorting : true, + showColumnFooter : true, + onRegisterApi : onRegisterApi, + fastWatch : true, + flatEntityAccess : true, }; vm.grouping = new Grouping(vm.gridOptions, true, 'depot_text', vm.grouped, true); @@ -215,35 +200,41 @@ function StockMovementsController(Stock, Notify, // column configuration has direct access to the grid API to alter the current // state of the columns - this will be saved if the user saves the grid configuration gridColumns.openConfigurationModal(); - }; + } vm.saveGridState = state.saveGridState; function clearGridState() { state.clearGridState(); $state.reload(); - }; + } // load stock lots in the grid function load(filters) { vm.hasError = false; vm.loading = true; - Stock.movements.read(null, filters).then(function (rows) { - // set flux name - rows.forEach(function (row) { - row.fluxName = getFluxName(row.flux_id); - }); + Stock.movements.read(null, filters) + .then(function (rows) { + // preprocess data + rows.forEach(function (row) { + + // compute the fluxName from its ID + row.fluxName = getFluxName(row.flux_id); - vm.gridOptions.data = rows; + // compute the row cost + row.cost = row.quantity * row.unit_cost; + }); - // force expand grid - vm.grouping.unfoldAllGroups(); - }) - .catch(Notify.handleError) - .finally(function () { - vm.loading = false; - }); + vm.gridOptions.data = rows; + + // force expand grid + vm.grouping.unfoldAllGroups(); + }) + .catch(Notify.handleError) + .finally(function () { + vm.loading = false; + }); } // search modal @@ -267,10 +258,9 @@ function StockMovementsController(Stock, Notify, // initialize module function startup() { - - if($state.params.filters) { + if ($state.params.filters) { var changes = [{ key : $state.params.filters.key, value : $state.params.filters.value }] - stockMovementFilters.replaceFilters(changes); + stockMovementFilters.replaceFilters(changes); Stock.cacheFilters(filterKey); } diff --git a/client/src/modules/stock/movements/templates/action.cell.html b/client/src/modules/stock/movements/templates/action.cell.html index 3f0b325641..f8b0085976 100644 --- a/client/src/modules/stock/movements/templates/action.cell.html +++ b/client/src/modules/stock/movements/templates/action.cell.html @@ -1,4 +1,4 @@ -
+
FORM.BUTTONS.ACTIONS diff --git a/client/src/modules/stock/movements/templates/cost.cell.html b/client/src/modules/stock/movements/templates/cost.cell.html deleted file mode 100644 index e8e5b1f820..0000000000 --- a/client/src/modules/stock/movements/templates/cost.cell.html +++ /dev/null @@ -1,3 +0,0 @@ -
- {{ row.entity.unit_cost * row.entity.quantity | currency: grid.appScope.enterprise.currency_id }} -
\ No newline at end of file diff --git a/server/config/routes.js b/server/config/routes.js index 2ed580ffc1..e921671fc2 100644 --- a/server/config/routes.js +++ b/server/config/routes.js @@ -42,7 +42,7 @@ const snis = require('../controllers/medical/snis'); const medicalReports = require('../controllers/medical/reports'); const diagnoses = require('../controllers/medical/diagnoses'); -// humaine ressource route +// human resources routes const employees = require('../controllers/payroll/employees'); const employeeReports = require('../controllers/payroll/reports'); @@ -175,12 +175,12 @@ exports.configure = function configure(app) { // API for journal app.get('/journal', journal.list); app.get('/journal/count', journal.count); - + app.get('/journal/:record_uuid', journal.getTransaction); app.post('/journal/:record_uuid/edit', journal.editTransaction); app.post('/journal/:uuid/reverse', journal.reverse); - + // API for general ledger app.get('/general_ledger', generalLedger.list); @@ -318,7 +318,7 @@ exports.configure = function configure(app) { // interface for linking entities, it renders a report for a particular entity app.get('/refenceLookup/:codeRef/:language', refenceLookup.getEntity); - + // interface for employee report app.get('/reports/payroll/employees', employeeReports.employeeRegistrations); diff --git a/server/controllers/stock/core.js b/server/controllers/stock/core.js index dbbff7279d..5301fc2a0e 100644 --- a/server/controllers/stock/core.js +++ b/server/controllers/stock/core.js @@ -8,7 +8,7 @@ * @requires lib/db * @requires lib/filter * @requires config/identifiers - **/ + */ const moment = require('moment'); const db = require('../../lib/db'); @@ -54,24 +54,27 @@ exports.getInventoryMovements = getInventoryMovements; * @description returns a list of lots * * @param {string} sql - An optional sql script of selecting in lot - * @param {object} params - A request query object - * @param {string} finalClause - An optional final clause (GROUP BY, HAVING, ...) to add to query built + * @param {object} parameters - A request query object + * @param {string} finalClauseParameter - An optional final clause (GROUP BY, HAVING, ...) to add to query built */ function getLots(sqlQuery, parameters, finalClauseParameter) { const finalClause = finalClauseParameter; - const params = parameters; + const params = parameters; const sql = sqlQuery || ` - SELECT - BUID(l.uuid) AS uuid, l.label, l.initial_quantity, l.unit_cost, BUID(l.origin_uuid) AS origin_uuid, - l.expiration_date, BUID(l.inventory_uuid) AS inventory_uuid, i.delay, l.entry_date, - i.code, i.text, BUID(m.depot_uuid) AS depot_uuid, d.text AS depot_text, iu.text AS unit_type - FROM lot l - JOIN inventory i ON i.uuid = l.inventory_uuid - JOIN inventory_unit iu ON iu.id = i.unit_id - JOIN stock_movement m ON m.lot_uuid = l.uuid AND m.flux_id = ${flux.FROM_PURCHASE} - JOIN depot d ON d.uuid = m.depot_uuid - `; + SELECT + BUID(l.uuid) AS uuid, l.label, l.initial_quantity, l.unit_cost, BUID(l.origin_uuid) AS origin_uuid, + l.expiration_date, BUID(l.inventory_uuid) AS inventory_uuid, i.delay, l.entry_date, + i.code, i.text, BUID(m.depot_uuid) AS depot_uuid, d.text AS depot_text, iu.text AS unit_type + FROM lot l + JOIN inventory i ON i.uuid = l.inventory_uuid + JOIN inventory_unit iu ON iu.id = i.unit_id + JOIN stock_movement m ON m.lot_uuid = l.uuid AND m.flux_id = ${flux.FROM_PURCHASE} + JOIN depot d ON d.uuid = m.depot_uuid +`; + + // make sure all uuids are properly converted to binary db.convert(params, ['uuid', 'depot_uuid', 'lot_uuid', 'inventory_uuid', 'document_uuid', 'entity_uuid']); + const filters = new FilterParser(params, { autoParseStatements : false }); filters.equals('uuid', 'uuid', 'l'); @@ -84,6 +87,7 @@ function getLots(sqlQuery, parameters, finalClauseParameter) { filters.equals('text', 'text', 'i'); filters.equals('label', 'label', 'l'); filters.equals('is_exit', 'is_exit', 'm'); + filters.equals('flux_id', 'flux_id', 'm'); filters.period('defaultPeriod', 'date'); filters.period('defaultPeriodEntry', 'entry_date', 'l'); @@ -92,13 +96,14 @@ function getLots(sqlQuery, parameters, finalClauseParameter) { filters.dateFrom('expiration_date_from', 'expiration_date', 'l'); filters.dateTo('expiration_date_to', 'expiration_date', 'l'); + filters.dateFrom('entry_date_from', 'entry_date', 'l'); filters.dateTo('entry_date_to', 'entry_date', 'l'); filters.dateFrom('dateFrom', 'date', 'm'); filters.dateTo('dateTo', 'date', 'm'); - // If finalClause is an empty string, filterParser will not group, it will be an empty string + // if finalClause is an empty string, filterParser will not group, it will be an empty string filters.setGroup(finalClause || ''); const query = filters.applyQuery(sql); @@ -131,38 +136,38 @@ function getLotsDepot(depotUuid, params, finalClause) { delete params.status; } - if(Number(params.includeEmptyLot) === 0){ + if (Number(params.includeEmptyLot) === 0) { exludeToken = 'HAVING quantity > 0'; delete params.includeEmptyLot; } const sql = ` - SELECT BUID(l.uuid) AS uuid, l.label, l.initial_quantity, - SUM(m.quantity * IF(m.is_exit = 1, -1, 1)) AS quantity, - d.text AS depot_text, l.unit_cost, l.expiration_date, - BUID(l.inventory_uuid) AS inventory_uuid, BUID(l.origin_uuid) AS origin_uuid, + SELECT BUID(l.uuid) AS uuid, l.label, l.initial_quantity, + SUM(m.quantity * IF(m.is_exit = 1, -1, 1)) AS quantity, + d.text AS depot_text, l.unit_cost, l.expiration_date, + BUID(l.inventory_uuid) AS inventory_uuid, BUID(l.origin_uuid) AS origin_uuid, l.entry_date, i.code, i.text, BUID(m.depot_uuid) AS depot_uuid, i.avg_consumption, i.purchase_interval, i.delay, iu.text AS unit_type - FROM stock_movement m + FROM stock_movement m JOIN lot l ON l.uuid = m.lot_uuid JOIN inventory i ON i.uuid = l.inventory_uuid - JOIN inventory_unit iu ON iu.id = i.unit_id - JOIN depot d ON d.uuid = m.depot_uuid + JOIN inventory_unit iu ON iu.id = i.unit_id + JOIN depot d ON d.uuid = m.depot_uuid `; const clause = finalClause || ` GROUP BY l.uuid, m.depot_uuid ${exludeToken}`; return getLots(sql, params, clause) - .then(stockManagementProcess) - .then((rows) => { - if (status) { - return rows.filter((row) => { - return row.status === status; - }); - } - return rows; + .then(stockManagementProcess) + .then((rows) => { + if (status) { + return rows.filter((row) => { + return row.status === status; }); + } + return rows; + }); } /** @@ -181,27 +186,27 @@ function getLotsMovements(depotUuid, params) { params.depot_uuid = depotUuid; } - if(params.groupByDocument === 1){ + if (params.groupByDocument === 1) { finalClause = 'GROUP BY document_uuid'; delete params.groupByDocument; } const sql = ` - SELECT - BUID(l.uuid) AS uuid, l.label, l.initial_quantity, m.quantity, m.reference, m.description, - d.text AS depot_text, IF(is_exit = 1, "OUT", "IN") AS io, l.unit_cost, - l.expiration_date, BUID(l.inventory_uuid) AS inventory_uuid, - BUID(l.origin_uuid) AS origin_uuid, l.entry_date, i.code, i.text, - BUID(m.depot_uuid) AS depot_uuid, m.is_exit, m.date, BUID(m.document_uuid) AS document_uuid, - m.flux_id, BUID(m.entity_uuid) AS entity_uuid, m.unit_cost, - f.label AS flux_label, i.delay, - iu.text AS unit_type - FROM stock_movement m - JOIN lot l ON l.uuid = m.lot_uuid - JOIN inventory i ON i.uuid = l.inventory_uuid - JOIN inventory_unit iu ON iu.id = i.unit_id - JOIN depot d ON d.uuid = m.depot_uuid - JOIN flux f ON f.id = m.flux_id + SELECT + BUID(l.uuid) AS uuid, l.label, l.initial_quantity, m.quantity, m.reference, m.description, + d.text AS depot_text, IF(is_exit = 1, "OUT", "IN") AS io, l.unit_cost, + l.expiration_date, BUID(l.inventory_uuid) AS inventory_uuid, + BUID(l.origin_uuid) AS origin_uuid, l.entry_date, i.code, i.text, + BUID(m.depot_uuid) AS depot_uuid, m.is_exit, m.date, BUID(m.document_uuid) AS document_uuid, + m.flux_id, BUID(m.entity_uuid) AS entity_uuid, m.unit_cost, + f.label AS flux_label, i.delay, + iu.text AS unit_type + FROM stock_movement m + JOIN lot l ON l.uuid = m.lot_uuid + JOIN inventory i ON i.uuid = l.inventory_uuid + JOIN inventory_unit iu ON iu.id = i.unit_id + JOIN depot d ON d.uuid = m.depot_uuid + JOIN flux f ON f.id = m.flux_id `; return getLots(sql, params, finalClause); @@ -222,34 +227,34 @@ function getLotsOrigins(depotUuid, params) { } const sql = ` - SELECT BUID(l.uuid) AS uuid, l.label, l.unit_cost, l.expiration_date, - BUID(l.inventory_uuid) AS inventory_uuid, BUID(l.origin_uuid) AS origin_uuid, - l.entry_date, i.code, i.text, origin.display_name, origin.reference, + SELECT BUID(l.uuid) AS uuid, l.label, l.unit_cost, l.expiration_date, + BUID(l.inventory_uuid) AS inventory_uuid, BUID(l.origin_uuid) AS origin_uuid, + l.entry_date, i.code, i.text, origin.display_name, origin.reference, BUID(m.document_uuid) AS document_uuid, m.flux_id, iu.text AS unit_type - FROM lot l - JOIN inventory i ON i.uuid = l.inventory_uuid - JOIN inventory_unit iu ON iu.id = i.unit_id + FROM lot l + JOIN inventory i ON i.uuid = l.inventory_uuid + JOIN inventory_unit iu ON iu.id = i.unit_id JOIN ( - SELECT + SELECT p.uuid, CONCAT_WS('.', '${identifiers.PURCHASE_ORDER.key}', proj.abbr, p.reference) AS reference, 'STOCK.PURCHASE_ORDER' AS display_name - FROM + FROM purchase p JOIN project proj ON proj.id = p.project_id - UNION - SELECT + UNION + SELECT d.uuid, CONCAT_WS('.', '${identifiers.DONATION.key}', proj.abbr, d.reference) AS reference, - 'STOCK.DONATION' AS display_name - FROM + 'STOCK.DONATION' AS display_name + FROM donation d JOIN project proj ON proj.id = d.project_id - UNION - SELECT + UNION + SELECT i.uuid, CONCAT_WS('.', '${identifiers.INTEGRATION.key}', proj.abbr, i.reference) AS reference, - 'STOCK.INTEGRATION' AS display_name - FROM - integration i JOIN project proj ON proj.id = i.project_id - ) AS origin ON origin.uuid = l.origin_uuid - JOIN stock_movement m ON m.lot_uuid = l.uuid AND m.is_exit = 0 + 'STOCK.INTEGRATION' AS display_name + FROM + integration i JOIN project proj ON proj.id = i.project_id + ) AS origin ON origin.uuid = l.origin_uuid + JOIN stock_movement m ON m.lot_uuid = l.uuid AND m.is_exit = 0 AND m.flux_id IN (${flux.FROM_PURCHASE}, ${flux.FROM_DONATION}, ${flux.FROM_INTEGRATION}) `; @@ -310,10 +315,10 @@ function getStockConsumption(periodIds) { const sql = ` SELECT SUM(s.quantity) AS quantity, BUID(i.uuid) AS uuid, i.text, i.code, d.text FROM stock_consumption s - JOIN inventory i ON i.uuid = s.inventory_uuid + JOIN inventory i ON i.uuid = s.inventory_uuid JOIN depot d ON d.uuid = s.depot_uuid JOIN period p ON p.id = s.period_id - WHERE p.id IN (?) + WHERE p.id IN (?) GROUP BY i.uuid, d.uuid `; return db.exec(sql, [periodIds]); @@ -344,12 +349,13 @@ function getStockConsumptionAverage(periodId, periodDate, numberOfMonths) { 'SELECT id FROM period WHERE DATE(?) BETWEEN DATE(start_date) AND DATE(end_date) LIMIT 1;'; const queryStockConsumption = ` - SELECT ROUND(AVG(s.quantity)) AS quantity, BUID(i.uuid) AS uuid, i.text, i.code, BUID(d.uuid) AS depot_uuid, d.text AS depot_text + SELECT ROUND(AVG(s.quantity)) AS quantity, BUID(i.uuid) AS uuid, i.text, i.code, BUID(d.uuid) AS depot_uuid, + d.text AS depot_text FROM stock_consumption s - JOIN inventory i ON i.uuid = s.inventory_uuid + JOIN inventory i ON i.uuid = s.inventory_uuid JOIN depot d ON d.uuid = s.depot_uuid JOIN period p ON p.id = s.period_id - WHERE p.id IN (?) + WHERE p.id IN (?) GROUP BY i.uuid, d.uuid `; @@ -391,18 +397,18 @@ function getInventoryQuantityAndConsumption(params) { } const sql = ` - SELECT BUID(l.uuid) AS uuid, l.label, l.initial_quantity, - SUM(m.quantity * IF(m.is_exit = 1, -1, 1)) AS quantity, - d.text AS depot_text, l.unit_cost, l.expiration_date, - BUID(l.inventory_uuid) AS inventory_uuid, BUID(l.origin_uuid) AS origin_uuid, + SELECT BUID(l.uuid) AS uuid, l.label, l.initial_quantity, + SUM(m.quantity * IF(m.is_exit = 1, -1, 1)) AS quantity, + d.text AS depot_text, l.unit_cost, l.expiration_date, + BUID(l.inventory_uuid) AS inventory_uuid, BUID(l.origin_uuid) AS origin_uuid, l.entry_date, i.code, i.text, BUID(m.depot_uuid) AS depot_uuid, i.avg_consumption, i.purchase_interval, i.delay, iu.text AS unit_type - FROM stock_movement m + FROM stock_movement m JOIN lot l ON l.uuid = m.lot_uuid JOIN inventory i ON i.uuid = l.inventory_uuid - JOIN inventory_unit iu ON iu.id = i.unit_id - JOIN depot d ON d.uuid = m.depot_uuid + JOIN inventory_unit iu ON iu.id = i.unit_id + JOIN depot d ON d.uuid = m.depot_uuid `; const clause = ' GROUP BY l.inventory_uuid, m.depot_uuid '; @@ -450,14 +456,14 @@ function getInventoryMovements(params) { SELECT BUID(l.uuid) AS uuid, l.label, l.initial_quantity, d.text AS depot_text, l.unit_cost, l.expiration_date, m.quantity, m.is_exit, m.date, - BUID(l.inventory_uuid) AS inventory_uuid, BUID(l.origin_uuid) AS origin_uuid, + BUID(l.inventory_uuid) AS inventory_uuid, BUID(l.origin_uuid) AS origin_uuid, l.entry_date, i.code, i.text, BUID(m.depot_uuid) AS depot_uuid, i.avg_consumption, i.purchase_interval, i.delay, iu.text AS unit_type - FROM stock_movement m + FROM stock_movement m JOIN lot l ON l.uuid = m.lot_uuid JOIN inventory i ON i.uuid = l.inventory_uuid - JOIN inventory_unit iu ON iu.id = i.unit_id - JOIN depot d ON d.uuid = m.depot_uuid + JOIN inventory_unit iu ON iu.id = i.unit_id + JOIN depot d ON d.uuid = m.depot_uuid `; return getLots(sql, params, ' ORDER BY m.date ASC ') @@ -486,11 +492,6 @@ function getInventoryMovements(params) { movement.exit.quantity = line.quantity; movement.exit.unit_cost = stockUnitCost; movement.exit.value = line.quantity * line.unit_cost; - - // stock status - movement.stock.quantity = stockQuantity; - movement.stock.unit_cost = stockUnitCost; - movement.stock.value = stockValue; } else { const newQuantity = line.quantity + stockQuantity; const newValue = (line.unit_cost * line.quantity) + stockValue; @@ -504,12 +505,13 @@ function getInventoryMovements(params) { movement.entry.quantity = line.quantity; movement.entry.unit_cost = line.unit_cost; movement.entry.value = line.quantity * line.unit_cost; - - // stock status - movement.stock.quantity = stockQuantity; - movement.stock.unit_cost = stockUnitCost; - movement.stock.value = stockValue; } + + // stock status + movement.stock.quantity = stockQuantity; + movement.stock.unit_cost = stockUnitCost; + movement.stock.value = stockValue; + return movement; }); diff --git a/test/end-to-end/stock/stock.movements.spec.js b/test/end-to-end/stock/stock.movements.spec.js index b2d30bf115..11cb84ae53 100644 --- a/test/end-to-end/stock/stock.movements.spec.js +++ b/test/end-to-end/stock/stock.movements.spec.js @@ -1,7 +1,6 @@ const FU = require('../shared/FormUtils'); const GU = require('../shared/GridUtils'); const helpers = require('../shared/helpers'); -const components = require('../shared/components'); const SearchModal = require('../shared/search.page'); const Filters = require('../shared/components/bhFilters'); @@ -39,11 +38,11 @@ function StockMovementsRegistryTests() { GU.expectRowCount(gridId, 15 + (2 * depotGroupingRow)); }); - it('find exit movements', () => { + it('filters by entry/exit', () => { // for Exit modal.setEntryExit(1); modal.submit(); - GU.expectRowCount(gridId, 16 + depotGroupingRow); + GU.expectRowCount(gridId, 8 + depotGroupingRow); }); it('find movements by depot', () => { @@ -67,43 +66,43 @@ function StockMovementsRegistryTests() { it('find by lots reasons for purchase order', () => { // FIX ME: reasons must not depend on translations - //selection with `id` works but it is not completed + // selection with `id` works but it is not completed modal.setMovementReason('Commande d\'achat'); modal.submit(); - GU.expectRowCount(gridId, 24 + depotGroupingRow); + GU.expectRowCount(gridId, 8 + depotGroupingRow); }); it('find by lots reasons for distribution to patient', () => { - // to patient + // to patient modal.setMovementReason('Vers un patient'); modal.submit(); - GU.expectRowCount(gridId, 24 + depotGroupingRow); + GU.expectRowCount(gridId, 2 + depotGroupingRow); }); it('find by lots reasons for distribution to depot', () => { modal.setMovementReason('Vers un depot'); modal.submit(); - GU.expectRowCount(gridId, 24 + depotGroupingRow); + GU.expectRowCount(gridId, 2 + depotGroupingRow); }); it('find by lots reasons for distribution from depot', () => { // from depot modal.setMovementReason('En provenance d\'un depot'); modal.submit(); - GU.expectRowCount(gridId, 24 + depotGroupingRow); + GU.expectRowCount(gridId, 1 + depotGroupingRow); }); it('find by lots reasons for positive adjustement', () => { modal.setMovementReason('Ajustement (Positif)'); modal.submit(); - GU.expectRowCount(gridId, 24 + depotGroupingRow); + GU.expectRowCount(gridId, 1 + depotGroupingRow); }); it('find by lots reasons for negative adjustement', () => { modal.setMovementReason('Ajustement (Negatif)'); modal.submit(); - GU.expectRowCount(gridId, 24 + depotGroupingRow); - }); + GU.expectRowCount(gridId, 1 + depotGroupingRow); + }); it('find lots by date - Fev 2017', () => { modal.setdateInterval('02/02/2017', '02/02/2017', 'date');