Skip to content

Commit

Permalink
fix(inventory): pass uuids in URL
Browse files Browse the repository at this point in the history
This commit fixes the inventory server UPDATE route to conform to our
HTTP API standards.  It sends back a JSON object instead of an array,
allowing both the create() and update() routes to pass the uuid back to
the central list state and use the grid to scroll to the updated record.

This commit contains much performance refactoring.
  1. Makes the <select>s use track by in the ActionForm.
  2. Uses <translate> directive instead of filter
  3. Uses a loading indicator on the bhLoadingButton

A few of the issues in
#738
have been addressed.
  • Loading branch information
Jonathan Niles committed Jan 4, 2017
1 parent 3d33087 commit d0e532f
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 98 deletions.
2 changes: 1 addition & 1 deletion client/src/js/filters/currency.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/

angular.module('bhima.filters')
.filter('currency', CurrencyFilter);
.filter('currency', CurrencyFilter);

CurrencyFilter.$inject = [
'currencyFormat', 'SessionService'
Expand Down
2 changes: 1 addition & 1 deletion client/src/partials/inventory/inventory.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function onEnterFactory(stateType) {
$state.go('^.list', params, { reload : true });
})
.catch(function (error) {
$state.go('^.list', { id : $state.params.id }, {notify : false });
$state.go('^.list', { uuid : $state.params.id }, {notify : false });
});
};
}
14 changes: 6 additions & 8 deletions client/src/partials/inventory/list/list.html
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
<!-- breadcrumb header -->
<bh-breadcrumb
path ="InventoryCtrl.bcPaths"
button ="InventoryCtrl.bcButtons"
print ="InventoryCtrl.buttonPrint"
path ="InventoryCtrl.bcPaths"
button ="InventoryCtrl.bcButtons"
print ="InventoryCtrl.buttonPrint"
>
</bh-breadcrumb>

<!-- grid content -->
<div class="flex-content">
<div class="container-fluid">

<!-- inventory list of items -->
<div id="inventoryListGrid"
<div
id="inventoryListGrid"
class="grid-full-height"
ui-grid="InventoryCtrl.gridOptions"
ui-grid-auto-resize
ui-grid-resize-columns
ui-grid-grouping>
ui-grid-resize-columns>
</div>
</div>
</div>
51 changes: 28 additions & 23 deletions client/src/partials/inventory/list/list.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
angular.module('bhima.controllers')
.controller('InventoryListController', InventoryListController);
.controller('InventoryListController', InventoryListController);

