Index: src/stock-physical-inventory-draft/physical-inventory-draft.controller.js =================================================================== diff -u -N -red465462836390de377c1996f00b86e5955d57e8 -r2a8476e37de29041b616a2a0382dc71db10bf6de --- src/stock-physical-inventory-draft/physical-inventory-draft.controller.js (.../physical-inventory-draft.controller.js) (revision ed465462836390de377c1996f00b86e5955d57e8) +++ src/stock-physical-inventory-draft/physical-inventory-draft.controller.js (.../physical-inventory-draft.controller.js) (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -29,17 +29,17 @@ .controller('PhysicalInventoryDraftController', controller); controller.$inject = ['$scope', '$state', '$stateParams', 'addProductsModalService', - 'messageService', 'physicalInventoryDraftFactory', 'notificationService', 'alertService', + 'messageService', 'physicalInventoryFactory', 'notificationService', 'alertService', 'confirmDiscardService', 'chooseDateModalService', 'program', 'facility', 'draft', - 'displayLineItemsGroup', 'confirmService', 'physicalInventoryDraftService', 'MAX_INTEGER_VALUE', + 'displayLineItemsGroup', 'confirmService', 'physicalInventoryService', 'MAX_INTEGER_VALUE', 'VVM_STATUS', 'reasons', 'stockReasonsCalculations', 'loadingModalService', '$window', 'stockmanagementUrlFactory', 'accessTokenFactory' ]; function controller($scope, $state, $stateParams, addProductsModalService, messageService, - physicalInventoryDraftFactory, notificationService, alertService, confirmDiscardService, + physicalInventoryFactory, notificationService, alertService, confirmDiscardService, chooseDateModalService, program, facility, draft, displayLineItemsGroup, - confirmService, physicalInventoryDraftService, MAX_INTEGER_VALUE, VVM_STATUS, + confirmService, physicalInventoryService, MAX_INTEGER_VALUE, VVM_STATUS, reasons, stockReasonsCalculations, loadingModalService, $window, stockmanagementUrlFactory, accessTokenFactory) { var vm = this; @@ -197,7 +197,7 @@ */ vm.saveDraft = function () { loadingModalService.open(); - return physicalInventoryDraftFactory.saveDraft(draft).then(function () { + return physicalInventoryFactory.saveDraft(draft).then(function () { notificationService.success('stockPhysicalInventoryDraft.saved'); resetWatchItems(); @@ -223,7 +223,7 @@ confirmService.confirmDestroy('stockPhysicalInventoryDraft.deleteDraft', 'stockPhysicalInventoryDraft.delete') .then(function () { loadingModalService.open(); - physicalInventoryDraftService.delete(draft.id).then(function () { + physicalInventoryService.delete(draft.id).then(function () { $scope.needToConfirm = false; $state.go('openlmis.stockmanagement.physicalInventory', $stateParams, {reload: true}); }) @@ -252,7 +252,7 @@ draft.occurredDate = resolvedData.occurredDate; draft.signature = resolvedData.signature; - physicalInventoryDraftService.submitPhysicalInventory(draft).then(function () { + physicalInventoryService.submitPhysicalInventory(draft).then(function () { notificationService.success('stockPhysicalInventoryDraft.submitted'); confirmService.confirm('stockPhysicalInventoryDraft.printModal.label', 'stockPhysicalInventoryDraft.printModal.yes', Index: src/stock-physical-inventory-draft/physical-inventory-draft.controller.spec.js =================================================================== diff -u -N -red465462836390de377c1996f00b86e5955d57e8 -r2a8476e37de29041b616a2a0382dc71db10bf6de --- src/stock-physical-inventory-draft/physical-inventory-draft.controller.spec.js (.../physical-inventory-draft.controller.spec.js) (revision ed465462836390de377c1996f00b86e5955d57e8) +++ src/stock-physical-inventory-draft/physical-inventory-draft.controller.spec.js (.../physical-inventory-draft.controller.spec.js) (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -17,7 +17,7 @@ var vm, $q, $rootScope, scope, state, stateParams, addProductsModalService, draftFactory, chooseDateModalService, facility, program, draft, lineItem, lineItem1, lineItem2, lineItem3, - lineItem4, reasons, physicalInventoryDraftService, stockmanagementUrlFactory, + lineItem4, reasons, physicalInventoryService, stockmanagementUrlFactory, accessTokenFactory, $window, confirm; beforeEach(function() { @@ -36,9 +36,9 @@ }; addProductsModalService = $injector.get('addProductsModalService'); spyOn(addProductsModalService, 'show'); - draftFactory = $injector.get('physicalInventoryDraftFactory'); + draftFactory = $injector.get('physicalInventoryFactory'); - physicalInventoryDraftService = jasmine.createSpyObj('physicalInventoryDraftService', ['submitPhysicalInventory']); + physicalInventoryService = jasmine.createSpyObj('physicalInventoryService', ['submitPhysicalInventory']); stockmanagementUrlFactory = jasmine.createSpy(); stockmanagementUrlFactory.andCallFake(function(url) { @@ -149,7 +149,7 @@ addProductsModalService: addProductsModalService, chooseDateModalService: chooseDateModalService, reasons: reasons, - physicalInventoryDraftService: physicalInventoryDraftService, + physicalInventoryService: physicalInventoryService, stockmanagementUrlFactory: stockmanagementUrlFactory, accessTokenFactory: accessTokenFactory, confirmService: confirmService @@ -242,7 +242,7 @@ }); it('and choose "print" should open report and change state', function() { - physicalInventoryDraftService.submitPhysicalInventory + physicalInventoryService.submitPhysicalInventory .andReturn($q.when()); confirmService.confirm.andReturn($q.when()) accessTokenFactory.addAccessToken.andReturn('url') @@ -259,7 +259,7 @@ }); it('and choose "no" should change state and not open report', function() { - physicalInventoryDraftService.submitPhysicalInventory + physicalInventoryService.submitPhysicalInventory .andReturn($q.when()); confirmService.confirm.andReturn($q.reject()) accessTokenFactory.addAccessToken.andReturn('url') @@ -275,7 +275,7 @@ }); it('and service call failed should not open report and not change state', function() { - physicalInventoryDraftService.submitPhysicalInventory.andReturn($q.reject()); + physicalInventoryService.submitPhysicalInventory.andReturn($q.reject()); vm.submit(); $rootScope.$apply(); Index: src/stock-physical-inventory-draft/physical-inventory-draft.factory.js =================================================================== diff -u -N --- src/stock-physical-inventory-draft/physical-inventory-draft.factory.js (revision 5790b8885b78870ac12da46227fe830bf16dfc8b) +++ src/stock-physical-inventory-draft/physical-inventory-draft.factory.js (revision 0) @@ -1,69 +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.physicalInventoryDraftFactory - * - * @description - * Allows the user to perform some logic on draft and call draft service. - */ - angular - .module('stock-physical-inventory-draft') - .factory('physicalInventoryDraftFactory', factory); - - factory.$inject = ['physicalInventoryDraftService']; - - function factory(physicalInventoryDraftService) { - - return { - saveDraft: saveDraft - }; - - /** - * @ngdoc method - * @methodOf stock-physical-inventory-draft.physicalInventoryDraftFactory - * @name saveDraft - * - * @description - * Performs logic on physical inventory draft and calls save method from draft service. - * - * @param {draft} draft Physical Inventory Draft to be saved - * @return {Promise} Saved draft - */ - function saveDraft(draft) { - var physicalInventory = angular.copy(draft); - - physicalInventory.lineItems = []; - angular.forEach(draft.lineItems, function(item) { - physicalInventory.lineItems.push({ - orderableId: item.orderable.id, - lotId: item.lot ? item.lot.id : null, - quantity: (_.isNull(item.quantity) || _.isUndefined(item.quantity)) && item.isAdded ? -1 : item.quantity, - extraData: { - vvmStatus: item.vvmStatus - }, - stockAdjustments: item.stockAdjustments - }); - }); - - return physicalInventoryDraftService.saveDraft(physicalInventory); - } - } -})(); Index: src/stock-physical-inventory-draft/physical-inventory-draft.factory.spec.js =================================================================== diff -u -N --- src/stock-physical-inventory-draft/physical-inventory-draft.factory.spec.js (revision a0622af12cab254ed9f8d0c81c261a02307de18d) +++ src/stock-physical-inventory-draft/physical-inventory-draft.factory.spec.js (revision 0) @@ -1,103 +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('physicalInventoryDraftFactory', function() { - - var $q, $rootScope, physicalInventoryDraftService, physicalInventoryDraftFactory, - draft; - - beforeEach(function() { - module('stock-physical-inventory-draft', function($provide) { - physicalInventoryDraftService = jasmine.createSpyObj('physicalInventoryDraftService', ['saveDraft']); - $provide.factory('physicalInventoryDraftService', function() { - return physicalInventoryDraftService; - }); - }); - - inject(function($injector) { - $q = $injector.get('$q'); - $rootScope = $injector.get('$rootScope'); - physicalInventoryDraftFactory = $injector.get('physicalInventoryDraftFactory'); - }); - - draft = { - id: 'draft-1', - lineItems: [ - { - orderable: { - id: 'orderable-1' - }, - lot: { - id: 'lot-1' - }, - quantity: 3, - vvmStatus: 'STAGE_1', - isAdded: false - }, - { - orderable: { - id: 'orderable-2' - }, - quantity: null, - vvmStatus: null, - isAdded: true - } - ] - }; - - physicalInventoryDraftService.saveDraft.andCallFake(function(passedDraft) { - return $q.when(passedDraft); - }); - }); - - describe('init', function() { - it('should expose saveDraft method', function() { - expect(angular.isFunction(physicalInventoryDraftFactory.saveDraft)).toBe(true); - }); - }); - - describe('saveDraft', function() { - it('should return promise', function() { - var result = physicalInventoryDraftFactory.saveDraft(draft); - $rootScope.$apply(); - - expect(result.then).not.toBeUndefined(); - expect(angular.isFunction(result.then)).toBe(true); - }); - - it('should call physicalInventoryDraftService', function() { - physicalInventoryDraftFactory.saveDraft(draft); - expect(physicalInventoryDraftService.saveDraft).toHaveBeenCalled(); - }); - - it('should save draft with changed lineItems', function() { - var savedDraft = undefined; - - physicalInventoryDraftFactory.saveDraft(draft).then(function(response) { - savedDraft = response; - }); - $rootScope.$apply(); - - expect(savedDraft).toBeDefined(); - expect(savedDraft.id).toEqual(draft.id); - angular.forEach(savedDraft.lineItems, function(lineItem, index) { - expect(lineItem.lotId).toEqual(draft.lineItems[index].lot ? draft.lineItems[index].lot.id : null); - expect(lineItem.orderableId).toEqual(draft.lineItems[index].orderable.id); - expect(lineItem.quantity).toEqual(draft.lineItems[index].isAdded ? -1 : draft.lineItems[index].quantity); - expect(lineItem.extraData.vvmStatus).toEqual(draft.lineItems[index].vvmStatus); - }); - }); - }); -}); Index: src/stock-physical-inventory-draft/physical-inventory-draft.module.js =================================================================== diff -u -N -r5201d5c6086a145628f91a7f120470db4a375ec1 -r2a8476e37de29041b616a2a0382dc71db10bf6de --- src/stock-physical-inventory-draft/physical-inventory-draft.module.js (.../physical-inventory-draft.module.js) (revision 5201d5c6086a145628f91a7f120470db4a375ec1) +++ src/stock-physical-inventory-draft/physical-inventory-draft.module.js (.../physical-inventory-draft.module.js) (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -16,7 +16,13 @@ (function () { 'use strict'; - angular.module('stock-physical-inventory-draft', [ + /** + * @module stock-physical-inventory-list + * + * @description + * Responsible for physical inventory draft screen. + */ + angular.module('stock-physical-inventory-draft', [ 'stockmanagement', 'stock-add-products-modal', 'stock-confirm-discard', @@ -26,6 +32,7 @@ 'stock-orderable-lot-util', 'stock-constants', 'stock-reasons', - 'openlmis-auth' + 'openlmis-auth', + 'stock-physical-inventory' ]); })(); Index: src/stock-physical-inventory-draft/physical-inventory-draft.routes.js =================================================================== diff -u -N -ra0622af12cab254ed9f8d0c81c261a02307de18d -r2a8476e37de29041b616a2a0382dc71db10bf6de --- src/stock-physical-inventory-draft/physical-inventory-draft.routes.js (.../physical-inventory-draft.routes.js) (revision a0622af12cab254ed9f8d0c81c261a02307de18d) +++ src/stock-physical-inventory-draft/physical-inventory-draft.routes.js (.../physical-inventory-draft.routes.js) (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -24,7 +24,7 @@ routes.$inject = ['$stateProvider', 'STOCKMANAGEMENT_RIGHTS']; function routes($stateProvider, STOCKMANAGEMENT_RIGHTS) { - $stateProvider.state('openlmis.stockmanagement.physicalInventory.view', { + $stateProvider.state('openlmis.stockmanagement.physicalInventory.draft', { url: '/:id?keyword&page&size', views: { '@openlmis': { Index: src/stock-physical-inventory-draft/physical-inventory-draft.service.js =================================================================== diff -u -N --- src/stock-physical-inventory-draft/physical-inventory-draft.service.js (revision a0622af12cab254ed9f8d0c81c261a02307de18d) +++ src/stock-physical-inventory-draft/physical-inventory-draft.service.js (revision 0) @@ -1,147 +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.physicalInventoryDraftService - * - * @description - * Responsible for searching by keyword. - */ - angular - .module('stock-physical-inventory-draft') - .service('physicalInventoryDraftService', service); - - service.$inject = ['$filter', '$resource', 'stockmanagementUrlFactory', 'messageService', 'openlmisDateFilter', 'productNameFilter']; - - function service($filter, $resource, stockmanagementUrlFactory, messageService, openlmisDateFilter, productNameFilter) { - var resource = $resource(stockmanagementUrlFactory('/api/physicalInventories'), {}, { - save: { - method: 'PUT', - url: stockmanagementUrlFactory('/api/physicalInventories/:id') - }, - delete: { - method: 'DELETE', - url: stockmanagementUrlFactory('/api/physicalInventories/:id') - }, - submitPhysicalInventory: { - method: 'POST', - url: stockmanagementUrlFactory('/api/stockEvents') - } - }); - - this.search = search; - this.saveDraft = saveDraft; - this.delete = deleteDraft; - this.submitPhysicalInventory = submit; - - /** - * @ngdoc method - * @methodOf stock-physical-inventory-draft.physicalInventoryDraftService - * @name search - * - * @description - * Searching from given line items by keyword. - * - * @param {String} keyword keyword - * @param {Array} lineItems all line items - * @return {Array} result search result - */ - function search(keyword, lineItems) { - var result = lineItems; - var hasLot = _.any(lineItems, function(item) { - return item.lot; - }); - - if (!_.isEmpty(keyword)) { - keyword = keyword.trim(); - result = _.filter(lineItems, function (item) { - var hasStockOnHand = !(_.isNull(item.stockOnHand) || _.isUndefined(item.stockOnHand)); - var hasQuantity = !(_.isNull(item.quantity) || _.isUndefined(item.quantity)) && item.quantity !== -1; - var searchableFields = [ - item.orderable.productCode, productNameFilter(item.orderable), - hasStockOnHand ? item.stockOnHand.toString() : "", - hasQuantity ? item.quantity.toString() : "", - item.lot ? item.lot.lotCode : (hasLot? messageService.get('orderableLotUtilService.noLotDefined') : ""), - item.lot ? openlmisDateFilter(item.lot.expirationDate) : "" - ]; - return _.any(searchableFields, function (field) { - return field.toLowerCase().contains(keyword.toLowerCase()); - }); - }); - } - - return result; - } - - /** - * @ngdoc method - * @methodOf stock-physical-inventory-draft.physicalInventoryDraftService - * @name saveDraft - * - * @description - * Saves physical inventory draft. - * - * @param {Object} draft Draft that will be saved - * @return {Promise} Saved draft - */ - function saveDraft(draft) { - return resource.save({id: draft.id}, draft).$promise; - } - - function deleteDraft(id) { - return resource.delete({id: id}).$promise; - } - - /** - * @ngdoc method - * @methodOf stock-physical-inventory-draft.physicalInventoryDraftService - * @name submit - * - * @description - * Submits physical inventory draft. - * - * @param {Object} physicalInventory Draft that will be saved - * @return {Promise} Submitted Physical Inventory - */ - function submit(physicalInventory) { - var event = _.clone(physicalInventory); - delete event.id; - event.resourceId = physicalInventory.id; - event.lineItems = physicalInventory.lineItems - .filter(function (item) { - return item.isAdded; - }) - .map(function (item) { - return { - orderableId: item.orderable.id, - lotId: item.lot ? item.lot.id : null, - quantity: item.quantity, - occurredDate: $filter('isoDate')(physicalInventory.occurredDate), - extraData: { - vvmStatus: item.vvmStatus - }, - stockAdjustments: item.stockAdjustments - }; - }); - - return resource.submitPhysicalInventory(event).$promise; - } - } -})(); Index: src/stock-physical-inventory-draft/physical-inventory-draft.service.spec.js =================================================================== diff -u -N --- src/stock-physical-inventory-draft/physical-inventory-draft.service.spec.js (revision 2d3917c598d3dbb1664bbad48f6dd0dad16159b4) +++ src/stock-physical-inventory-draft/physical-inventory-draft.service.spec.js (revision 0) @@ -1,145 +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('physicalInventoryDraftService', function () { - - var lineItem1, lineItem2, lineItem3, - service, httpBackend, rootScope, stockmanagementUrlFactory, messageService; - - beforeEach(function () { - module('stock-physical-inventory-draft'); - lineItem1 = { - "isAdded": true, - "orderable": { - "id": "c9e65f02-f84f-4ba2-85f7-e2cb6f0989af", - "productCode": "C1", - "fullProductName": "Streptococcus Pneumoniae Vaccine II", - "dispensable": { - "dispensingUnit": "" - } - }, - "stockOnHand": 233, - "quantity": 3 - }; - lineItem2 = { - "isAdded": true, - "orderable": { - "id": "2400e410-b8dd-4954-b1c0-80d8a8e785fc", - "productCode": "C2", - "fullProductName": "Acetylsalicylic Acid", - "dispensable": { - "dispensingUnit": "" - } - }, - "stockOnHand": null, - "quantity": 4 - }; - lineItem3 = { - "isAdded": true, - "orderable": { - "id": "2400e410-b8dd-4954-b1c0-80d8a8e785fc", - "productCode": "C2", - "fullProductName": "Acetylsalicylic Acid", - "dispensable": { - "dispensingUnit": "" - } - }, - "lot": { - "lotCode": "L1", - "expirationDate": "2017-05-02T05:59:51.993Z" - }, - "stockOnHand": null, - "quantity": null - }; - - inject(function (_physicalInventoryDraftService_, _$httpBackend_, _$rootScope_, - _stockmanagementUrlFactory_, _messageService_) { - service = _physicalInventoryDraftService_; - httpBackend = _$httpBackend_; - rootScope = _$rootScope_; - stockmanagementUrlFactory = _stockmanagementUrlFactory_; - messageService = _messageService_; - }); - }); - - describe('search', function () { - var lineItems; - - beforeEach(function () { - lineItems = [lineItem1, lineItem2, lineItem3]; - }); - - it('should get all line items when keyword is empty', function () { - expect(service.search('', lineItems)).toEqual(lineItems); - }); - - it("should search by productCode", function () { - expect(service.search('c2', lineItems)).toEqual([lineItem2, lineItem3]); - }); - - it("should search by productFullName", function () { - expect(service.search('Streptococcus', lineItems)).toEqual([lineItem1]); - }); - - it("should search by stockOnHand", function () { - expect(service.search('233', lineItems)).toEqual([lineItem1]); - }); - - it("should search by quantity", function () { - expect(service.search('4', lineItems)).toEqual([lineItem2]); - }); - - it("should search by lotCode", function () { - expect(service.search('L1', lineItems)).toEqual([lineItem3]); - }); - - it("should get all line items without lot info", function () { - spyOn(messageService, 'get'); - messageService.get.andReturn('No lot defined'); - expect(service.search('No lot defined', lineItems)).toEqual([lineItem1, lineItem2]); - }); - - it("should search by expirationDate", function () { - expect(service.search('02/05/2017', lineItems)).toEqual([lineItem3]); - }); - }); - - it("should save physical inventory draft", function () { - var draft = {id: 123, lineItems: [lineItem1, lineItem2, lineItem3]}; - - httpBackend.when('PUT', stockmanagementUrlFactory('/api/physicalInventories/' + draft.id)) - .respond(function (method, url, data) { - return [200, data];//return whatever was passed to http backend. - }); - - var result = []; - service.saveDraft(draft).then(function (response) { - result = response; - }); - - httpBackend.flush(); - rootScope.$apply(); - - expect(result.lineItems.length).toBe(3); - expect(result.lineItems[0].quantity).toBe(3); - expect(result.lineItems[1].quantity).toBe(4); - expect(result.lineItems[2].quantity).toBe(null); - }); - - afterEach(function() { - httpBackend.verifyNoOutstandingExpectation(); - httpBackend.verifyNoOutstandingRequest(); - }); -}); Index: src/stock-physical-inventory-list/physical-inventory-list.controller.js =================================================================== diff -u -N -rbc0a350cd998163ccf8aeac9d74b36ecadfb57b2 -r2a8476e37de29041b616a2a0382dc71db10bf6de --- src/stock-physical-inventory-list/physical-inventory-list.controller.js (.../physical-inventory-list.controller.js) (revision bc0a350cd998163ccf8aeac9d74b36ecadfb57b2) +++ src/stock-physical-inventory-list/physical-inventory-list.controller.js (.../physical-inventory-list.controller.js) (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -107,15 +107,15 @@ if (!draft.id) { physicalInventoryService.createDraft(program.id, facility.id).then(function (data) { draft.id = data.id; - $state.go('openlmis.stockmanagement.physicalInventory.view', { + $state.go('openlmis.stockmanagement.physicalInventory.draft', { id: draft.id, draft: draft, program: program, facility: facility }); }); } - $state.go('openlmis.stockmanagement.physicalInventory.view', { + $state.go('openlmis.stockmanagement.physicalInventory.draft', { id: draft.id, draft: draft, program: program, Index: src/stock-physical-inventory-list/physical-inventory-list.controller.spec.js =================================================================== diff -u -N -rbc0a350cd998163ccf8aeac9d74b36ecadfb57b2 -r2a8476e37de29041b616a2a0382dc71db10bf6de --- src/stock-physical-inventory-list/physical-inventory-list.controller.spec.js (.../physical-inventory-list.controller.spec.js) (revision bc0a350cd998163ccf8aeac9d74b36ecadfb57b2) +++ src/stock-physical-inventory-list/physical-inventory-list.controller.spec.js (.../physical-inventory-list.controller.spec.js) (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -15,8 +15,7 @@ describe("PhysicalInventoryListController", function () { - var vm, q, rootScope, state, facility, programs, loadingModalService, messageService, - physicalInventoryService; + var vm, q, rootScope, state, facility, programs, messageService; beforeEach(function () { @@ -43,7 +42,7 @@ programs: programs, messageService: messageService, drafts: [{programId: '1'}, {programId: '2'}], - $state: state, + $state: state }); }); }); @@ -68,11 +67,11 @@ vm.editDraft(draft); - expect(state.go).toHaveBeenCalledWith('openlmis.stockmanagement.physicalInventory.view', { + expect(state.go).toHaveBeenCalledWith('openlmis.stockmanagement.physicalInventory.draft', { id: draft.id, draft: draft, program: {name: 'HIV', id: '1'}, - facility: facility, + facility: facility }); }); }); Index: src/stock-physical-inventory-list/physical-inventory-list.module.js =================================================================== diff -u -N -rbc0a350cd998163ccf8aeac9d74b36ecadfb57b2 -r2a8476e37de29041b616a2a0382dc71db10bf6de --- src/stock-physical-inventory-list/physical-inventory-list.module.js (.../physical-inventory-list.module.js) (revision bc0a350cd998163ccf8aeac9d74b36ecadfb57b2) +++ src/stock-physical-inventory-list/physical-inventory-list.module.js (.../physical-inventory-list.module.js) (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -29,5 +29,6 @@ 'referencedata-facility', 'referencedata-program', 'stock-card-summaries', + 'stock-physical-inventory' ]); })(); Index: src/stock-physical-inventory-list/physical-inventory.factory.js =================================================================== diff -u -N --- src/stock-physical-inventory-list/physical-inventory.factory.js (revision bc0a350cd998163ccf8aeac9d74b36ecadfb57b2) +++ src/stock-physical-inventory-list/physical-inventory.factory.js (revision 0) @@ -1,201 +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.physicalInventoryFactory - * - * @description - * Allows the user to retrieve physical inventory enhanced informations. - */ - angular - .module('stock-physical-inventory-list') - .factory('physicalInventoryFactory', factory); - - factory.$inject = [ - '$q', 'stockCardSummariesService', 'physicalInventoryService', 'SEARCH_OPTIONS', '$filter' - ]; - - function factory($q, stockCardSummariesService, physicalInventoryService, SEARCH_OPTIONS, - $filter) { - - return { - getDrafts: getDrafts, - getDraft: getDraft, - getPhysicalInventory: getPhysicalInventory - }; - - /** - * @ngdoc method - * @methodOf stock-physical-inventory.physicalInventoryFactory - * @name getDrafts - * - * @description - * Retrieves physical inventory drafts by facility and program. - * - * @param {Array} programIds An array of program UUID - * @param {String} facility Facility UUID - * @return {Promise} Physical inventories promise - */ - function getDrafts(programIds, facility) { - var promises = []; - angular.forEach(programIds, function(program) { - promises.push(getDraft(program, facility)); - }); - - return $q.all(promises); - } - - /** - * @ngdoc method - * @methodOf stock-physical-inventory.physicalInventoryFactory - * @name getDraft - * - * @description - * Retrieves physical inventory draft by facility and program. - * - * @param {String} program Program UUID - * @param {String} facility Facility UUID - * @return {Promise} Physical inventory promise - */ - function getDraft(program, facility) { - var deferred = $q.defer(); - - $q.all([ - stockCardSummariesService.getStockCardSummaries(program, facility, SEARCH_OPTIONS.INCLUDE_APPROVED_ORDERABLES), - physicalInventoryService.getDraft(program, facility) - ]).then(function(responses) { - var summaries = responses[0], - draft = responses[1], - draftToReturn = { - programId: program, - facilityId: facility, - lineItems: [] - }; - - if (draft.length === 0) { // no saved draft - angular.forEach(summaries, function(summary) { - draftToReturn.lineItems.push({ - stockOnHand: summary.stockOnHand, - lot: summary.lot, - orderable: summary.orderable, - quantity: null, - vvmStatus: null, - stockAdjustments: [] - }); - }); - - draftToReturn.isStarter = true; - } else { // draft was saved - prepareLineItems(draft[0], summaries, draftToReturn) - draftToReturn.id = draft[0].id; - } - - deferred.resolve(draftToReturn); - }, deferred.reject); - - return deferred.promise; - } - - /** - * @ngdoc method - * @methodOf stock-physical-inventory.physicalInventoryFactory - * @name getPhysicalInventory - * - * @description - * Retrieves physical inventory by id. - * - * @param {String} id Draft UUID - * @return {Promise} Physical inventory promise - */ - function getPhysicalInventory(id) { - var deferred = $q.defer(); - - physicalInventoryService.getPhysicalInventory(id).then(function (physicalInventory) { - stockCardSummariesService.getStockCardSummaries( - physicalInventory.programId, physicalInventory.facilityId, - SEARCH_OPTIONS.INCLUDE_APPROVED_ORDERABLES) - .then(function (summaries) { - var draftToReturn = { - programId: physicalInventory.programId, - facilityId: physicalInventory.facilityId, - lineItems: [] - }; - prepareLineItems(physicalInventory, summaries, draftToReturn); - draftToReturn.id = physicalInventory.id; - - deferred.resolve(draftToReturn); - - }, deferred.reject) - }, deferred.reject); - - return deferred.promise; - } - - function prepareLineItems(physicalInventory, summaries, draftToReturn) { - var quantities = {}, - extraData = {}; - - angular.forEach(physicalInventory.lineItems, function (lineItem) { - quantities[identityOfLines(lineItem)] = lineItem.quantity; - extraData[identityOfLines(lineItem)] = lineItem.extraData; - }); - - angular.forEach(summaries, function (summary) { - draftToReturn.lineItems.push({ - stockOnHand: summary.stockOnHand, - lot: summary.lot, - orderable: summary.orderable, - quantity: quantities[identityOf(summary)], - vvmStatus: extraData[identityOf(summary)] ? extraData[identityOf(summary)].vvmStatus : null, - stockAdjustments: getStockAdjustments(physicalInventory.lineItems, summary) - }); - }); - } - - function identityOfLines(identifiable) { - return identifiable.orderableId + (identifiable.lotId ? identifiable.lotId : ''); - } - - function identityOf(identifiable) { - return identifiable.orderable.id + (identifiable.lot ? identifiable.lot.id : ''); - } - - function getStockAdjustments(lineItems, summary) { - var filtered; - - if (summary.lot) { - filtered = $filter('filter')(lineItems, { - orderableId: summary.orderable.id, - lotId: summary.lot.id - }); - } else { - filtered = $filter('filter')(lineItems, function(lineItem) { - return lineItem.orderableId === summary.orderable.id && !lineItem.lotId; - }); - } - - if (filtered.length === 1) { - return filtered[0].stockAdjustments; - } - - return []; - } - } -})(); Index: src/stock-physical-inventory-list/physical-inventory.factory.spec.js =================================================================== diff -u -N --- src/stock-physical-inventory-list/physical-inventory.factory.spec.js (revision bc0a350cd998163ccf8aeac9d74b36ecadfb57b2) +++ src/stock-physical-inventory-list/physical-inventory.factory.spec.js (revision 0) @@ -1,227 +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('physicalInventoryFactory', function() { - - var $q, $rootScope, physicalInventoryService, physicalInventoryFactory, SEARCH_OPTIONS, - summaries, draft; - - beforeEach(function() { - module('stock-physical-inventory-list', function($provide) { - physicalInventoryService = jasmine.createSpyObj('physicalInventoryService', ['getDraft', 'getPhysicalInventory']); - $provide.factory('physicalInventoryService', function() { - return physicalInventoryService; - }); - - stockCardSummariesService = jasmine.createSpyObj('stockCardSummariesService', ['getStockCardSummaries']); - $provide.factory('stockCardSummariesService', function() { - return stockCardSummariesService; - }); - }); - - inject(function($injector) { - $q = $injector.get('$q'); - $rootScope = $injector.get('$rootScope'); - physicalInventoryFactory = $injector.get('physicalInventoryFactory'); - SEARCH_OPTIONS = $injector.get('SEARCH_OPTIONS'); - }); - - summaries = [ - { - stockOnHand: 1, - lot: { - id: 'lot-1', - expirationDate: '2017-06-12' - }, - orderable: { - id: 'orderable-1', - code: 'orderable-code-1', - name: 'orderable-name-1' - } - }, - { - stockOnHand: 2, - lot: { - id: 'lot-2', - expirationDate: '2016-06-12' - }, - orderable: { - id: 'orderable-2', - code: 'orderable-code-2', - name: 'orderable-name-2' - } - } - ]; - draft = { - - programId: 'program-id', - facilityId: 'facility-id', - lineItems: [ - { - quantity: 4, - extraData: { - vvmStatus: 'STAGE_1' - }, - lotId: 'lot-1', - orderableId: 'orderable-1' - }, - { - quantity: 4, - extraData: { - vvmStatus: 'STAGE_2' - }, - lotId: 'lot-2', - orderableId: 'orderable-2' - } - ], - $status: 200 - }; - - stockCardSummariesService.getStockCardSummaries.andReturn($q.when(summaries)); - physicalInventoryService.getPhysicalInventory.andReturn($q.reject()); - }); - - describe('init', function() { - it('should expose getDraft method', function() { - expect(angular.isFunction(physicalInventoryFactory.getDraft)).toBe(true); - }); - - it('should expose getDrafts method', function() { - expect(angular.isFunction(physicalInventoryFactory.getDrafts)).toBe(true); - }); - - it('should expose getPhysicalInventory method', function() { - expect(angular.isFunction(physicalInventoryFactory.getPhysicalInventory)).toBe(true); - }); - }); - - describe('getDraft', function() { - var programId, - facilityId; - - beforeEach(function() { - programId = 'program-id'; - facilityId = 'facility-id'; - }); - - it('should return promise', function() { - var result = physicalInventoryFactory.getDraft(programId, facilityId); - expect(result.then).not.toBeUndefined(); - expect(angular.isFunction(result.then)).toBe(true); - }); - - it('should call stockCardSummariesService', function() { - physicalInventoryFactory.getDraft(programId, facilityId); - expect(stockCardSummariesService.getStockCardSummaries).toHaveBeenCalledWith(programId, facilityId, SEARCH_OPTIONS.INCLUDE_APPROVED_ORDERABLES); - }); - - it('should call physicalInventoryService', function() { - physicalInventoryFactory.getDraft(programId, facilityId); - expect(physicalInventoryService.getDraft).toHaveBeenCalledWith(programId, facilityId); - }); - - it('should get proper response when draft was saved', function() { - var returnedDraft = undefined; - - physicalInventoryService.getDraft.andReturn($q.when([draft])); - - physicalInventoryFactory.getDraft(programId, facilityId).then(function(response) { - returnedDraft = response; - }); - $rootScope.$apply(); - - expect(returnedDraft).toBeDefined(); - expect(returnedDraft.programId).toEqual(programId); - expect(returnedDraft.facilityId).toEqual(facilityId); - angular.forEach(returnedDraft.lineItems, function(lineItem, index) { - expect(lineItem.stockOnHand).toEqual(summaries[index].stockOnHand); - expect(lineItem.lot).toEqual(summaries[index].lot); - expect(lineItem.orderable).toEqual(summaries[index].orderable); - expect(lineItem.quantity).toEqual(draft.lineItems[index].quantity); - expect(lineItem.vvmStatus).toEqual(draft.lineItems[index].extraData.vvmStatus); - }); - }); - - it('should get proper response when draft was not saved', function() { - var returnedDraft = undefined; - - physicalInventoryService.getDraft.andReturn($q.when([])); - - physicalInventoryFactory.getDraft(programId, facilityId).then(function(response) { - returnedDraft = response; - }); - $rootScope.$apply(); - - expect(returnedDraft).toBeDefined(); - expect(returnedDraft.programId).toEqual(programId); - expect(returnedDraft.facilityId).toEqual(facilityId); - angular.forEach(returnedDraft.lineItems, function(lineItem, index) { - expect(lineItem.stockOnHand).toEqual(summaries[index].stockOnHand); - expect(lineItem.lot).toEqual(summaries[index].lot); - expect(lineItem.orderable).toEqual(summaries[index].orderable); - expect(lineItem.quantity).toEqual(summaries[index].quantity); - expect(lineItem.vvmStauts).toEqual(null); - }); - }); - }); - - describe('getPhysicalInventory', function() { - var id; - - beforeEach(function () { - id = 'some-id'; - }); - - it('should return promise', function() { - var result = physicalInventoryFactory.getPhysicalInventory(id); - expect(result.then).not.toBeUndefined(); - expect(angular.isFunction(result.then)).toBe(true); - }); - - it('should call stockCardSummariesService after resolve physicalInventoryService.getPhysicalInventory', function() { - physicalInventoryService.getPhysicalInventory.andReturn($q.when(draft)); - physicalInventoryFactory.getPhysicalInventory(id); - $rootScope.$apply(); - expect(stockCardSummariesService.getStockCardSummaries).toHaveBeenCalledWith(draft.programId, draft.facilityId, SEARCH_OPTIONS.INCLUDE_APPROVED_ORDERABLES); - }); - - it('should call physicalInventoryService', function() { - physicalInventoryFactory.getPhysicalInventory(id); - expect(physicalInventoryService.getPhysicalInventory).toHaveBeenCalledWith(id); - }); - - it('should get proper response', function() { - var returnedDraft = undefined; - - physicalInventoryService.getPhysicalInventory.andReturn($q.when(draft)); - - physicalInventoryFactory.getPhysicalInventory(id).then(function(response) { - returnedDraft = response; - }); - $rootScope.$apply(); - - expect(returnedDraft).toBeDefined(); - expect(returnedDraft.programId).toEqual(draft.programId); - expect(returnedDraft.facilityId).toEqual(draft.facilityId); - angular.forEach(returnedDraft.lineItems, function(lineItem, index) { - expect(lineItem.stockOnHand).toEqual(summaries[index].stockOnHand); - expect(lineItem.lot).toEqual(summaries[index].lot); - expect(lineItem.orderable).toEqual(summaries[index].orderable); - expect(lineItem.quantity).toEqual(draft.lineItems[index].quantity); - expect(lineItem.vvmStatus).toEqual(draft.lineItems[index].extraData.vvmStatus); - }); - }); - }); -}); Index: src/stock-physical-inventory-list/physical-inventory.service.js =================================================================== diff -u -N --- src/stock-physical-inventory-list/physical-inventory.service.js (revision bc0a350cd998163ccf8aeac9d74b36ecadfb57b2) +++ src/stock-physical-inventory-list/physical-inventory.service.js (revision 0) @@ -1,92 +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.physicalInventoryService - * - * @description - * Responsible for retrieving physical inventory information from server. - */ - angular - .module('stock-physical-inventory-list') - .service('physicalInventoryService', service); - - service.$inject = ['$resource', 'stockmanagementUrlFactory']; - - function service($resource, stockmanagementUrlFactory) { - var resource = $resource(stockmanagementUrlFactory('/api/physicalInventories'), {}, { - get: { - method: 'GET', - url: stockmanagementUrlFactory('/api/physicalInventories/:id') - } - }); - - this.getDraft = getDraft; - this.createDraft = createDraft; - this.getPhysicalInventory = getPhysicalInventory; - - /** - * @ngdoc method - * @methodOf stock-physical-inventory.physicalInventoryService - * @name getDraft - * - * @description - * Retrieves physical inventory draft by facility and program from server. - * - * @param {String} program Program UUID - * @param {String} facility Facility UUID - * @return {Promise} physical inventory promise - */ - function getDraft(program, facility) { - return resource.query({program: program, facility: facility, isDraft: true}).$promise; - } - - /** - * @ngdoc method - * @methodOf stock-physical-inventory.physicalInventoryService - * @name getPhysicalInventory - * - * @description - * Retrieves physical inventory by id from server. - * - * @param {String} id physical inventory UUID - * @return {Promise} physical inventory promise - */ - function getPhysicalInventory(id) { - return resource.get({id: id}).$promise; - } - - /** - * @ngdoc method - * @methodOf stock-physical-inventory.physicalInventoryService - * @name createDraft - * - * @description - * Creates physical inventory draft by facility and program from server. - * - * @param {String} program Program UUID - * @param {String} facility Facility UUID - * @return {Promise} physical inventory promise - */ - function createDraft(program, facility) { - return resource.save({programId: program, facilityId: facility}).$promise; - } - } -})(); Index: src/stock-physical-inventory-list/physical-inventory.service.spec.js =================================================================== diff -u -N --- src/stock-physical-inventory-list/physical-inventory.service.spec.js (revision bc0a350cd998163ccf8aeac9d74b36ecadfb57b2) +++ src/stock-physical-inventory-list/physical-inventory.service.spec.js (revision 0) @@ -1,93 +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('physicalInventoryService', function() { - - var $rootScope, $httpBackend, physicalInventoryService, stockmanagementUrlFactory; - - beforeEach(function() { - module('stock-physical-inventory-list'); - - inject(function($injector) { - $httpBackend = $injector.get('$httpBackend'); - $rootScope = $injector.get('$rootScope'); - stockmanagementUrlFactory = $injector.get('stockmanagementUrlFactory'); - physicalInventoryService = $injector.get('physicalInventoryService'); - }); - }); - - it('should get draft', function () { - var result, - facilityId = '2'; - draft = {programId: '1'}; - - $httpBackend.when('GET', stockmanagementUrlFactory('/api/physicalInventories?program=' + draft.programId + - '&facility=' + facilityId + '&isDraft=true')).respond(200, [draft]); - - physicalInventoryService.getDraft(draft.programId, facilityId).then(function(response) { - result = response; - }); - - $httpBackend.flush(); - $rootScope.$apply(); - - expect(result[0].programId).toBe(draft.programId); - }); - - it('should get physical inventory', function () { - var result, - physicalInventory = {id: '1'}; - - $httpBackend.when('GET', stockmanagementUrlFactory('/api/physicalInventories/' + physicalInventory.id)) - .respond(200, physicalInventory); - - physicalInventoryService.getPhysicalInventory(physicalInventory.id).then(function(response) { - result = response; - }); - - $httpBackend.flush(); - $rootScope.$apply(); - - expect(result.id).toBe(physicalInventory.id); - }); - - it('should create new draft', function () { - var result, - draft = { - facilityId: '2', - programId: '1' - }; - - $httpBackend.when('POST', stockmanagementUrlFactory('/api/physicalInventories')) - .respond(function (method, url, data) { - return [201, data];//return whatever was passed to http backend. - }); - - physicalInventoryService.createDraft(draft.programId, draft.facilityId).then(function(response) { - result = response; - }); - - $httpBackend.flush(); - $rootScope.$apply(); - - expect(result.programId).toBe(draft.programId); - expect(result.facilityId).toBe(draft.facilityId); - }); - - afterEach(function() { - $httpBackend.verifyNoOutstandingExpectation(); - $httpBackend.verifyNoOutstandingRequest(); - }); -}); Index: src/stock-physical-inventory/messages_en.json =================================================================== diff -u -N --- src/stock-physical-inventory/messages_en.json (revision 0) +++ src/stock-physical-inventory/messages_en.json (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -0,0 +1,13 @@ +{ + "stockPhysicalInventory.stockManagement": "Stock Management", + "stockPhysicalInventory.physicalInventory": "Physical inventory", + "stockPhysicalInventory.title": "Physical inventory for ${facility}", + "stockPhysicalInventory.noPhysicalInventoryFound": "No physical inventory found.", + "stockPhysicalInventory.program": "Program", + "stockPhysicalInventory.status": "Status", + "stockPhysicalInventory.actions": "Actions", + "stockPhysicalInventory.start": "Start", + "stockPhysicalInventory.continue": "Continue", + "stockPhysicalInventory.notStarted": "Not yet started", + "stockPhysicalInventory.draft": "Draft" +} Index: src/stock-physical-inventory/physical-inventory-draft.factory.spec.js =================================================================== diff -u -N --- src/stock-physical-inventory/physical-inventory-draft.factory.spec.js (revision 0) +++ src/stock-physical-inventory/physical-inventory-draft.factory.spec.js (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -0,0 +1,103 @@ +/* + * 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('physicalInventoryDraftFactory', function() { + + var $q, $rootScope, physicalInventoryService, physicalInventoryFactory, + draft; + + beforeEach(function() { + module('stock-physical-inventory', function($provide) { + physicalInventoryService = jasmine.createSpyObj('physicalInventoryService', ['saveDraft']); + $provide.factory('physicalInventoryService', function() { + return physicalInventoryService; + }); + }); + + inject(function($injector) { + $q = $injector.get('$q'); + $rootScope = $injector.get('$rootScope'); + physicalInventoryFactory = $injector.get('physicalInventoryFactory'); + }); + + draft = { + id: 'draft-1', + lineItems: [ + { + orderable: { + id: 'orderable-1' + }, + lot: { + id: 'lot-1' + }, + quantity: 3, + vvmStatus: 'STAGE_1', + isAdded: false + }, + { + orderable: { + id: 'orderable-2' + }, + quantity: null, + vvmStatus: null, + isAdded: true + } + ] + }; + + physicalInventoryService.saveDraft.andCallFake(function(passedDraft) { + return $q.when(passedDraft); + }); + }); + + describe('init', function() { + it('should expose saveDraft method', function() { + expect(angular.isFunction(physicalInventoryFactory.saveDraft)).toBe(true); + }); + }); + + describe('saveDraft', function() { + it('should return promise', function() { + var result = physicalInventoryFactory.saveDraft(draft); + $rootScope.$apply(); + + expect(result.then).not.toBeUndefined(); + expect(angular.isFunction(result.then)).toBe(true); + }); + + it('should call physicalInventoryService', function() { + physicalInventoryFactory.saveDraft(draft); + expect(physicalInventoryService.saveDraft).toHaveBeenCalled(); + }); + + it('should save draft with changed lineItems', function() { + var savedDraft = undefined; + + physicalInventoryFactory.saveDraft(draft).then(function(response) { + savedDraft = response; + }); + $rootScope.$apply(); + + expect(savedDraft).toBeDefined(); + expect(savedDraft.id).toEqual(draft.id); + angular.forEach(savedDraft.lineItems, function(lineItem, index) { + expect(lineItem.lotId).toEqual(draft.lineItems[index].lot ? draft.lineItems[index].lot.id : null); + expect(lineItem.orderableId).toEqual(draft.lineItems[index].orderable.id); + expect(lineItem.quantity).toEqual(draft.lineItems[index].isAdded ? -1 : draft.lineItems[index].quantity); + expect(lineItem.extraData.vvmStatus).toEqual(draft.lineItems[index].vvmStatus); + }); + }); + }); +}); Index: src/stock-physical-inventory/physical-inventory-draft.service.spec.js =================================================================== diff -u -N --- src/stock-physical-inventory/physical-inventory-draft.service.spec.js (revision 0) +++ src/stock-physical-inventory/physical-inventory-draft.service.spec.js (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -0,0 +1,145 @@ +/* + * 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('physicalInventoryDraftService', function () { + + var lineItem1, lineItem2, lineItem3, + service, httpBackend, rootScope, stockmanagementUrlFactory, messageService; + + beforeEach(function () { + module('stock-physical-inventory'); + lineItem1 = { + "isAdded": true, + "orderable": { + "id": "c9e65f02-f84f-4ba2-85f7-e2cb6f0989af", + "productCode": "C1", + "fullProductName": "Streptococcus Pneumoniae Vaccine II", + "dispensable": { + "dispensingUnit": "" + } + }, + "stockOnHand": 233, + "quantity": 3 + }; + lineItem2 = { + "isAdded": true, + "orderable": { + "id": "2400e410-b8dd-4954-b1c0-80d8a8e785fc", + "productCode": "C2", + "fullProductName": "Acetylsalicylic Acid", + "dispensable": { + "dispensingUnit": "" + } + }, + "stockOnHand": null, + "quantity": 4 + }; + lineItem3 = { + "isAdded": true, + "orderable": { + "id": "2400e410-b8dd-4954-b1c0-80d8a8e785fc", + "productCode": "C2", + "fullProductName": "Acetylsalicylic Acid", + "dispensable": { + "dispensingUnit": "" + } + }, + "lot": { + "lotCode": "L1", + "expirationDate": "2017-05-02T05:59:51.993Z" + }, + "stockOnHand": null, + "quantity": null + }; + + inject(function (_physicalInventoryService_, _$httpBackend_, _$rootScope_, + _stockmanagementUrlFactory_, _messageService_) { + service = _physicalInventoryService_; + httpBackend = _$httpBackend_; + rootScope = _$rootScope_; + stockmanagementUrlFactory = _stockmanagementUrlFactory_; + messageService = _messageService_; + }); + }); + + describe('search', function () { + var lineItems; + + beforeEach(function () { + lineItems = [lineItem1, lineItem2, lineItem3]; + }); + + it('should get all line items when keyword is empty', function () { + expect(service.search('', lineItems)).toEqual(lineItems); + }); + + it("should search by productCode", function () { + expect(service.search('c2', lineItems)).toEqual([lineItem2, lineItem3]); + }); + + it("should search by productFullName", function () { + expect(service.search('Streptococcus', lineItems)).toEqual([lineItem1]); + }); + + it("should search by stockOnHand", function () { + expect(service.search('233', lineItems)).toEqual([lineItem1]); + }); + + it("should search by quantity", function () { + expect(service.search('4', lineItems)).toEqual([lineItem2]); + }); + + it("should search by lotCode", function () { + expect(service.search('L1', lineItems)).toEqual([lineItem3]); + }); + + it("should get all line items without lot info", function () { + spyOn(messageService, 'get'); + messageService.get.andReturn('No lot defined'); + expect(service.search('No lot defined', lineItems)).toEqual([lineItem1, lineItem2]); + }); + + it("should search by expirationDate", function () { + expect(service.search('02/05/2017', lineItems)).toEqual([lineItem3]); + }); + }); + + it("should save physical inventory draft", function () { + var draft = {id: 123, lineItems: [lineItem1, lineItem2, lineItem3]}; + + httpBackend.when('PUT', stockmanagementUrlFactory('/api/physicalInventories/' + draft.id)) + .respond(function (method, url, data) { + return [200, data];//return whatever was passed to http backend. + }); + + var result = []; + service.saveDraft(draft).then(function (response) { + result = response; + }); + + httpBackend.flush(); + rootScope.$apply(); + + expect(result.lineItems.length).toBe(3); + expect(result.lineItems[0].quantity).toBe(3); + expect(result.lineItems[1].quantity).toBe(4); + expect(result.lineItems[2].quantity).toBe(null); + }); + + afterEach(function() { + httpBackend.verifyNoOutstandingExpectation(); + httpBackend.verifyNoOutstandingRequest(); + }); +}); Index: src/stock-physical-inventory/physical-inventory.factory.js =================================================================== diff -u -N --- src/stock-physical-inventory/physical-inventory.factory.js (revision 0) +++ src/stock-physical-inventory/physical-inventory.factory.js (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -0,0 +1,232 @@ +/* + * 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.physicalInventoryFactory + * + * @description + * Allows the user to retrieve physical inventory enhanced informations. + */ + angular + .module('stock-physical-inventory') + .factory('physicalInventoryFactory', factory); + + factory.$inject = [ + '$q', 'stockCardSummariesService', 'physicalInventoryService', 'SEARCH_OPTIONS', '$filter' + ]; + + function factory($q, stockCardSummariesService, physicalInventoryService, SEARCH_OPTIONS, + $filter) { + + return { + getDrafts: getDrafts, + getDraft: getDraft, + getPhysicalInventory: getPhysicalInventory, + saveDraft: saveDraft + }; + + /** + * @ngdoc method + * @methodOf stock-physical-inventory.physicalInventoryFactory + * @name getDrafts + * + * @description + * Retrieves physical inventory drafts by facility and program. + * + * @param {Array} programIds An array of program UUID + * @param {String} facility Facility UUID + * @return {Promise} Physical inventories promise + */ + function getDrafts(programIds, facility) { + var promises = []; + angular.forEach(programIds, function(program) { + promises.push(getDraft(program, facility)); + }); + + return $q.all(promises); + } + + /** + * @ngdoc method + * @methodOf stock-physical-inventory.physicalInventoryFactory + * @name getDraft + * + * @description + * Retrieves physical inventory draft by facility and program. + * + * @param {String} program Program UUID + * @param {String} facility Facility UUID + * @return {Promise} Physical inventory promise + */ + function getDraft(program, facility) { + var deferred = $q.defer(); + + $q.all([ + stockCardSummariesService.getStockCardSummaries(program, facility, SEARCH_OPTIONS.INCLUDE_APPROVED_ORDERABLES), + physicalInventoryService.getDraft(program, facility) + ]).then(function(responses) { + var summaries = responses[0], + draft = responses[1], + draftToReturn = { + programId: program, + facilityId: facility, + lineItems: [] + }; + + if (draft.length === 0) { // no saved draft + angular.forEach(summaries, function(summary) { + draftToReturn.lineItems.push({ + stockOnHand: summary.stockOnHand, + lot: summary.lot, + orderable: summary.orderable, + quantity: null, + vvmStatus: null, + stockAdjustments: [] + }); + }); + + draftToReturn.isStarter = true; + } else { // draft was saved + prepareLineItems(draft[0], summaries, draftToReturn) + draftToReturn.id = draft[0].id; + } + + deferred.resolve(draftToReturn); + }, deferred.reject); + + return deferred.promise; + } + + /** + * @ngdoc method + * @methodOf stock-physical-inventory.physicalInventoryFactory + * @name getPhysicalInventory + * + * @description + * Retrieves physical inventory by id. + * + * @param {String} id Draft UUID + * @return {Promise} Physical inventory promise + */ + function getPhysicalInventory(id) { + var deferred = $q.defer(); + + physicalInventoryService.getPhysicalInventory(id).then(function (physicalInventory) { + stockCardSummariesService.getStockCardSummaries( + physicalInventory.programId, physicalInventory.facilityId, + SEARCH_OPTIONS.INCLUDE_APPROVED_ORDERABLES) + .then(function (summaries) { + var draftToReturn = { + programId: physicalInventory.programId, + facilityId: physicalInventory.facilityId, + lineItems: [] + }; + prepareLineItems(physicalInventory, summaries, draftToReturn); + draftToReturn.id = physicalInventory.id; + + deferred.resolve(draftToReturn); + + }, deferred.reject) + }, deferred.reject); + + return deferred.promise; + } + + /** + * @ngdoc method + * @methodOf stock-physical-inventory.physicalInventoryFactory + * @name saveDraft + * + * @description + * Performs logic on physical inventory draft and calls save method from draft service. + * + * @param {draft} draft Physical Inventory Draft to be saved + * @return {Promise} Saved draft + */ + function saveDraft(draft) { + var physicalInventory = angular.copy(draft); + + physicalInventory.lineItems = []; + angular.forEach(draft.lineItems, function(item) { + physicalInventory.lineItems.push({ + orderableId: item.orderable.id, + lotId: item.lot ? item.lot.id : null, + quantity: (_.isNull(item.quantity) || _.isUndefined(item.quantity)) && item.isAdded ? -1 : item.quantity, + extraData: { + vvmStatus: item.vvmStatus + }, + stockAdjustments: item.stockAdjustments + }); + }); + + return physicalInventoryService.saveDraft(physicalInventory); + } + + function prepareLineItems(physicalInventory, summaries, draftToReturn) { + var quantities = {}, + extraData = {}; + + angular.forEach(physicalInventory.lineItems, function (lineItem) { + quantities[identityOfLines(lineItem)] = lineItem.quantity; + extraData[identityOfLines(lineItem)] = lineItem.extraData; + }); + + angular.forEach(summaries, function (summary) { + draftToReturn.lineItems.push({ + stockOnHand: summary.stockOnHand, + lot: summary.lot, + orderable: summary.orderable, + quantity: quantities[identityOf(summary)], + vvmStatus: extraData[identityOf(summary)] ? extraData[identityOf(summary)].vvmStatus : null, + stockAdjustments: getStockAdjustments(physicalInventory.lineItems, summary) + }); + }); + } + + function identityOfLines(identifiable) { + return identifiable.orderableId + (identifiable.lotId ? identifiable.lotId : ''); + } + + function identityOf(identifiable) { + return identifiable.orderable.id + (identifiable.lot ? identifiable.lot.id : ''); + } + + function getStockAdjustments(lineItems, summary) { + var filtered; + + if (summary.lot) { + filtered = $filter('filter')(lineItems, { + orderableId: summary.orderable.id, + lotId: summary.lot.id + }); + } else { + filtered = $filter('filter')(lineItems, function(lineItem) { + return lineItem.orderableId === summary.orderable.id && !lineItem.lotId; + }); + } + + if (filtered.length === 1) { + return filtered[0].stockAdjustments; + } + + return []; + } + } +})(); Index: src/stock-physical-inventory/physical-inventory.factory.spec.js =================================================================== diff -u -N --- src/stock-physical-inventory/physical-inventory.factory.spec.js (revision 0) +++ src/stock-physical-inventory/physical-inventory.factory.spec.js (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -0,0 +1,227 @@ +/* + * 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('physicalInventoryFactory', function() { + + var $q, $rootScope, physicalInventoryService, physicalInventoryFactory, SEARCH_OPTIONS, + summaries, draft; + + beforeEach(function() { + module('stock-physical-inventory', function($provide) { + physicalInventoryService = jasmine.createSpyObj('physicalInventoryService', ['getDraft', 'getPhysicalInventory']); + $provide.factory('physicalInventoryService', function() { + return physicalInventoryService; + }); + + stockCardSummariesService = jasmine.createSpyObj('stockCardSummariesService', ['getStockCardSummaries']); + $provide.factory('stockCardSummariesService', function() { + return stockCardSummariesService; + }); + }); + + inject(function($injector) { + $q = $injector.get('$q'); + $rootScope = $injector.get('$rootScope'); + physicalInventoryFactory = $injector.get('physicalInventoryFactory'); + SEARCH_OPTIONS = $injector.get('SEARCH_OPTIONS'); + }); + + summaries = [ + { + stockOnHand: 1, + lot: { + id: 'lot-1', + expirationDate: '2017-06-12' + }, + orderable: { + id: 'orderable-1', + code: 'orderable-code-1', + name: 'orderable-name-1' + } + }, + { + stockOnHand: 2, + lot: { + id: 'lot-2', + expirationDate: '2016-06-12' + }, + orderable: { + id: 'orderable-2', + code: 'orderable-code-2', + name: 'orderable-name-2' + } + } + ]; + draft = { + + programId: 'program-id', + facilityId: 'facility-id', + lineItems: [ + { + quantity: 4, + extraData: { + vvmStatus: 'STAGE_1' + }, + lotId: 'lot-1', + orderableId: 'orderable-1' + }, + { + quantity: 4, + extraData: { + vvmStatus: 'STAGE_2' + }, + lotId: 'lot-2', + orderableId: 'orderable-2' + } + ], + $status: 200 + }; + + stockCardSummariesService.getStockCardSummaries.andReturn($q.when(summaries)); + physicalInventoryService.getPhysicalInventory.andReturn($q.reject()); + }); + + describe('init', function() { + it('should expose getDraft method', function() { + expect(angular.isFunction(physicalInventoryFactory.getDraft)).toBe(true); + }); + + it('should expose getDrafts method', function() { + expect(angular.isFunction(physicalInventoryFactory.getDrafts)).toBe(true); + }); + + it('should expose getPhysicalInventory method', function() { + expect(angular.isFunction(physicalInventoryFactory.getPhysicalInventory)).toBe(true); + }); + }); + + describe('getDraft', function() { + var programId, + facilityId; + + beforeEach(function() { + programId = 'program-id'; + facilityId = 'facility-id'; + }); + + it('should return promise', function() { + var result = physicalInventoryFactory.getDraft(programId, facilityId); + expect(result.then).not.toBeUndefined(); + expect(angular.isFunction(result.then)).toBe(true); + }); + + it('should call stockCardSummariesService', function() { + physicalInventoryFactory.getDraft(programId, facilityId); + expect(stockCardSummariesService.getStockCardSummaries).toHaveBeenCalledWith(programId, facilityId, SEARCH_OPTIONS.INCLUDE_APPROVED_ORDERABLES); + }); + + it('should call physicalInventoryService', function() { + physicalInventoryFactory.getDraft(programId, facilityId); + expect(physicalInventoryService.getDraft).toHaveBeenCalledWith(programId, facilityId); + }); + + it('should get proper response when draft was saved', function() { + var returnedDraft = undefined; + + physicalInventoryService.getDraft.andReturn($q.when([draft])); + + physicalInventoryFactory.getDraft(programId, facilityId).then(function(response) { + returnedDraft = response; + }); + $rootScope.$apply(); + + expect(returnedDraft).toBeDefined(); + expect(returnedDraft.programId).toEqual(programId); + expect(returnedDraft.facilityId).toEqual(facilityId); + angular.forEach(returnedDraft.lineItems, function(lineItem, index) { + expect(lineItem.stockOnHand).toEqual(summaries[index].stockOnHand); + expect(lineItem.lot).toEqual(summaries[index].lot); + expect(lineItem.orderable).toEqual(summaries[index].orderable); + expect(lineItem.quantity).toEqual(draft.lineItems[index].quantity); + expect(lineItem.vvmStatus).toEqual(draft.lineItems[index].extraData.vvmStatus); + }); + }); + + it('should get proper response when draft was not saved', function() { + var returnedDraft = undefined; + + physicalInventoryService.getDraft.andReturn($q.when([])); + + physicalInventoryFactory.getDraft(programId, facilityId).then(function(response) { + returnedDraft = response; + }); + $rootScope.$apply(); + + expect(returnedDraft).toBeDefined(); + expect(returnedDraft.programId).toEqual(programId); + expect(returnedDraft.facilityId).toEqual(facilityId); + angular.forEach(returnedDraft.lineItems, function(lineItem, index) { + expect(lineItem.stockOnHand).toEqual(summaries[index].stockOnHand); + expect(lineItem.lot).toEqual(summaries[index].lot); + expect(lineItem.orderable).toEqual(summaries[index].orderable); + expect(lineItem.quantity).toEqual(summaries[index].quantity); + expect(lineItem.vvmStauts).toEqual(null); + }); + }); + }); + + describe('getPhysicalInventory', function() { + var id; + + beforeEach(function () { + id = 'some-id'; + }); + + it('should return promise', function() { + var result = physicalInventoryFactory.getPhysicalInventory(id); + expect(result.then).not.toBeUndefined(); + expect(angular.isFunction(result.then)).toBe(true); + }); + + it('should call stockCardSummariesService after resolve physicalInventoryService.getPhysicalInventory', function() { + physicalInventoryService.getPhysicalInventory.andReturn($q.when(draft)); + physicalInventoryFactory.getPhysicalInventory(id); + $rootScope.$apply(); + expect(stockCardSummariesService.getStockCardSummaries).toHaveBeenCalledWith(draft.programId, draft.facilityId, SEARCH_OPTIONS.INCLUDE_APPROVED_ORDERABLES); + }); + + it('should call physicalInventoryService', function() { + physicalInventoryFactory.getPhysicalInventory(id); + expect(physicalInventoryService.getPhysicalInventory).toHaveBeenCalledWith(id); + }); + + it('should get proper response', function() { + var returnedDraft = undefined; + + physicalInventoryService.getPhysicalInventory.andReturn($q.when(draft)); + + physicalInventoryFactory.getPhysicalInventory(id).then(function(response) { + returnedDraft = response; + }); + $rootScope.$apply(); + + expect(returnedDraft).toBeDefined(); + expect(returnedDraft.programId).toEqual(draft.programId); + expect(returnedDraft.facilityId).toEqual(draft.facilityId); + angular.forEach(returnedDraft.lineItems, function(lineItem, index) { + expect(lineItem.stockOnHand).toEqual(summaries[index].stockOnHand); + expect(lineItem.lot).toEqual(summaries[index].lot); + expect(lineItem.orderable).toEqual(summaries[index].orderable); + expect(lineItem.quantity).toEqual(draft.lineItems[index].quantity); + expect(lineItem.vvmStatus).toEqual(draft.lineItems[index].extraData.vvmStatus); + }); + }); + }); +}); Index: src/stock-physical-inventory/physical-inventory.module.js =================================================================== diff -u -N --- src/stock-physical-inventory/physical-inventory.module.js (revision 0) +++ src/stock-physical-inventory/physical-inventory.module.js (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -0,0 +1,34 @@ +/* + * 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'; + + + /** + * @module stock-physical-inventory + * + * @description + * Main physical inventory module. + */ + angular.module('stock-physical-inventory', [ + 'stockmanagement', + 'stock-program-util', + 'referencedata-facility', + 'referencedata-program', + 'stock-card-summaries', + 'stock-product-name' + ]); +})(); Index: src/stock-physical-inventory/physical-inventory.service.js =================================================================== diff -u -N --- src/stock-physical-inventory/physical-inventory.service.js (revision 0) +++ src/stock-physical-inventory/physical-inventory.service.js (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -0,0 +1,213 @@ +/* + * 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.physicalInventoryService + * + * @description + * Responsible for retrieving physical inventory information from server. + */ + angular + .module('stock-physical-inventory') + .service('physicalInventoryService', service); + + service.$inject = ['$resource', 'stockmanagementUrlFactory', '$filter', 'messageService', 'openlmisDateFilter', 'productNameFilter']; + + function service($resource, stockmanagementUrlFactory, $filter, messageService, openlmisDateFilter, productNameFilter) { + var resource = $resource(stockmanagementUrlFactory('/api/physicalInventories'), {}, { + get: { + method: 'GET', + url: stockmanagementUrlFactory('/api/physicalInventories/:id') + }, + update: { + method: 'PUT', + url: stockmanagementUrlFactory('/api/physicalInventories/:id') + }, + delete: { + method: 'DELETE', + url: stockmanagementUrlFactory('/api/physicalInventories/:id') + }, + submitPhysicalInventory: { + method: 'POST', + url: stockmanagementUrlFactory('/api/stockEvents') + } + }); + + this.getDraft = getDraft; + this.createDraft = createDraft; + this.getPhysicalInventory = getPhysicalInventory; + this.search = search; + this.saveDraft = saveDraft; + this.delete = deleteDraft; + this.submitPhysicalInventory = submit; + + /** + * @ngdoc method + * @methodOf stock-physical-inventory.physicalInventoryService + * @name getDraft + * + * @description + * Retrieves physical inventory draft by facility and program from server. + * + * @param {String} program Program UUID + * @param {String} facility Facility UUID + * @return {Promise} physical inventory promise + */ + function getDraft(program, facility) { + return resource.query({program: program, facility: facility, isDraft: true}).$promise; + } + + /** + * @ngdoc method + * @methodOf stock-physical-inventory.physicalInventoryService + * @name getPhysicalInventory + * + * @description + * Retrieves physical inventory by id from server. + * + * @param {String} id physical inventory UUID + * @return {Promise} physical inventory promise + */ + function getPhysicalInventory(id) { + return resource.get({id: id}).$promise; + } + + /** + * @ngdoc method + * @methodOf stock-physical-inventory.physicalInventoryService + * @name createDraft + * + * @description + * Creates physical inventory draft by facility and program from server. + * + * @param {String} program Program UUID + * @param {String} facility Facility UUID + * @return {Promise} physical inventory promise + */ + function createDraft(program, facility) { + return resource.save({programId: program, facilityId: facility}).$promise; + } + + /** + * @ngdoc method + * @methodOf stock-physical-inventory.physicalInventoryService + * @name search + * + * @description + * Searching from given line items by keyword. + * + * @param {String} keyword keyword + * @param {Array} lineItems all line items + * @return {Array} result search result + */ + function search(keyword, lineItems) { + var result = lineItems; + var hasLot = _.any(lineItems, function(item) { + return item.lot; + }); + + if (!_.isEmpty(keyword)) { + keyword = keyword.trim(); + result = _.filter(lineItems, function (item) { + var hasStockOnHand = !(_.isNull(item.stockOnHand) || _.isUndefined(item.stockOnHand)); + var hasQuantity = !(_.isNull(item.quantity) || _.isUndefined(item.quantity)) && item.quantity !== -1; + var searchableFields = [ + item.orderable.productCode, productNameFilter(item.orderable), + hasStockOnHand ? item.stockOnHand.toString() : "", + hasQuantity ? item.quantity.toString() : "", + item.lot ? item.lot.lotCode : (hasLot? messageService.get('orderableLotUtilService.noLotDefined') : ""), + item.lot ? openlmisDateFilter(item.lot.expirationDate) : "" + ]; + return _.any(searchableFields, function (field) { + return field.toLowerCase().contains(keyword.toLowerCase()); + }); + }); + } + + return result; + } + + /** + * @ngdoc method + * @methodOf stock-physical-inventory.physicalInventoryService + * @name saveDraft + * + * @description + * Saves physical inventory draft. + * + * @param {Object} draft Draft that will be saved + * @return {Promise} Saved draft + */ + function saveDraft(draft) { + return resource.update({id: draft.id}, draft).$promise; + } + + /** + * @ngdoc method + * @methodOf stock-physical-inventory.physicalInventoryService + * @name deleteDraft + * + * @description + * Deletes physical inventory draft. + * + * @param {Object} draft Draft that will be removed + * @return {Promise} Promise with response + */ + function deleteDraft(id) { + return resource.delete({id: id}).$promise; + } + + /** + * @ngdoc method + * @methodOf stock-physical-inventory.physicalInventoryService + * @name submit + * + * @description + * Submits physical inventory draft. + * + * @param {Object} physicalInventory Draft that will be saved + * @return {Promise} Submitted Physical Inventory + */ + function submit(physicalInventory) { + var event = _.clone(physicalInventory); + delete event.id; + event.resourceId = physicalInventory.id; + event.lineItems = physicalInventory.lineItems + .filter(function (item) { + return item.isAdded; + }) + .map(function (item) { + return { + orderableId: item.orderable.id, + lotId: item.lot ? item.lot.id : null, + quantity: item.quantity, + occurredDate: $filter('isoDate')(physicalInventory.occurredDate), + extraData: { + vvmStatus: item.vvmStatus + }, + stockAdjustments: item.stockAdjustments + }; + }); + + return resource.submitPhysicalInventory(event).$promise; + } + + } +})(); Index: src/stock-physical-inventory/physical-inventory.service.spec.js =================================================================== diff -u -N --- src/stock-physical-inventory/physical-inventory.service.spec.js (revision 0) +++ src/stock-physical-inventory/physical-inventory.service.spec.js (revision 2a8476e37de29041b616a2a0382dc71db10bf6de) @@ -0,0 +1,93 @@ +/* + * 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('physicalInventoryService', function() { + + var $rootScope, $httpBackend, physicalInventoryService, stockmanagementUrlFactory; + + beforeEach(function() { + module('stock-physical-inventory'); + + inject(function($injector) { + $httpBackend = $injector.get('$httpBackend'); + $rootScope = $injector.get('$rootScope'); + stockmanagementUrlFactory = $injector.get('stockmanagementUrlFactory'); + physicalInventoryService = $injector.get('physicalInventoryService'); + }); + }); + + it('should get draft', function () { + var result, + facilityId = '2'; + draft = {programId: '1'}; + + $httpBackend.when('GET', stockmanagementUrlFactory('/api/physicalInventories?program=' + draft.programId + + '&facility=' + facilityId + '&isDraft=true')).respond(200, [draft]); + + physicalInventoryService.getDraft(draft.programId, facilityId).then(function(response) { + result = response; + }); + + $httpBackend.flush(); + $rootScope.$apply(); + + expect(result[0].programId).toBe(draft.programId); + }); + + it('should get physical inventory', function () { + var result, + physicalInventory = {id: '1'}; + + $httpBackend.when('GET', stockmanagementUrlFactory('/api/physicalInventories/' + physicalInventory.id)) + .respond(200, physicalInventory); + + physicalInventoryService.getPhysicalInventory(physicalInventory.id).then(function(response) { + result = response; + }); + + $httpBackend.flush(); + $rootScope.$apply(); + + expect(result.id).toBe(physicalInventory.id); + }); + + it('should create new draft', function () { + var result, + draft = { + facilityId: '2', + programId: '1' + }; + + $httpBackend.when('POST', stockmanagementUrlFactory('/api/physicalInventories')) + .respond(function (method, url, data) { + return [201, data];//return whatever was passed to http backend. + }); + + physicalInventoryService.createDraft(draft.programId, draft.facilityId).then(function(response) { + result = response; + }); + + $httpBackend.flush(); + $rootScope.$apply(); + + expect(result.programId).toBe(draft.programId); + expect(result.facilityId).toBe(draft.facilityId); + }); + + afterEach(function() { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); +});