diff --git a/src/stock-physical-inventory-draft/messages_en.json b/src/stock-physical-inventory-draft/messages_en.json new file mode 100644 index 0000000..750d9e5 --- /dev/null +++ b/src/stock-physical-inventory-draft/messages_en.json @@ -0,0 +1,3 @@ +{ + "stockPhysicalInventoryDraft.unaccountedQuantityError": "Unnacounted quantity must be 0" +} \ No newline at end of file diff --git a/src/stock-physical-inventory-draft/physical-inventory-draft.controller.js b/src/stock-physical-inventory-draft/physical-inventory-draft.controller.js index f81b9b3..0e895b6 100644 --- a/src/stock-physical-inventory-draft/physical-inventory-draft.controller.js +++ b/src/stock-physical-inventory-draft/physical-inventory-draft.controller.js @@ -644,6 +644,28 @@ return lineItem.quantityInvalid; }; + // SELV3-508: Add validation to check unaccounted quantity + /** + * @ngdoc method + * @methodOf stock-adjustment-creation.controller:StockAdjustmentCreationController + * @name validateUnaccountedQuantity + * + * @description + * Validate line item quantity and returns self. + * + * @param {Object} lineItem line item to be validated. + */ + vm.validateUnaccountedQuantity = function(lineItem) { + if (lineItem.unaccountedQuantity === 0) { + lineItem.unaccountedQuantityInvalid = false; + } else { + lineItem.unaccountedQuantityInvalid = messageService + .get('stockPhysicalInventoryDraft.unaccountedQuantityError'); + } + return lineItem.unaccountedQuantityInvalid; + }; + // SELV3-508: ends here + function isEmpty(value) { return value === '' || value === undefined || value === null; } @@ -655,7 +677,7 @@ .each(function(item) { if (!item.active) { activeError = 'stockPhysicalInventoryDraft.submitInvalidActive'; - } else if (vm.validateQuantity(item)) { + } else if (vm.validateQuantity(item) || vm.validateUnaccountedQuantity(item)) { qtyError = 'stockPhysicalInventoryDraft.submitInvalid'; } }); diff --git a/src/stock-physical-inventory-draft/physical-inventory-draft.controller.spec.js b/src/stock-physical-inventory-draft/physical-inventory-draft.controller.spec.js index 83b1a18..bdd46d2 100644 --- a/src/stock-physical-inventory-draft/physical-inventory-draft.controller.spec.js +++ b/src/stock-physical-inventory-draft/physical-inventory-draft.controller.spec.js @@ -322,13 +322,24 @@ describe('PhysicalInventoryDraftController', function() { it('should show modal for occurred date if no quantity missing', function() { this.lineItem1.active = true; this.lineItem3.active = true; + // SELV3-508: Add validation to check unaccounted quantity + this.lineItem1.quantity = 1234; this.lineItem3.quantity = 123; + this.lineItem1.stockAdjustments = [{ + quantity: 1234, + reason: { + reasonType: 'CREDIT' + } + }]; this.lineItem3.stockAdjustments = [{ quantity: 123, reason: { reasonType: 'CREDIT' } }]; + this.lineItem1.unaccountedQuantity = 0; + this.lineItem3.unaccountedQuantity = 0; + // SELV3-508: ends here var deferred = this.$q.defer(); deferred.resolve(); chooseDateModalService.show.andReturn(deferred.promise); @@ -365,13 +376,24 @@ describe('PhysicalInventoryDraftController', function() { beforeEach(function() { this.lineItem1.active = true; this.lineItem3.active = true; + // SELV3-508: Add validation to check unaccounted quantity + this.lineItem1.quantity = 1234; this.lineItem3.quantity = 123; + this.lineItem1.stockAdjustments = [{ + quantity: 1234, + reason: { + reasonType: 'CREDIT' + } + }]; this.lineItem3.stockAdjustments = [{ quantity: 123, reason: { reasonType: 'CREDIT' } }]; + this.lineItem1.unaccountedQuantity = 0; + this.lineItem3.unaccountedQuantity = 0; + // SELV3-508: ends here spyOn(this.$window, 'open').andCallThrough(); chooseDateModalService.show.andReturn(this.$q.when({})); spyOn(this.accessTokenFactory, 'addAccessToken').andCallThrough(); diff --git a/src/stock-physical-inventory-draft/physical-inventory-draft.html b/src/stock-physical-inventory-draft/physical-inventory-draft.html new file mode 100644 index 0000000..90860db --- /dev/null +++ b/src/stock-physical-inventory-draft/physical-inventory-draft.html @@ -0,0 +1,120 @@ +
{{'stockPhysicalInventoryDraft.productCode' | message}} | +{{'stockPhysicalInventoryDraft.product' | message}} | +{{'stockPhysicalInventoryDraft.lotCode' | message}} | +{{'stockPhysicalInventoryDraft.expiryDate' | message}} | +{{'stockPhysicalInventoryDraft.soh' | message}} | +{{'stockPhysicalInventoryDraft.currentStock' | message}} | +{{'stockPhysicalInventoryDraft.VVMStatus' | message}} | +{{'stockPhysicalInventoryDraft.reasons' | message}} | +{{'stockPhysicalInventoryDraft.unaccountedQuantity' | message}} | +{{'stockPhysicalInventoryDraft.actions' | message}} | +|
---|---|---|---|---|---|---|---|---|---|---|
{{lineItems[0].orderable.productCode}} | +{{lineItems[0].orderable | productName}} | ++ | + | {{vm.calculate(lineItems, 'stockOnHand')}} | +{{vm.calculate(lineItems, 'quantity')}} | ++ | + | + | + | |
{{lineItems.length > 1 ? '' : lineItem.orderable.productCode}} | +{{lineItems.length > 1 ? '' : (lineItem.orderable | productName)}} | ++ + | ++ {{lineItem.displayLotMessage}} + | +{{lineItem.lot.expirationDate | openlmisDate}} | +{{lineItem.stockOnHand}} | ++ + | ++ + | +
+
+ | {{lineItem.unaccountedQuantity}} | + + ++ + | +