// dependencies injection
InventoryListController.$inject = [
Expand All @@ -14,7 +14,7 @@ InventoryListController.$inject = [
function InventoryListController ($translate, Inventory, Notify, uiGridConstants, Modal, $state) {
var vm = this;

/** gobal variables */
/** global variables */
vm.filterEnabled = false;
vm.gridOptions = {};
vm.gridApi = {};
Expand All @@ -41,27 +41,32 @@ function InventoryListController ($translate, Inventory, Notify, uiGridConstants

// grid default options

var columnDefs = [
{
field : 'code', displayName : 'FORM.LABELS.CODE', headerCellFilter : 'translate'
},{
field : 'consumable', displayName : 'FORM.LABELS.CONSUMABLE', headerCellFilter : 'translate',
cellTemplate : '/partials/inventory/list/templates/consumable.cell.tmpl.html'
},
{ field : 'groupName', displayName : 'FORM.LABELS.GROUP', headerCellFilter : 'translate'},
{ field : 'label', displayName : 'FORM.LABELS.LABEL', headerCellFilter : 'translate'},
{ field : 'price', displayName : 'FORM.LABELS.PRICE', headerCellFilter : 'translate', cellClass: 'text-right' },
{ field : 'type', displayName : 'FORM.LABELS.TYPE', headerCellFilter : 'translate'},
{ field : 'unit', displayName : 'FORM.LABELS.UNIT', headerCellFilter : 'translate'},
{ field : 'unit_weight', displayName : 'FORM.LABELS.WEIGHT', headerCellFilter : 'translate', cellClass: 'text-right' },
{ field : 'unit_volume', displayName : 'FORM.LABELS.VOLUME', headerCellFilter : 'translate', cellClass: 'text-right' },
{
field : 'action',
displayName : '',
cellTemplate: '/partials/inventory/list/templates/inventoryEdit.actions.tmpl.html',
enableFiltering: false,
enableSorting: false,
enableColumnMenu: false,
var columnDefs = [{
field : 'code', displayName : 'FORM.LABELS.CODE', headerCellFilter : 'translate'
},{
field : 'consumable', displayName : 'FORM.LABELS.CONSUMABLE', headerCellFilter : 'translate',
cellTemplate : '/partials/inventory/list/templates/consumable.cell.tmpl.html'
}, {
field : 'groupName', displayName : 'FORM.LABELS.GROUP', headerCellFilter : 'translate'
}, {
field : 'label', displayName : 'FORM.LABELS.LABEL', headerCellFilter : 'translate'
}, {
field : 'price', displayName : 'FORM.LABELS.PRICE', headerCellFilter : 'translate', cellClass: 'text-right', type:'number'
}, {
field : 'type', displayName : 'FORM.LABELS.TYPE', headerCellFilter : 'translate'
}, {
field : 'unit', displayName : 'FORM.LABELS.UNIT', headerCellFilter : 'translate'
}, {
field : 'unit_weight', displayName : 'FORM.LABELS.WEIGHT', headerCellFilter : 'translate', cellClass: 'text-right', type:'number'
}, {
field : 'unit_volume', displayName : 'FORM.LABELS.VOLUME', headerCellFilter : 'translate', cellClass: 'text-right', type:'number'
}, {
field : 'action',
displayName : '',
cellTemplate: '/partials/inventory/list/templates/inventoryEdit.actions.tmpl.html',
enableFiltering: false,
enableSorting: false,
enableColumnMenu: false,
}];

vm.gridOptions = {
Expand Down
8 changes: 5 additions & 3 deletions client/src/partials/inventory/list/modals/actions.modal.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
angular.module('bhima.controllers')
.controller('InventoryListActionsModalController', InventoryListActionsModalController);
.controller('InventoryListActionsModalController', InventoryListActionsModalController);

InventoryListActionsModalController.$inject = [
'AccountService', 'InventoryService', 'InventoryGroupService',
Expand Down Expand Up @@ -38,14 +38,16 @@ function InventoryListActionsModalController(Account, Inventory, InventoryGroup,
Inventory.create(record) :
Inventory.update(vm.identifier, record);

promise
return promise
.then(function (res) {
var message = vm.isCreateState ?
'FORM.INFO.CREATE_SUCCESS' :
'FORM.INFO.UPDATE_SUCCESS';

Notify.success(message);
Instance.close(res);

// pass back the uuid
Instance.close(res.uuid);
})
.catch(Notify.handleError);
}
Expand Down
58 changes: 24 additions & 34 deletions client/src/partials/inventory/list/modals/actions.tmpl.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
<form name="ActionForm" bh-submit="$ctrl.submit(ActionForm)" bh-form-defaults novalidate>
<div class="modal-header">
<ol class="headercrumb">
<li class="static">
{{ "FORM.LABELS.INVENTORY" | translate }}
<li class="static" translate>FORM.LABELS.INVENTORY</li>
<li class="title text-capitalize" ng-show="$ctrl.isCreateState" translate>
INVENTORY.ADD_METADATA
</li>
<li class="title text-capitalize" ng-show="$ctrl.isCreateState">
{{ "INVENTORY.ADD_METADATA" | translate }}
</li>

<li class="title text-capitalize" ng-show="$ctrl.isUpdateState">
{{ "INVENTORY.EDIT_METADATA" | translate }}
<li class="title text-capitalize" ng-show="$ctrl.isUpdateState" translate>
INVENTORY.EDIT_METADATA
</li>
</ol>
</div>
Expand All @@ -18,7 +15,7 @@
<div
class="form-group"
ng-class="{ 'has-error' : ActionForm.$submitted && ActionForm.code.$invalid }">
<label class="control-label">{{ 'FORM.LABELS.CODE' | translate }}</label>
<label class="control-label" translate>FORM.LABELS.CODE</label>
<input ng-model="$ctrl.item.code"
class="form-control"
type="text"
Expand All @@ -32,7 +29,7 @@

<div class="form-group"
ng-class="{ 'has-error' : ActionForm.$submitted && ActionForm.text.$invalid }">
<label class="control-label">{{ 'FORM.LABELS.NAME' | translate }}</label>
<label class="control-label" translate>FORM.LABELS.NAME</label>
<input ng-model="$ctrl.item.label"
class="form-control"
type="text"
Expand All @@ -47,13 +44,13 @@
<div class="checkbox">
<label>
<input type="checkbox" name="consumable" ng-true-value="1" ng-false-value="0" ng-model="$ctrl.item.consumable">
{{ 'FORM.LABELS.CONSUMABLE' | translate }}
<span translate>FORM.LABELS.CONSUMABLE</span>
</label>
</div>

<div class="form-group"
ng-class="{ 'has-error' : ActionForm.$submitted && ActionForm.price.$invalid }">
<label class="control-label">{{ 'FORM.LABELS.PRICE' | translate }}</label>
<label class="control-label" translate>FORM.LABELS.PRICE</label>
<input class="form-control"
type="number"
ng-min="0"
Expand All @@ -68,14 +65,12 @@

<div class="form-group"
ng-class="{ 'has-error' : ActionForm.$submitted && ActionForm.group.$invalid }">
<label class="control-label">{{ 'FORM.LABELS.GROUP' | translate }}</label>
<select
class="form-control"
name="group"
<label class="control-label" translate>FORM.LABELS.GROUP</label>
<select class="form-control" name="group"
ng-model="$ctrl.item.group"
ng-options="ig as ig.name for ig in $ctrl.inventoryGroupList"
ng-options="ig as ig.name for ig in $ctrl.inventoryGroupList track by ig.uuid"
required>
<option value="" disabled> {{ 'FORM.SELECT.INVENTORY_GROUP' | translate }} </option>
<option value="" disabled translate>FORM.SELECT.INVENTORY_GROUP</option>
</select>
<div class="help-block" ng-messages="ActionForm.group.$error" ng-show="ActionForm.$submitted">
<div ng-messages-include="partials/templates/messages.tmpl.html"></div>
Expand All @@ -84,14 +79,14 @@

<div class="form-group"
ng-class="{ 'has-error' : ActionForm.$submitted && ActionForm.type.$invalid }">
<label class="control-label">{{ 'FORM.LABELS.TYPE' | translate }}</label>
<label class="control-label" translate>FORM.LABELS.TYPE</label>
<select
class="form-control"
name="type"
ng-model="$ctrl.item.type"
ng-options="type as type.text for type in $ctrl.inventoryTypeList"
ng-options="type as type.text for type in $ctrl.inventoryTypeList track by type.id"
required>
<option value="" disabled> {{ 'FORM.SELECT.INVENTORY_TYPE' | translate }} </option>
<option value="" disabled translate>FORM.SELECT.INVENTORY_TYPE</option>
</select>
<div class="help-block" ng-messages="ActionForm.type.$error" ng-show="ActionForm.$submitted">
<div ng-messages-include="partials/templates/messages.tmpl.html"></div>
Expand All @@ -100,45 +95,40 @@

<div class="form-group"
ng-class="{ 'has-error' : ActionForm.$submitted && ActionForm.unit.$invalid }">
<label class="control-label">{{ 'FORM.LABELS.UNIT' | translate }}</label>
<label class="control-label" translate>FORM.LABELS.UNIT</label>
<select
class="form-control"
name="unit"
ng-model="$ctrl.item.unit"
ng-options="unit as unit.text for unit in $ctrl.inventoryUnitList"
required>
<option value="" disabled> {{ 'FORM.SELECT.INVENTORY_UNIT' | translate }} </option>
<option value="" disabled translate>FORM.SELECT.INVENTORY_UNIT</option>
</select>
<div class="help-block" ng-messages="ActionForm.unit.$error" ng-show="ActionForm.$submitted">
<div ng-messages-include="partials/templates/messages.tmpl.html"></div>
</div>
</div>

<div class="form-group">
<label class="control-label">{{ 'FORM.LABELS.UNIT_WEIGHT' | translate }}</label>
<label class="control-label" translate>FORM.LABELS.UNIT_WEIGHT</label>
<input class="form-control" type="number" step="1" name="unit_weight"
ng-model="$ctrl.item.unit_weight"
placeholder="{{ 'FORM.PLACEHOLDERS.UNIT_WEIGHT' | translate }}...">
</div>

<div class="form-group">
<label class="control-label">{{ 'FORM.LABELS.UNIT_VOLUME' | translate }}</label>
<input class="form-control" type="number" step="1" name="unit_volume" ng-model="$ctrl.item.unit_volume"
placeholder="{{ 'FORM.PLACEHOLDERS.UNIT_VOLUME' | translate }}...">
<label class="control-label" translate>FORM.LABELS.UNIT_VOLUME</label>
<input class="form-control" type="number" step="1" name="unit_volume" ng-model="$ctrl.item.unit_volume" placeholder="{{ 'FORM.PLACEHOLDERS.UNIT_VOLUME' | translate }}...">
</div>

</div>

<div class="modal-footer">
<button type="button"
class="btn btn-default"
data-method="cancel"
ng-click="$ctrl.cancel()">
{{ 'FORM.BUTTONS.CANCEL' | translate }}
<button type="button" class="btn btn-default" data-method="cancel" ng-click="$ctrl.cancel()">
<span translate>FORM.BUTTONS.CANCEL</span>
</button>

<bh-loading-button loading-state="ActionForm.$loading">
{{ 'FORM.BUTTONS.SUBMIT' | translate }}
<span translate>FORM.BUTTONS.SUBMIT</span>
</bh-loading-button>
</div>
</form>
33 changes: 14 additions & 19 deletions server/controllers/inventory/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,14 @@ function createInventoryItems(req, res, next) {
* Update an inventory data entry
*/
function updateInventoryItems(req, res, next) {

core.updateItemsMetadata(req.body, req.params.uuid)
.then((metadata) => {
res.status(200).json(metadata);
})
.catch(function (error) {
core.errorHandler(error, req, res, next);
})
.done();
.then(metadata => {
res.status(200).json(metadata);
})
.catch(function (error) {
core.errorHandler(error, req, res, next);
})
.done();
}

/**
Expand Down Expand Up @@ -159,17 +158,13 @@ function getInventoryItemsById(req, res, next) {
var uuid = req.params.uuid;

core.getItemsMetadataById(uuid)
.then(function (rows) {
if (!rows.length) {
throw core.errors.NO_INVENTORY_ITEM;
}

res.status(200).json(rows[0]);
})
.catch(function (error) {
core.errorHandler(error, req, res, next);
})
.done();
.then(function (row) {
res.status(200).json(row);
})
.catch(function (error) {
core.errorHandler(error, req, res, next);
})
.done();
}

/**
Expand Down
6 changes: 3 additions & 3 deletions server/controllers/inventory/inventory/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function updateItemsMetadata(record, identifier) {
* in the main controller (inventory.js)
*/
return db.exec(sql, [record, record.uuid])
.then(() => getItemsMetadataById(identifier));
.then(() => getItemsMetadataById(identifier));
}

/**
Expand Down Expand Up @@ -135,7 +135,7 @@ function getItemsMetadata() {
*/
function getItemsMetadataById(uuid) {

var sql =
const sql =
`SELECT BUID(i.uuid) as uuid, i.code, i.text AS label, i.price, iu.text AS unit,
it.text AS type, ig.name AS groupName, BUID(ig.uuid) AS group_uuid, i.consumable, i.stock_min,
i.stock_max, i.origin_stamp AS timestamp, i.type_id, i.unit_id, i.unit_weight, i.unit_volume,
Expand All @@ -146,7 +146,7 @@ function getItemsMetadataById(uuid) {
i.unit_id = iu.id
WHERE i.uuid = ?;`;

return db.exec(sql, [db.bid(uuid)]);
return db.one(sql, [db.bid(uuid), uuid, 'inventory']);
}

/**
Expand Down
12 changes: 6 additions & 6 deletions test/integration/inventory.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,12 @@ describe('(/inventory) The Inventory HTTP API', () => {
.then((res) => {
// NOTE: Returned data are from the /inventory/:uuid/metadata API
// these data are not sended by the test but come from join with other table :
// label, groupNmae, type, unit
expect(res.body[0].uuid).to.be.equal(metadataUpdate.uuid);
expect(res.body[0].code).to.be.equal(metadataUpdate.code);
expect(res.body[0].text).to.be.equal(metadataUpdate.label);
expect(res.body[0].price).to.be.equal(metadataUpdate.price);
expect(res.body[0].group_uuid).to.be.equal(metadataUpdate.group_uuid);
// label, groupName, type, unit
expect(res.body.uuid).to.be.equal(metadataUpdate.uuid);
expect(res.body.code).to.be.equal(metadataUpdate.code);
expect(res.body.text).to.be.equal(metadataUpdate.label);
expect(res.body.price).to.be.equal(metadataUpdate.price);
expect(res.body.group_uuid).to.be.equal(metadataUpdate.group_uuid);
})
.catch(helpers.handler);
});
Expand Down

0 comments on commit d0e532f

Please sign in to comment.