diff --git a/client/src/i18n/en/cost_center.json b/client/src/i18n/en/cost_center.json index e30e45e480..187903024f 100644 --- a/client/src/i18n/en/cost_center.json +++ b/client/src/i18n/en/cost_center.json @@ -17,10 +17,12 @@ "EDIT_ALLOCATION_BASIS": "Edit allocation basis", "EDIT_ALLOCATION_KEYS" : "Edit Allocation Keys", "EDIT_COST_CENTER" : "Update the Cost Center Information", + "EDIT_STEP_ORDER" : "Edit order of cost allocation steps", "PRINCIPAL": "Principal Cost Center", "NO_COST_CENTER_DEFINED": "** Cost Center Not Defined **", "SELECT_ALLOCATION_BASIS": "Select allocation basis", "STEP_DOWN_COST_ALLOCATION": "Step-down cost allocation", + "STEP_ORDER": "Allocation Step Order", "ONLY_FOR_EXPLOITATION_ACCOUNTS": "Only for operating accounts (income and expenses). For others accounts, the cost center will not be considered", "UPDATE_ALLOCATION_QUANTITIES": "Update", "UPDATE_ALLOCATION_QUANTITIES_TOOLTIP": "Update system-computed cost center allocation quantities", diff --git a/client/src/i18n/fr/cost_center.json b/client/src/i18n/fr/cost_center.json index 3ec1c542be..e1bc6ec910 100644 --- a/client/src/i18n/fr/cost_center.json +++ b/client/src/i18n/fr/cost_center.json @@ -17,10 +17,12 @@ "EDIT_ALLOCATION_BASIS": "Modifier la base d'allocation", "EDIT_ALLOCATION_KEYS" : "Modifier les clés de répartition", "EDIT_COST_CENTER" : "Mise à jour des informations du centre de coût", + "EDIT_STEP_ORDER" : "Modifier l'ordre des étapes de l'allocation des coûts", "PRINCIPAL": "Centre de coût Principal", "NO_COST_CENTER_DEFINED": "** Aucun centre de cout **", "SELECT_ALLOCATION_BASIS": "Sélectionnez la base d'allocation", "STEP_DOWN_COST_ALLOCATION": "Allocation séquentielle des coûts", + "STEP_ORDER": "Ordre des étapes de l'allocation", "ONLY_FOR_EXPLOITATION_ACCOUNTS": "Uniquement pour les comptes d'exploitations (produits et charges). Pour les autres comptes, le centre de cout ne sera pas pris en compte", "UPDATE_ALLOCATION_QUANTITIES": "Mettre à jour", "UPDATE_ALLOCATION_QUANTITIES_TOOLTIP": "Mettre à jour les quantités d'allocation des centres de coûts calculées par le système", diff --git a/client/src/modules/cost_center/cost_center.html b/client/src/modules/cost_center/cost_center.html index b6698556e6..921805ba25 100644 --- a/client/src/modules/cost_center/cost_center.html +++ b/client/src/modules/cost_center/cost_center.html @@ -21,6 +21,11 @@ ALLOCATION_BASES +
  • + + COST_CENTER.EDIT_STEP_ORDER + +
  • diff --git a/client/src/modules/cost_center/cost_center.js b/client/src/modules/cost_center/cost_center.js index f3f1ede40d..14037d0b0d 100644 --- a/client/src/modules/cost_center/cost_center.js +++ b/client/src/modules/cost_center/cost_center.js @@ -22,6 +22,7 @@ function CostCenterController(CostCenters, ModalService, Notify, uiGridConstants vm.deleteCostCenter = deleteCostCenter; vm.toggleFilter = toggleFilter; vm.openEditAllocationBasisModal = openEditAllocationBasisModal; + vm.editAllocationStepOrder = editAllocationStepOrder; // global variables vm.gridApi = {}; @@ -159,5 +160,13 @@ function CostCenterController(CostCenters, ModalService, Notify, uiGridConstants }).result.catch(angular.noop); } + function editAllocationStepOrder() { + $uibModal.open({ + templateUrl : 'modules/cost_center/modals/edit_allocation_step_order.modal.html', + controller : 'AllocationEditStepOrderController as ModalCtrl', + // size : 'lg', + }).result.catch(angular.noop); + } + loadCostCenters(); } diff --git a/client/src/modules/cost_center/cost_center.service.js b/client/src/modules/cost_center/cost_center.service.js index a472ac32c8..e1fa13a8aa 100644 --- a/client/src/modules/cost_center/cost_center.service.js +++ b/client/src/modules/cost_center/cost_center.service.js @@ -45,5 +45,11 @@ function CostCenterService(Api, $uibModal) { .then(service.util.unwrapHttpResponse); }; + service.setAllocationStepOrder = (options) => { + const url = `/cost_center/step_order/multi`; + return service.$http.put(url, { params : options }) + .then(service.util.unwrapHttpResponse); + }; + return service; } diff --git a/client/src/modules/cost_center/modals/edit_allocation_step_order.modal.html b/client/src/modules/cost_center/modals/edit_allocation_step_order.modal.html new file mode 100644 index 0000000000..1613e8640c --- /dev/null +++ b/client/src/modules/cost_center/modals/edit_allocation_step_order.modal.html @@ -0,0 +1,44 @@ +
    + + + + + + + +
    \ No newline at end of file diff --git a/client/src/modules/cost_center/modals/edit_allocation_step_order.modal.js b/client/src/modules/cost_center/modals/edit_allocation_step_order.modal.js new file mode 100644 index 0000000000..65f46c6e4d --- /dev/null +++ b/client/src/modules/cost_center/modals/edit_allocation_step_order.modal.js @@ -0,0 +1,115 @@ +angular.module('bhima.controllers') + .controller('AllocationEditStepOrderController', AllocationEditStepOrderController); + +AllocationEditStepOrderController.$inject = [ + 'CostCenterService', 'NotifyService', '$uibModalInstance', 'uiGridConstants', +]; + +function AllocationEditStepOrderController(CostCenters, Notify, Instance, uiGridConstants) { + + const vm = this; + + vm.loading = false; + vm.cancel = Instance.close; + vm.loadCostCenters = loadCostCenters; + vm.moveStepDown = moveStepDown; + vm.moveStepUp = moveStepUp; + vm.submit = submit; + + // global variables + vm.gridApi = {}; + vm.filterEnabled = false; + + // options for the UI grid + vm.gridOptions = { + appScopeProvider : vm, + enableColumnMenus : false, + flatEntityAccess : true, + enableRowReordering : true, + enableSorting : false, + onRegisterApi : onRegisterApiFn, + columnDefs : [ + { + field : 'label', + displayName : 'FORM.LABELS.DESIGNATION', + headerCellFilter : 'translate', + enableSorting : false, + }, + { + field : 'step_order', + displayName : 'COST_CENTER.STEP_ORDER', + headerCellFilter : 'translate', + headerCellClass : 'allocationBasisColHeader', + defaultSort : { direction : uiGridConstants.ASC, priority : 1 }, + type : 'number', + visible : true, + }, + { + field : 'reorder', + displayName : '', + cellTemplate : '/modules/cost_center/templates/reorder_allocation_steps.tmpl.html', + enableSorting : false, + enableFiltering : false, + }, + ], + }; + + function loadCostCenters() { + vm.loading = true; + CostCenters.read() + .then((data) => { + const auxData = data.filter(item => !item.is_principal); + auxData.sort((a, b) => Number(a.step_order) - Number(b.step_order)); + + // rewrite the step order + auxData.forEach((value, idx) => { + value.step_order = idx + 1; + }); + + vm.data = auxData; + vm.gridOptions.data = vm.data; + }) + .catch(Notify.handleError) + .finally(() => { + vm.loading = false; + }); + } + + function onRegisterApiFn(gridApi) { + vm.gridApi = gridApi; + } + + function moveStepDown(row) { + const stepOrder = row.step_order; + const upper = vm.data.find(r => r.step_order === stepOrder + 1); + row.step_order++; + upper.step_order--; + vm.gridOptions.data = vm.data; + vm.gridApi.core.refreshRows(); + } + + function moveStepUp(row) { + const stepOrder = row.step_order; + const lower = vm.data.find(r => r.step_order === stepOrder - 1); + row.step_order--; + lower.step_order++; + vm.gridOptions.data = vm.data; + vm.gridApi.core.refreshRows(); + } + + function submit() { + vm.loading = true; + const newStepOrder = vm.gridOptions.data.map(row => ({ + id : row.id, + step_order : row.step_order, + })); + CostCenters.setAllocationStepOrder({ new_order : newStepOrder }) + .then(() => { + vm.loading = false; + Instance.close(); + Notify.success('FORM.INFO.UPDATE_SUCCESS'); + }); + } + + loadCostCenters(); +} diff --git a/client/src/modules/cost_center/templates/reorder_allocation_steps.tmpl.html b/client/src/modules/cost_center/templates/reorder_allocation_steps.tmpl.html new file mode 100644 index 0000000000..cb361524f1 --- /dev/null +++ b/client/src/modules/cost_center/templates/reorder_allocation_steps.tmpl.html @@ -0,0 +1,13 @@ +
    + + + +
    diff --git a/server/config/routes.js b/server/config/routes.js index aca7a72e1c..7d0138fb40 100644 --- a/server/config/routes.js +++ b/server/config/routes.js @@ -934,6 +934,7 @@ exports.configure = function configure(app) { app.post('/cost_center', costCenter.create); app.put('/cost_center/:id', costCenter.update); app.delete('/cost_center/:id', costCenter.delete); + app.put('/cost_center/step_order/multi', costCenter.setAllocationStepOrder); // Step-down allocation basis API app.get('/cost_center_allocation_basis', costAllocationBasis.list); diff --git a/server/controllers/finance/cost_center.js b/server/controllers/finance/cost_center.js index 5f97b041cf..9db8f89c2d 100644 --- a/server/controllers/finance/cost_center.js +++ b/server/controllers/finance/cost_center.js @@ -12,7 +12,7 @@ const FilterParser = require('../../lib/filter'); async function lookupCostCenter(id) { const sqlCostCenter = ` SELECT fc.id, fc.label, fc.is_principal, fc.project_id, - fc.allocation_method, fc.allocation_basis_id, + fc.allocation_method, fc.allocation_basis_id, fc.step_order, cab.name AS allocation_basis_name, cab.units as allocation_basis_units, cab.is_predefined AS allocation_basis_is_predefined, cabval.quantity AS allocation_basis_quantity @@ -68,7 +68,7 @@ async function lookupCostCenter(id) { function list(req, res, next) { const filters = new FilterParser(req.query, { tableAlias : 'f' }); const sql = ` - SELECT f.id, f.label, f.is_principal, f.project_id, + SELECT f.id, f.label, f.is_principal, f.project_id, f.step_order, f.allocation_method, f.allocation_basis_id, GROUP_CONCAT(' ', LOWER(ar.description)) AS abbrs, GROUP_CONCAT(' ', s.name) serviceNames, p.name AS projectName, @@ -341,6 +341,23 @@ function assignCostCenterParams(accountsCostCenter, rubrics, key) { return rubrics; } + +// PUT /cost_center/step_order/multi +function setAllocationStepOrder(req, res, next) { + const { params } = req.body; + const query = 'UPDATE `cost_center` SET `step_order` = ? WHERE `id` = ?'; + const transaction = db.transaction(); + params.new_order.forEach(row => { + transaction.addQuery(query, [row.step_order, row.id]); + }); + + transaction.execute() + .then(() => { + res.sendStatus(204); + }) + .catch(next); +} + // get list of costCenter exports.list = list; // get details of a costCenter @@ -355,3 +372,5 @@ exports.delete = del; exports.getAllCostCenterAccounts = getAllCostCenterAccounts; // Assign Cost Center Params exports.assignCostCenterParams = assignCostCenterParams; + +exports.setAllocationStepOrder = setAllocationStepOrder;