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.title' | message: {'facilityCode': vm.facility.code, 'facilityName': vm.facility.name, 'program': vm.program.name} }} +

+ +
+
+
+ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {{'stockPhysicalInventoryDraft.noLineItems' | message}} + + {{'stockPhysicalInventoryDraft.noSearchResults' | message}} +
{{'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}} + +
+ +
+ + \ No newline at end of file