Index: src/stock-physical-inventory-draft/physical-inventory-draft-watcher.factory.js =================================================================== diff -u -N --- src/stock-physical-inventory-draft/physical-inventory-draft-watcher.factory.js (revision 3b7d95b30d47aa6eb7e36074a787e5b502e522b2) +++ src/stock-physical-inventory-draft/physical-inventory-draft-watcher.factory.js (revision 0) @@ -1,83 +0,0 @@ -/* - * This program is part of the OpenLMIS logistics management information system platform software. - * Copyright © 2017 VillageReach - * - * This program is free software: you can redistribute it and/or modify it under the terms - * of the GNU Affero General Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - *   - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  - * See the GNU Affero General Public License for more details. You should have received a copy of - * the GNU Affero General Public License along with this program. If not, see - * http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.  - */ - -(function() { - - 'use strict'; - - /** - * @ngdoc service - * @name stock-physical-inventory-draft.PhysicalInventoryDraftWatcher - * - * @description - * Provides auto-save feature to the draft. Notifies when changes are being made to the - * watched draft - this can be avoided by silencing the watcher. - */ - angular - .module('stock-physical-inventory-draft') - .factory('PhysicalInventoryDraftWatcher', factory); - - factory.$inject = ['$timeout', 'physicalInventoryDraftCacheService']; - - function factory($timeout, physicalInventoryDraftCacheService) { - - PhysicalInventoryDraftWatcher.prototype.disableWatcher = disableWatcher; - PhysicalInventoryDraftWatcher.prototype.enableWatcher = enableWatcher; - - return PhysicalInventoryDraftWatcher; - - /** - * @ngdoc method - * @methodOf stock-physical-inventory-draft.PhysicalInventoryDraftWatcher - * @name PhysicalInventoryDraftWatcher - * - * @description - * Creates physical inventory draft watcher for changes in draft line items. - * - * @param {Scope} scope scope that draft is in - * @param {Object} draft draft to set watcher on - * @return {PhysicalInventoryDraftWatcher} watcher object - */ - function PhysicalInventoryDraftWatcher(scope, draft) { - this.enabled = true; - - addWatcher(scope, draft, 'lineItems', this); - } - - function enableWatcher() { - this.enabled = true; - } - - function disableWatcher() { - this.enabled = false; - } - - function addWatcher(scope, draft, valueToWatch, watcher) { - scope.$watch(function() { - return draft[valueToWatch]; - }, function(oldValue, newValue) { - if (oldValue !== newValue && watcher.enabled) { - $timeout.cancel(watcher.syncTimeout); - watcher.syncTimeout = $timeout(function() { - draft.$modified = true; - physicalInventoryDraftCacheService.cacheDraft(draft); - watcher.syncTimeout = undefined; - }, 500); - } - }, true); - } - } - -})(); Index: src/stock-physical-inventory-draft/physical-inventory-draft-watcher.factory.spec.js =================================================================== diff -u -N --- src/stock-physical-inventory-draft/physical-inventory-draft-watcher.factory.spec.js (revision 3b7d95b30d47aa6eb7e36074a787e5b502e522b2) +++ src/stock-physical-inventory-draft/physical-inventory-draft-watcher.factory.spec.js (revision 0) @@ -1,132 +0,0 @@ -/* - * This program is part of the OpenLMIS logistics management information system platform software. - * Copyright © 2017 VillageReach - * - * This program is free software: you can redistribute it and/or modify it under the terms - * of the GNU Affero General Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - *   - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  - * See the GNU Affero General Public License for more details. You should have received a copy of - * the GNU Affero General Public License along with this program. If not, see - * http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.  - */ - -describe('PhysicalInventoryDraftWatcher', function() { - - var draftStorage; - - beforeEach(function() { - module('stock-physical-inventory-draft', function($provide) { - draftStorage = jasmine.createSpyObj('draftStorage', ['put']); - var offlineFlag = jasmine.createSpyObj('offlineDrafts', ['getAll', 'clearAll', 'put']); - offlineFlag.getAll.andReturn([false]); - var localStorageFactorySpy = jasmine.createSpy('localStorageFactory').andCallFake(function(name) { - if (name === 'offlineFlag') { - return offlineFlag; - } - return draftStorage; - }); - $provide.service('localStorageFactory', function() { - return localStorageFactorySpy; - }); - }); - - inject(function($injector) { - this.PhysicalInventoryDraftWatcher = $injector.get('PhysicalInventoryDraftWatcher'); - this.$rootScope = $injector.get('$rootScope'); - this.$timeout = $injector.get('$timeout'); - this.OrderableDataBuilder = $injector.get('OrderableDataBuilder'); - this.PhysicalInventoryDataBuilder = $injector.get('PhysicalInventoryDataBuilder'); - this.PhysicalInventoryLineItemDataBuilder = $injector.get('PhysicalInventoryLineItemDataBuilder'); - this.physicalInventoryDraftCacheService = $injector.get('physicalInventoryDraftCacheService'); - this.PhysicalInventoryLineItemAdjustmentDataBuilder = - $injector.get('PhysicalInventoryLineItemAdjustmentDataBuilder'); - }); - - spyOn(this.physicalInventoryDraftCacheService, 'cacheDraft').andCallThrough(); - this.scope = this.$rootScope.$new(); - this.draft = new this.PhysicalInventoryDataBuilder() - .withLineItems([ - new this.PhysicalInventoryLineItemDataBuilder() - .withQuantity(50) - .withOrderable(new this.OrderableDataBuilder() - .withProductCode('C100') - .build()) - .build(), - new this.PhysicalInventoryLineItemDataBuilder() - .withStockAdjustments([ - new this.PhysicalInventoryLineItemAdjustmentDataBuilder() - .withQuantity(20) - .build() - ]) - .withOrderable(new this.OrderableDataBuilder() - .withProductCode('C200') - .build()) - .build() - ]); - - new this.PhysicalInventoryDraftWatcher(this.scope, this.draft); - this.scope.$digest(); - }); - - describe('line items watcher', function() { - - it('should save draft after changes in quantity', function() { - this.draft.lineItems[0].quantity = 100; - this.scope.$digest(); - this.$timeout.flush(); - - expect(this.physicalInventoryDraftCacheService.cacheDraft).toHaveBeenCalledWith(this.draft); - }); - - it('should save draft after adding new stock adjustments', function() { - this.draft.lineItems[0].stockAdjustments = [ - new this.PhysicalInventoryLineItemAdjustmentDataBuilder() - .withQuantity(10) - .build() - ]; - this.scope.$digest(); - this.$timeout.flush(); - - expect(this.physicalInventoryDraftCacheService.cacheDraft).toHaveBeenCalledWith(this.draft); - }); - - it('should save draft after changes in stock adjustments', function() { - this.draft.lineItems[1].stockAdjustments = [ - new this.PhysicalInventoryLineItemAdjustmentDataBuilder() - .withQuantity(100) - .build() - ]; - this.scope.$digest(); - this.$timeout.flush(); - - expect(this.draft.lineItems[1].stockAdjustments.length).toEqual(1); - expect(this.physicalInventoryDraftCacheService.cacheDraft).toHaveBeenCalledWith(this.draft); - }); - - it('should save draft after adding new line items', function() { - this.draft.lineItems.push(new this.PhysicalInventoryLineItemDataBuilder() - .withQuantity(80) - .withOrderable(new this.OrderableDataBuilder() - .withProductCode('C300') - .build()) - .build()); - this.scope.$digest(); - this.$timeout.flush(); - - expect(this.draft.lineItems.length).toEqual(3); - expect(this.physicalInventoryDraftCacheService.cacheDraft).toHaveBeenCalledWith(this.draft); - }); - - it('should not save draft if quantity has not changed', function() { - this.draft.lineItems[0].quantity = 50; - this.scope.$digest(); - this.$timeout.flush(); - - expect(this.physicalInventoryDraftCacheService.cacheDraft).not.toHaveBeenCalled(); - }); - }); - -}); Index: src/stock-physical-inventory-draft/physical-inventory-draft.controller.js =================================================================== diff -u -N -r195ebb7e3a95859748b5cf91e924f034cddd1f75 -r5a33997e62d383425760afc87c10ee9d590138db --- src/stock-physical-inventory-draft/physical-inventory-draft.controller.js (.../physical-inventory-draft.controller.js) (revision 195ebb7e3a95859748b5cf91e924f034cddd1f75) +++ src/stock-physical-inventory-draft/physical-inventory-draft.controller.js (.../physical-inventory-draft.controller.js) (revision 5a33997e62d383425760afc87c10ee9d590138db) @@ -34,19 +34,18 @@ 'displayLineItemsGroup', 'confirmService', 'physicalInventoryService', 'MAX_INTEGER_VALUE', 'VVM_STATUS', 'reasons', 'stockReasonsCalculations', 'loadingModalService', '$window', 'stockmanagementUrlFactory', 'accessTokenFactory', 'orderableGroupService', '$filter', '$q', - 'offlineService', 'PhysicalInventoryDraftWatcher', 'localStorageFactory', 'physicalInventoryDraftCacheService']; + 'offlineService', 'localStorageFactory', 'physicalInventoryDraftCacheService']; function controller($scope, $state, $stateParams, addProductsModalService, messageService, physicalInventoryFactory, notificationService, alertService, chooseDateModalService, program, facility, draft, displayLineItemsGroup, confirmService, physicalInventoryService, MAX_INTEGER_VALUE, VVM_STATUS, reasons, stockReasonsCalculations, loadingModalService, $window, stockmanagementUrlFactory, accessTokenFactory, orderableGroupService, $filter, $q, - offlineService, PhysicalInventoryDraftWatcher, localStorageFactory, + offlineService, localStorageFactory, physicalInventoryDraftCacheService) { - var vm = this, - watcher = new PhysicalInventoryDraftWatcher($scope, draft, localStorageFactory('physicalInventoryDrafts')); + var vm = this; vm.$onInit = onInit; @@ -161,6 +160,17 @@ vm.draft = draft; /** + * @ngdoc property + * @propertyOf stock-physical-inventory-draft.controller:PhysicalInventoryDraftController + * @name dataChanged + * @type {boolean} + * + * @description + * A flag that changes its value when the data in the form is changed. Used by saving-indicator + */ + vm.dataChanged = false; + + /** * @ngdoc method * @methodOf stock-physical-inventory-draft.controller:PhysicalInventoryDraftController * @name getStatusDisplay @@ -188,7 +198,6 @@ .difference(_.flatten(vm.displayLineItemsGroup)) .value(); - watcher.disableWatcher(); addProductsModalService.show(notYetAddedItems, vm.hasLot).then(function() { $stateParams.program = vm.program; $stateParams.facility = vm.facility; @@ -264,7 +273,6 @@ * Save physical inventory draft. */ vm.saveDraft = function() { - watcher.disableWatcher(); loadingModalService.open(); return physicalInventoryFactory.saveDraft(draft).then(function() { notificationService.success('stockPhysicalInventoryDraft.saved'); @@ -312,7 +320,6 @@ 'stockPhysicalInventoryDraft.deleteDraft', 'stockPhysicalInventoryDraft.delete' ).then(function() { - watcher.disableWatcher(); loadingModalService.open(); physicalInventoryService.deleteDraft(draft.id).then(function() { $state.go('openlmis.stockmanagement.physicalInventory', $stateParams, { @@ -339,7 +346,6 @@ alertService.error('stockPhysicalInventoryDraft.submitInvalid'); } else { chooseDateModalService.show().then(function(resolvedData) { - watcher.disableWatcher(); loadingModalService.open(); draft.occurredDate = resolvedData.occurredDate; @@ -430,7 +436,9 @@ vm.groupedCategories = $filter('groupByProgramProductCategory')(newList, vm.program.id); }, true); - physicalInventoryDraftCacheService.cacheDraft(draft); + if (!$stateParams.noReload) { + physicalInventoryDraftCacheService.cacheDraft(draft); + } } /** @@ -446,6 +454,7 @@ function checkUnaccountedStockAdjustments(lineItem) { lineItem.unaccountedQuantity = stockReasonsCalculations.calculateUnaccounted(lineItem, lineItem.stockAdjustments); + physicalInventoryDraftCacheService.cacheDraft(draft); } /** @@ -462,6 +471,8 @@ vm.updateProgress(); vm.validateQuantity(lineItem); vm.checkUnaccountedStockAdjustments(lineItem); + vm.dataChanged = !vm.dataChanged; + physicalInventoryDraftCacheService.cacheDraft(draft); } /** Index: src/stock-physical-inventory-draft/physical-inventory-draft.controller.spec.js =================================================================== diff -u -N -r77bf6b3ef5c41fa18f08bf39f5e0dd75392b93be -r5a33997e62d383425760afc87c10ee9d590138db --- src/stock-physical-inventory-draft/physical-inventory-draft.controller.spec.js (.../physical-inventory-draft.controller.spec.js) (revision 77bf6b3ef5c41fa18f08bf39f5e0dd75392b93be) +++ src/stock-physical-inventory-draft/physical-inventory-draft.controller.spec.js (.../physical-inventory-draft.controller.spec.js) (revision 5a33997e62d383425760afc87c10ee9d590138db) @@ -45,7 +45,6 @@ this.accessTokenFactory = $injector.get('accessTokenFactory'); this.physicalInventoryService = $injector.get('physicalInventoryService'); this.confirmService = $injector.get('confirmService'); - this.PhysicalInventoryDraftWatcher = $injector.get('PhysicalInventoryDraftWatcher'); this.physicalInventoryDraftCacheService = $injector.get('physicalInventoryDraftCacheService'); this.alertService = $injector.get('alertService'); }); @@ -56,7 +55,6 @@ spyOn(this.confirmService, 'confirmDestroy'); spyOn(this.addProductsModalService, 'show'); spyOn(this.$state, 'go'); - spyOn(this.PhysicalInventoryDraftWatcher.prototype, 'disableWatcher'); spyOn(this.draftFactory, 'saveDraft'); spyOn(this.physicalInventoryDraftCacheService, 'cacheDraft'); spyOn(this.alertService, 'error'); @@ -250,15 +248,6 @@ expect(this.draftFactory.saveDraft).toHaveBeenCalledWith(this.draft); }); - it('should disable PhysicalInventoryDraftWatcher', function() { - this.draftFactory.saveDraft.andReturn(this.$q.resolve()); - - this.vm.saveDraft(); - this.$rootScope.$apply(); - - expect(this.PhysicalInventoryDraftWatcher.prototype.disableWatcher).toHaveBeenCalled(); - }); - it('should cache draft', function() { this.draftFactory.saveDraft.andReturn(this.$q.defer().promise); this.$rootScope.$apply(); @@ -365,19 +354,6 @@ expect(this.$state.go).not.toHaveBeenCalled(); }); - it('should disable PhysicalInventoryDraftWatcher', function() { - this.physicalInventoryService.submitPhysicalInventory - .andReturn(this.$q.when()); - this.confirmService.confirm.andReturn(this.$q.reject()); - - this.draft.id = 1; - - this.vm.submit(); - this.$rootScope.$apply(); - - expect(this.PhysicalInventoryDraftWatcher.prototype.disableWatcher).toHaveBeenCalled(); - }); - it('should return proper error message and remove from local storage', function() { spyOn(this.physicalInventoryDraftCacheService, 'removeById'); @@ -505,16 +481,6 @@ } ); }); - - it('should disable PhysicalInventoryDraftWatcher', function() { - this.confirmService.confirmDestroy.andReturn(this.$q.resolve()); - - this.vm.delete(); - this.$rootScope.$apply(); - - expect(this.PhysicalInventoryDraftWatcher.prototype.disableWatcher).toHaveBeenCalled(); - }); - }); }); Index: src/stock-physical-inventory-draft/physical-inventory-draft.html =================================================================== diff -u -N -r3b7d95b30d47aa6eb7e36074a787e5b502e522b2 -r5a33997e62d383425760afc87c10ee9d590138db --- src/stock-physical-inventory-draft/physical-inventory-draft.html (.../physical-inventory-draft.html) (revision 3b7d95b30d47aa6eb7e36074a787e5b502e522b2) +++ src/stock-physical-inventory-draft/physical-inventory-draft.html (.../physical-inventory-draft.html) (revision 5a33997e62d383425760afc87c10ee9d590138db) @@ -18,7 +18,7 @@ {{'stockPhysicalInventoryDraft.addProduct' | message}} - +