From befb850b1addf23f86873484773449392700d9e4 Mon Sep 17 00:00:00 2001 From: saleksandra Date: Thu, 26 Sep 2024 14:29:54 +0200 Subject: [PATCH] OLMIS-7776: Fix issues with saving lots on Physical Inventory page --- CHANGELOG.md | 1 + .../add-products-modal.controller.js | 5 +- .../add-products-modal.controller.spec.js | 18 ++++++- .../add-products-modal.service.js | 9 ++-- .../add-products-modal.service.spec.js | 7 ++- .../messages_en.json | 4 +- .../physical-inventory-draft.controller.js | 54 ++++++++++--------- ...hysical-inventory-draft.controller.spec.js | 27 ++++++++-- .../physical-inventory.factory.js | 8 +++ .../physical-inventory.factory.spec.js | 22 ++++++++ 10 files changed, 118 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c94d8918..c36e8e85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ New functionalities that are backwards-compatible: Bug fixes: * [OLMIS-7748](https://openlmis.atlassian.net/browse/OLMIS-7748): Fix filtering 'includeInactive' on the Physical Inventory page +* [OLMIS-7776](https://openlmis.atlassian.net/browse/OLMIS-7776): Fix issues with saving lots on Physical Inventory page 2.1.5 / 2023-06-26 ================== diff --git a/src/stock-add-products-modal/add-products-modal.controller.js b/src/stock-add-products-modal/add-products-modal.controller.js index c0766ab9..22f74698 100644 --- a/src/stock-add-products-modal/add-products-modal.controller.js +++ b/src/stock-add-products-modal/add-products-modal.controller.js @@ -30,11 +30,11 @@ controller.$inject = ['availableItems', 'messageService', 'modalDeferred', 'orderableGroupService', '$scope', 'MAX_INTEGER_VALUE', 'hasPermissionToAddNewLot', 'selectedItems', 'alertService', - 'moment']; + 'moment', 'draft', 'physicalInventoryDraftCacheService']; function controller(availableItems, messageService, modalDeferred, orderableGroupService, $scope, MAX_INTEGER_VALUE, hasPermissionToAddNewLot, selectedItems, alertService, - moment) { + moment, draft, physicalInventoryDraftCacheService) { var vm = this; vm.$onInit = onInit; @@ -317,6 +317,7 @@ selectedItems.push(item); } }); + physicalInventoryDraftCacheService.cacheDraft(draft); modalDeferred.resolve(); } } diff --git a/src/stock-add-products-modal/add-products-modal.controller.spec.js b/src/stock-add-products-modal/add-products-modal.controller.spec.js index acfb6642..3d9592a0 100644 --- a/src/stock-add-products-modal/add-products-modal.controller.spec.js +++ b/src/stock-add-products-modal/add-products-modal.controller.spec.js @@ -16,11 +16,13 @@ describe('AddProductsModalController', function() { var vm, deferred, $q, $rootScope, $controller, OrderableDataBuilder, orderableGroupService, - LotDataBuilder, messageService, scope, item1, item2, lot1, lot2, selectedItems, orderable; + LotDataBuilder, messageService, scope, item1, item2, lot1, lot2, selectedItems, orderable, + physicalInventoryDraftCacheService; beforeEach(function() { module('stock-add-products-modal'); module('referencedata'); + module('stock-physical-inventory-draft'); inject(function($injector) { $rootScope = $injector.get('$rootScope'); @@ -30,6 +32,7 @@ describe('AddProductsModalController', function() { orderableGroupService = $injector.get('orderableGroupService'); LotDataBuilder = $injector.get('LotDataBuilder'); messageService = $injector.get('messageService'); + physicalInventoryDraftCacheService = $injector.get('physicalInventoryDraftCacheService'); }); deferred = $q.defer(); @@ -69,7 +72,11 @@ describe('AddProductsModalController', function() { orderableGroupService: orderableGroupService, $scope: scope, hasPermissionToAddNewLot: true, - selectedItems: selectedItems + selectedItems: selectedItems, + draft: { + lineItems: [] + }, + physicalInventoryDraftCacheService: physicalInventoryDraftCacheService }); vm.$onInit(); }); @@ -261,13 +268,18 @@ describe('AddProductsModalController', function() { quantity: 2 }; vm.addedItems = [item1, item2]; + var draft = { + lineItems: [] + }; + spyOn(physicalInventoryDraftCacheService, 'cacheDraft'); spyOn(deferred, 'resolve'); //when vm.confirm(); //then + expect(physicalInventoryDraftCacheService.cacheDraft).toHaveBeenCalledWith(draft); expect(deferred.resolve).toHaveBeenCalled(); }); @@ -281,12 +293,14 @@ describe('AddProductsModalController', function() { }; vm.addedItems = [item1, item2]; + spyOn(physicalInventoryDraftCacheService, 'cacheDraft'); spyOn(deferred, 'resolve'); //when vm.confirm(); //then + expect(physicalInventoryDraftCacheService.cacheDraft).not.toHaveBeenCalled(); expect(deferred.resolve).not.toHaveBeenCalled(); }); }); diff --git a/src/stock-add-products-modal/add-products-modal.service.js b/src/stock-add-products-modal/add-products-modal.service.js index 7989f550..d4052677 100644 --- a/src/stock-add-products-modal/add-products-modal.service.js +++ b/src/stock-add-products-modal/add-products-modal.service.js @@ -42,10 +42,10 @@ * Shows modal that allows users to choose products. * * @param {Array} availableItems orderable + lot items that can be selected - * @param {Array} selectedItems orderable + lot items that were added already + * @param {Array} draft physical inventory draft * @return {Promise} resolved with selected products. */ - function show(availableItems, selectedItems) { + function show(availableItems, draft) { return openlmisModalService.createDialog( { controller: 'AddProductsModalController', @@ -56,8 +56,11 @@ availableItems: function() { return availableItems; }, + draft: function() { + return draft; + }, selectedItems: function() { - return selectedItems; + return draft.lineItems; }, hasPermissionToAddNewLot: function(permissionService, ADMINISTRATION_RIGHTS, authorizationService) { diff --git a/src/stock-add-products-modal/add-products-modal.service.spec.js b/src/stock-add-products-modal/add-products-modal.service.spec.js index 6c1cf3da..a53c789b 100644 --- a/src/stock-add-products-modal/add-products-modal.service.spec.js +++ b/src/stock-add-products-modal/add-products-modal.service.spec.js @@ -56,13 +56,17 @@ describe('addProductsModalService', function() { lot: new that.LotDataBuilder().build() } ]; + + that.draft = { + lineItems: that.lineItems + }; }); describe('show', function() { it('should call createDialog function', function() { - that.addProductsModalService.show(that.items, that.lineItems); + that.addProductsModalService.show(that.items, that.draft); expect(that.openlmisModalService.createDialog).toHaveBeenCalled(); @@ -72,6 +76,7 @@ describe('addProductsModalService', function() { expect(that.config.show).toBeTruthy(); expect(angular.isFunction(that.config.resolve.availableItems)).toBeTruthy(); expect(angular.isFunction(that.config.resolve.selectedItems)).toBeTruthy(); + expect(angular.isFunction(that.config.resolve.draft)).toBeTruthy(); expect(angular.isFunction(that.config.resolve.hasPermissionToAddNewLot)).toBeTruthy(); }); }); diff --git a/src/stock-physical-inventory-draft/messages_en.json b/src/stock-physical-inventory-draft/messages_en.json index c792d358..883baf23 100644 --- a/src/stock-physical-inventory-draft/messages_en.json +++ b/src/stock-physical-inventory-draft/messages_en.json @@ -41,5 +41,7 @@ "stockPhysicalInventoryDraft.deactivateItem": "Do you want to deactivate Product with Lot Code: ${lot} for ${product}? \n This lot will also be deactivated on stock card", "stockPhysicalInventoryDraft.unaccountedQuantity": "Unaccounted Quantity", "stockPhysicalInventoryDraft.unaccountedQuantityError": "Unnacounted quantity must be 0", - "stockPhysicalInventoryDraft.actions": "Actions" + "stockPhysicalInventoryDraft.actions": "Actions", + "stockPhysicalInventoryDraft.saveDraft": "Warning: Saving will make all newly added lots unmodifiable, but removing physical inventory row will still be possible.", + "stockPhysicalInventoryDraft.error": "Error" } 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 f4ee80a8..48925bb2 100644 --- a/src/stock-physical-inventory-draft/physical-inventory-draft.controller.js +++ b/src/stock-physical-inventory-draft/physical-inventory-draft.controller.js @@ -258,7 +258,7 @@ notYetAddedItems.push(item); }); - addProductsModalService.show(notYetAddedItems, draft.lineItems).then(function() { + addProductsModalService.show(notYetAddedItems, draft).then(function() { $stateParams.program = vm.program; $stateParams.facility = vm.facility; $stateParams.noReload = true; @@ -345,8 +345,8 @@ return item; } }).active = false; - vm.draft = draft; - vm.saveDraft(true); + + vm.cacheDraft(); $state.go($state.current.name, $stateParams, { reload: $state.current.name }); @@ -389,31 +389,37 @@ * @description * Save physical inventory draft. */ - vm.saveDraft = function(withNotification) { - loadingModalService.open(); - return physicalInventoryFactory.saveDraft(draft).then(function() { - if (!withNotification) { - notificationService.success('stockPhysicalInventoryDraft.saved'); - } + vm.saveDraft = function() { + confirmService.confirmDestroy( + 'stockPhysicalInventoryDraft.saveDraft', + 'stockPhysicalInventoryDraft.save' + ).then(function() { + loadingModalService.open(); + return saveLots(draft, function() { + return physicalInventoryFactory.saveDraft(draft).then(function() { + notificationService.success('stockPhysicalInventoryDraft.saved'); - draft.$modified = undefined; - vm.cacheDraft(); + draft.$modified = undefined; + vm.cacheDraft(); - $stateParams.program = vm.program; - $stateParams.facility = vm.facility; - draft.lineItems.forEach(function(lineItem) { - if (lineItem.$isNewItem) { - lineItem.$isNewItem = false; - } - }); - $stateParams.noReload = true; + $stateParams.isAddProduct = false; + $stateParams.program = vm.program; + $stateParams.facility = vm.facility; + draft.lineItems.forEach(function(lineItem) { + if (lineItem.$isNewItem) { + lineItem.$isNewItem = false; + } + }); + $stateParams.noReload = true; - $state.go($state.current.name, $stateParams, { - reload: $state.current.name + $state.go($state.current.name, $stateParams, { + reload: $state.current.name + }); + }, function(errorResponse) { + loadingModalService.close(); + alertService.error(errorResponse.data.message); + }); }); - }, function(errorResponse) { - loadingModalService.close(); - alertService.error(errorResponse.data.message); }); }; 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 6ef293c7..0ac94de8 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 @@ -22,6 +22,7 @@ describe('PhysicalInventoryDraftController', function() { module('stock-physical-inventory-draft', function() { chooseDateModalService = jasmine.createSpyObj('chooseDateModalService', ['show']); }); + module('admin-lot-edit'); inject(function($injector) { this.$controller = $injector.get('$controller'); @@ -168,7 +169,8 @@ describe('PhysicalInventoryDraftController', function() { stockmanagementUrlFactory: this.stockmanagementUrlFactory, accessTokenFactory: this.accessTokenFactory, confirmService: this.confirmService, - stockCardService: this.stockCardService + stockCardService: this.stockCardService, + LotResource: this.LotResource }); this.vm.$onInit(); @@ -250,7 +252,7 @@ describe('PhysicalInventoryDraftController', function() { this.lineItem4, asd(this.lineItem1.orderable), asd(this.lineItem3.orderable) - ], [this.lineItem1, this.lineItem2, this.lineItem3, this.lineItem4]); + ], this.draft); }); function asd(orderable) { @@ -267,9 +269,24 @@ describe('PhysicalInventoryDraftController', function() { describe('saveDraft', function() { + it('should open confirmation modal', function() { + this.confirmService.confirmDestroy.andReturn(this.$q.resolve()); + this.draftFactory.saveDraft.andReturn(this.$q.defer().promise); + + this.vm.saveDraft(); + this.$rootScope.$apply(); + + expect(this.confirmService.confirmDestroy).toHaveBeenCalledWith( + 'stockPhysicalInventoryDraft.saveDraft', + 'stockPhysicalInventoryDraft.save' + ); + }); + it('should save draft', function() { + this.confirmService.confirmDestroy.andReturn(this.$q.resolve()); this.draftFactory.saveDraft.andReturn(this.$q.defer().promise); this.draftFactory.saveDraft.andReturn(this.$q.resolve()); + spyOn(this.LotResource.prototype, 'create'); this.vm.saveDraft(); this.$rootScope.$apply(); @@ -278,7 +295,9 @@ describe('PhysicalInventoryDraftController', function() { }); it('should cache draft', function() { - this.draftFactory.saveDraft.andReturn(this.$q.defer().promise); + this.confirmService.confirmDestroy.andReturn(this.$q.resolve()); + this.draftFactory.saveDraft.andReturn(this.$q.resolve()); + this.$rootScope.$apply(); this.vm.saveDraft(); @@ -359,7 +378,7 @@ describe('PhysicalInventoryDraftController', function() { this.$rootScope.$apply(); - expect(this.draftFactory.saveDraft).toHaveBeenCalled(); + expect(this.physicalInventoryDraftCacheService.cacheDraft).toHaveBeenCalledWith(this.draft); }); }); diff --git a/src/stock-physical-inventory/physical-inventory.factory.js b/src/stock-physical-inventory/physical-inventory.factory.js index b1425216..2a2f6762 100644 --- a/src/stock-physical-inventory/physical-inventory.factory.js +++ b/src/stock-physical-inventory/physical-inventory.factory.js @@ -217,10 +217,14 @@ function prepareLineItems(physicalInventory, summaries, draftToReturn) { var quantities = {}, extraData = {}; + var newLineItems = []; angular.forEach(physicalInventory.lineItems, function(lineItem) { quantities[identityOf(lineItem)] = lineItem.quantity; extraData[identityOf(lineItem)] = getExtraData(lineItem); + if (lineItem.$isNewItem) { + newLineItems.push(lineItem); + } }); angular.forEach(summaries, function(summary) { @@ -236,6 +240,10 @@ physicalInventory.$modified) }); }); + + angular.forEach(newLineItems, function(newLineItem) { + draftToReturn.lineItems.push(newLineItem); + }); } function identityOf(identifiable) { diff --git a/src/stock-physical-inventory/physical-inventory.factory.spec.js b/src/stock-physical-inventory/physical-inventory.factory.spec.js index c820e673..97efd985 100644 --- a/src/stock-physical-inventory/physical-inventory.factory.spec.js +++ b/src/stock-physical-inventory/physical-inventory.factory.spec.js @@ -340,6 +340,28 @@ describe('physicalInventoryFactory', function() { }); }); + it('should get proper response with new LineItem', function() { + var returnedDraft; + draft.lineItems.push({ + $isNewItem: true, + isAdded: true, + lot: { + lotCode: 'TEST', + active: true + }, + orderableId: 'orderable-1', + quantity: 100 + }); + physicalInventoryService.getPhysicalInventory.andReturn($q.when(draft)); + physicalInventoryFactory.getPhysicalInventory(id).then(function(response) { + returnedDraft = response; + }); + $rootScope.$apply(); + + expect(returnedDraft).toBeDefined(); + expect(returnedDraft.lineItems.length).toEqual(3); + }); + it('should get proper response when draft was modified', function() { var returnedDraft;