diff --git a/db/changes/10460-motherDay/00-aclItemType.sql b/db/changes/10460-motherDay/00-aclItemType.sql new file mode 100644 index 000000000..836a69dfd --- /dev/null +++ b/db/changes/10460-motherDay/00-aclItemType.sql @@ -0,0 +1,4 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('ItemType', '*', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('ItemType', '*', 'WRITE', 'ALLOW', 'ROLE', 'buyer'); \ No newline at end of file diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index c329e4c6e..3adf1b584 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -744,14 +744,19 @@ INSERT INTO `vn`.`itemCategory`(`id`, `name`, `display`, `color`, `icon`, `code` (7, 'Accessories', 1, NULL, 'icon-accessory', 'accessory'), (8, 'Fruit', 1, NULL, 'icon-fruit', 'fruit'); -INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `warehouseFk`, `life`,`workerFk`, `isPackaging`) +INSERT INTO `vn`.`temperature`(`code`, `name`, `description`) VALUES - (1, 'CRI', 'Crisantemo', 2, 1, 31, 35, 0), - (2, 'ITG', 'Anthurium', 1, 1, 31, 35, 0), - (3, 'WPN', 'Paniculata', 2, 1, 31, 35, 0), - (4, 'PRT', 'Delivery ports', 3, 1, NULL, 35, 1), - (5, 'CON', 'Container', 3, 1, NULL, 35, 1), - (6, 'ALS', 'Alstroemeria', 1, 1, 31, 16, 0); + ('warm', 'Warm', 'Warm'), + ('cool', 'Cool', 'Cool'); + +INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `warehouseFk`, `life`,`workerFk`, `isPackaging`, `temperatureFk`) + VALUES + (1, 'CRI', 'Crisantemo', 2, 1, 31, 35, 0, 'cool'), + (2, 'ITG', 'Anthurium', 1, 1, 31, 35, 0, 'cool'), + (3, 'WPN', 'Paniculata', 2, 1, 31, 35, 0, 'cool'), + (4, 'PRT', 'Delivery ports', 3, 1, NULL, 35, 1, 'warm'), + (5, 'CON', 'Container', 3, 1, NULL, 35, 1, 'warm'), + (6, 'ALS', 'Alstroemeria', 1, 1, 31, 16, 0, 'warm'); INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`) VALUES @@ -2290,11 +2295,6 @@ INSERT INTO `vn`.`workerTimeControlParams` (`id`, `dayBreak`, `weekBreak`, `week (1, 43200, 129600, 734400, 43200, 50400, 259200, 1296000, 36000); INSERT IGNORE INTO `vn`.`greugeConfig` (`id`, `freightPickUpPrice`) VALUES ('1', '11'); - -INSERT INTO `vn`.`temperature`(`code`, `name`, `description`) - VALUES - ('warm', 'Warm', 'Warm'), - ('cool', 'Cool', 'Cool'); INSERT INTO `vn`.`thermograph`(`id`, `model`) VALUES diff --git a/modules/account/front/role/summary/index.js b/modules/account/front/role/summary/index.js index 0a08fe8b2..4f321fa98 100644 --- a/modules/account/front/role/summary/index.js +++ b/modules/account/front/role/summary/index.js @@ -6,7 +6,6 @@ class Controller extends Component { this._role = value; this.$.summary = null; if (!value) return; - this.$http.get(`Roles/${value.id}`) .then(res => this.$.summary = res.data); } diff --git a/modules/item/back/models/item-type.json b/modules/item/back/models/item-type.json index cb9d5ace8..843d9877f 100644 --- a/modules/item/back/models/item-type.json +++ b/modules/item/back/models/item-type.json @@ -21,8 +21,11 @@ "life": { "type": "number" }, - "isPackaging": { - "type": "boolean" + "promo": { + "type": "number" + }, + "isUnconventionalSize": { + "type": "number" } }, "relations": { @@ -40,6 +43,16 @@ "type": "belongsTo", "model": "ItemCategory", "foreignKey": "categoryFk" + }, + "itemPackingType": { + "type": "belongsTo", + "model": "ItemPackingType", + "foreignKey": "itemPackingTypeFk" + }, + "temperature": { + "type": "belongsTo", + "model": "Temperature", + "foreignKey": "temperatureFk" } }, "acls": [ diff --git a/modules/item/front/index.js b/modules/item/front/index.js index c328b1c8d..6a8d1b3b7 100644 --- a/modules/item/front/index.js +++ b/modules/item/front/index.js @@ -23,4 +23,4 @@ import './waste/index/'; import './waste/detail'; import './fixed-price'; import './fixed-price-search-panel'; - +import './item-type'; diff --git a/modules/item/front/item-type/basic-data/index.html b/modules/item/front/item-type/basic-data/index.html new file mode 100644 index 000000000..1417a05ab --- /dev/null +++ b/modules/item/front/item-type/basic-data/index.html @@ -0,0 +1,62 @@ + + +
+ + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/modules/item/front/item-type/basic-data/index.js b/modules/item/front/item-type/basic-data/index.js new file mode 100644 index 000000000..ec280fdf8 --- /dev/null +++ b/modules/item/front/item-type/basic-data/index.js @@ -0,0 +1,12 @@ +import ngModule from '../../module'; +import Section from 'salix/components/section'; + +export default class Controller extends Section {} + +ngModule.component('vnItemTypeBasicData', { + template: require('./index.html'), + controller: Controller, + bindings: { + itemType: '<' + } +}); diff --git a/modules/item/front/item-type/card/index.html b/modules/item/front/item-type/card/index.html new file mode 100644 index 000000000..80af6088e --- /dev/null +++ b/modules/item/front/item-type/card/index.html @@ -0,0 +1,5 @@ + + + + + diff --git a/modules/item/front/item-type/card/index.js b/modules/item/front/item-type/card/index.js new file mode 100644 index 000000000..fa6b37340 --- /dev/null +++ b/modules/item/front/item-type/card/index.js @@ -0,0 +1,23 @@ +import ngModule from '../../module'; +import ModuleCard from 'salix/components/module-card'; + +class Controller extends ModuleCard { + reload() { + const filter = { + include: [ + {relation: 'worker'}, + {relation: 'category'}, + {relation: 'itemPackingType'}, + {relation: 'temperature'} + ] + }; + + this.$http.get(`ItemTypes/${this.$params.id}`, {filter}) + .then(res => this.itemType = res.data); + } +} + +ngModule.vnComponent('vnItemTypeCard', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/item/front/item-type/card/index.spec.js b/modules/item/front/item-type/card/index.spec.js new file mode 100644 index 000000000..ab2314bb9 --- /dev/null +++ b/modules/item/front/item-type/card/index.spec.js @@ -0,0 +1,27 @@ +import './index'; + +describe('component vnItemTypeCard', () => { + let controller; + let $httpBackend; + + beforeEach(ngModule('item')); + + beforeEach(inject(($componentController, _$httpBackend_) => { + $httpBackend = _$httpBackend_; + controller = $componentController('vnItemTypeCard', {$element: null}); + })); + + describe('reload()', () => { + it('should reload the controller data', () => { + controller.$params.id = 1; + + const itemType = {id: 1}; + + $httpBackend.expectGET('ItemTypes/1').respond(itemType); + controller.reload(); + $httpBackend.flush(); + + expect(controller.itemType).toEqual(itemType); + }); + }); +}); diff --git a/modules/item/front/item-type/create/index.html b/modules/item/front/item-type/create/index.html new file mode 100644 index 000000000..44cb5183d --- /dev/null +++ b/modules/item/front/item-type/create/index.html @@ -0,0 +1,62 @@ + + +
+ + + + + + + + + + + + + + + + + + + + +
diff --git a/modules/item/front/item-type/create/index.js b/modules/item/front/item-type/create/index.js new file mode 100644 index 000000000..ccf7744be --- /dev/null +++ b/modules/item/front/item-type/create/index.js @@ -0,0 +1,15 @@ +import ngModule from '../../module'; +import Section from 'salix/components/section'; + +export default class Controller extends Section { + onSubmit() { + return this.$.watcher.submit().then(res => + this.$state.go('item.itemType.card.basicData', {id: res.data.id}) + ); + } +} + +ngModule.component('vnItemTypeCreate', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/item/front/item-type/create/index.spec.js b/modules/item/front/item-type/create/index.spec.js new file mode 100644 index 000000000..4b000df9a --- /dev/null +++ b/modules/item/front/item-type/create/index.spec.js @@ -0,0 +1,34 @@ +import './index'; + +describe('component vnItemTypeCreate', () => { + let $scope; + let $state; + let controller; + + beforeEach(ngModule('item')); + + beforeEach(inject(($componentController, $rootScope, _$state_) => { + $scope = $rootScope.$new(); + $state = _$state_; + $scope.watcher = { + submit: () => { + return { + then: callback => { + callback({data: {id: '1234'}}); + } + }; + } + }; + const $element = angular.element(''); + controller = $componentController('vnItemTypeCreate', {$element, $scope}); + })); + + describe('onSubmit()', () => { + it(`should call submit() on the watcher then expect a callback`, () => { + jest.spyOn($state, 'go'); + controller.onSubmit(); + + expect(controller.$state.go).toHaveBeenCalledWith('item.itemType.card.basicData', {id: '1234'}); + }); + }); +}); diff --git a/modules/item/front/item-type/descriptor/index.html b/modules/item/front/item-type/descriptor/index.html new file mode 100644 index 000000000..5a0e8ed49 --- /dev/null +++ b/modules/item/front/item-type/descriptor/index.html @@ -0,0 +1,25 @@ + + +
+ + + + + + + + +
+
+
\ No newline at end of file diff --git a/modules/item/front/item-type/descriptor/index.js b/modules/item/front/item-type/descriptor/index.js new file mode 100644 index 000000000..9322c599a --- /dev/null +++ b/modules/item/front/item-type/descriptor/index.js @@ -0,0 +1,20 @@ +import ngModule from '../../module'; +import Descriptor from 'salix/components/descriptor'; + +class Controller extends Descriptor { + get itemType() { + return this.entity; + } + + set itemType(value) { + this.entity = value; + } +} + +ngModule.component('vnItemTypeDescriptor', { + template: require('./index.html'), + controller: Controller, + bindings: { + itemType: '<' + } +}); diff --git a/modules/item/front/item-type/index.js b/modules/item/front/item-type/index.js new file mode 100644 index 000000000..5dcbe4097 --- /dev/null +++ b/modules/item/front/item-type/index.js @@ -0,0 +1,8 @@ +import './main'; +import './index/'; +import './summary'; +import './card'; +import './descriptor'; +import './create'; +import './basic-data'; +import './search-panel'; diff --git a/modules/item/front/item-type/index/index.html b/modules/item/front/item-type/index/index.html new file mode 100644 index 000000000..50b9eb172 --- /dev/null +++ b/modules/item/front/item-type/index/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/item/front/item-type/index/index.js b/modules/item/front/item-type/index/index.js new file mode 100644 index 000000000..54ecba997 --- /dev/null +++ b/modules/item/front/item-type/index/index.js @@ -0,0 +1,14 @@ +import ngModule from '../../module'; +import Section from 'salix/components/section'; + +export default class Controller extends Section { + preview(itemType) { + this.selectedItemType = itemType; + this.$.summary.show(); + } +} + +ngModule.component('vnItemTypeIndex', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/item/front/item-type/index/index.spec.js b/modules/item/front/item-type/index/index.spec.js new file mode 100644 index 000000000..887c03f7f --- /dev/null +++ b/modules/item/front/item-type/index/index.spec.js @@ -0,0 +1,34 @@ +import './index'; + +describe('Item', () => { + describe('Component vnItemTypeIndex', () => { + let controller; + let $window; + + beforeEach(ngModule('item')); + + beforeEach(inject(($componentController, _$window_) => { + $window = _$window_; + const $element = angular.element(''); + controller = $componentController('vnItemTypeIndex', {$element}); + })); + + describe('preview()', () => { + it('should show the dialog summary', () => { + controller.$.summary = {show: () => {}}; + jest.spyOn(controller.$.summary, 'show'); + + const itemType = {id: 1}; + + const event = new MouseEvent('click', { + view: $window, + bubbles: true, + cancelable: true + }); + controller.preview(event, itemType); + + expect(controller.$.summary.show).toHaveBeenCalledWith(); + }); + }); + }); +}); diff --git a/modules/item/front/item-type/index/locale/es.yml b/modules/item/front/item-type/index/locale/es.yml new file mode 100644 index 000000000..1a71ff212 --- /dev/null +++ b/modules/item/front/item-type/index/locale/es.yml @@ -0,0 +1,2 @@ +Item Type: Familia +New itemType: Nueva familia \ No newline at end of file diff --git a/modules/item/front/item-type/main/index.html b/modules/item/front/item-type/main/index.html new file mode 100644 index 000000000..faba696c0 --- /dev/null +++ b/modules/item/front/item-type/main/index.html @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file diff --git a/modules/item/front/item-type/main/index.js b/modules/item/front/item-type/main/index.js new file mode 100644 index 000000000..0dea00abb --- /dev/null +++ b/modules/item/front/item-type/main/index.js @@ -0,0 +1,24 @@ +import ngModule from '../../module'; +import ModuleMain from 'salix/components/module-main'; + +export default class ItemType extends ModuleMain { + exprBuilder(param, value) { + switch (param) { + case 'search': + return /^\d+$/.test(value) + ? {id: value} + : {or: [ + {name: {like: `%${value}%`}}, + {code: {like: `%${value}%`}} + ]}; + case 'name': + case 'code': + return {[param]: {like: `%${value}%`}}; + } + } +} + +ngModule.vnComponent('vnItemType', { + controller: ItemType, + template: require('./index.html') +}); diff --git a/modules/item/front/item-type/main/index.spec.js b/modules/item/front/item-type/main/index.spec.js new file mode 100644 index 000000000..dcb14ec0e --- /dev/null +++ b/modules/item/front/item-type/main/index.spec.js @@ -0,0 +1,31 @@ +import './index'; + +describe('Item', () => { + describe('Component vnItemType', () => { + let controller; + + beforeEach(ngModule('item')); + + beforeEach(inject($componentController => { + const $element = angular.element(''); + controller = $componentController('vnItemType', {$element}); + })); + + describe('exprBuilder()', () => { + it('should return a filter based on a search by id', () => { + const filter = controller.exprBuilder('search', '123'); + + expect(filter).toEqual({id: '123'}); + }); + + it('should return a filter based on a search by name or code', () => { + const filter = controller.exprBuilder('search', 'Alstroemeria'); + + expect(filter).toEqual({or: [ + {name: {like: '%Alstroemeria%'}}, + {code: {like: '%Alstroemeria%'}}, + ]}); + }); + }); + }); +}); diff --git a/modules/item/front/item-type/main/locale/es.yml b/modules/item/front/item-type/main/locale/es.yml new file mode 100644 index 000000000..7aceac46f --- /dev/null +++ b/modules/item/front/item-type/main/locale/es.yml @@ -0,0 +1 @@ +Search itemType by id, name or code: Buscar familia por id, nombre o código \ No newline at end of file diff --git a/modules/item/front/item-type/search-panel/index.html b/modules/item/front/item-type/search-panel/index.html new file mode 100644 index 000000000..4aa762900 --- /dev/null +++ b/modules/item/front/item-type/search-panel/index.html @@ -0,0 +1,22 @@ +
+
+ + + + + + + + + + + +
+
\ No newline at end of file diff --git a/modules/item/front/item-type/search-panel/index.js b/modules/item/front/item-type/search-panel/index.js new file mode 100644 index 000000000..17a439c39 --- /dev/null +++ b/modules/item/front/item-type/search-panel/index.js @@ -0,0 +1,7 @@ +import ngModule from '../../module'; +import SearchPanel from 'core/components/searchbar/search-panel'; + +ngModule.component('vnItemTypeSearchPanel', { + template: require('./index.html'), + controller: SearchPanel +}); diff --git a/modules/item/front/item-type/summary/index.html b/modules/item/front/item-type/summary/index.html new file mode 100644 index 000000000..d003c8f38 --- /dev/null +++ b/modules/item/front/item-type/summary/index.html @@ -0,0 +1,50 @@ + +
+ {{summary.id}} - {{summary.name}} - {{summary.worker.firstName}} {{summary.worker.lastName}} +
+ + +

Basic data

+ + + + + + + + + + + + + + + + + + + + +
+
+
\ No newline at end of file diff --git a/modules/item/front/item-type/summary/index.js b/modules/item/front/item-type/summary/index.js new file mode 100644 index 000000000..7645de8b1 --- /dev/null +++ b/modules/item/front/item-type/summary/index.js @@ -0,0 +1,33 @@ +import ngModule from '../../module'; +import Component from 'core/lib/component'; + +class Controller extends Component { + set itemType(value) { + this._itemType = value; + this.$.summary = null; + if (!value) return; + + const filter = { + include: [ + {relation: 'worker'}, + {relation: 'category'}, + {relation: 'itemPackingType'}, + {relation: 'temperature'} + ] + }; + this.$http.get(`ItemTypes/${value.id}`, {filter}) + .then(res => this.$.summary = res.data); + } + + get itemType() { + return this._itemType; + } +} + +ngModule.component('vnItemTypeSummary', { + template: require('./index.html'), + controller: Controller, + bindings: { + itemType: '<' + } +}); diff --git a/modules/item/front/item-type/summary/locale/es.yml b/modules/item/front/item-type/summary/locale/es.yml new file mode 100644 index 000000000..8f4cef70f --- /dev/null +++ b/modules/item/front/item-type/summary/locale/es.yml @@ -0,0 +1,4 @@ +Life: Vida +Promo: Promoción +Item packing type: Tipo de embalaje +Is unconventional size: Es de tamaño poco convencional \ No newline at end of file diff --git a/modules/item/front/routes.json b/modules/item/front/routes.json index 9e21e1697..5743d0ce7 100644 --- a/modules/item/front/routes.json +++ b/modules/item/front/routes.json @@ -9,7 +9,8 @@ {"state": "item.index", "icon": "icon-item"}, {"state": "item.request", "icon": "icon-buyrequest"}, {"state": "item.waste.index", "icon": "icon-claims"}, - {"state": "item.fixedPrice", "icon": "icon-fixedPrice"} + {"state": "item.fixedPrice", "icon": "icon-fixedPrice"}, + {"state": "item.itemType", "icon": "contact_support"} ], "card": [ {"state": "item.card.basicData", "icon": "settings"}, @@ -20,6 +21,9 @@ {"state": "item.card.diary", "icon": "icon-transaction"}, {"state": "item.card.last-entries", "icon": "icon-regentry"}, {"state": "item.card.log", "icon": "history"} + ], + "itemType": [ + {"state": "item.itemType.card.basicData", "icon": "settings"} ] }, "keybindings": [ @@ -169,6 +173,47 @@ "component": "vn-fixed-price", "description": "Fixed prices", "acl": ["buyer"] + }, + { + "url" : "/item-type?q", + "state": "item.itemType", + "component": "vn-item-type", + "description": "Item Type", + "acl": ["buyer"] + }, + { + "url": "/create", + "state": "item.itemType.create", + "component": "vn-item-type-create", + "description": "New itemType", + "acl": ["buyer"] + }, + { + "url": "/:id", + "state": "item.itemType.card", + "component": "vn-item-type-card", + "abstract": true, + "description": "Detail" + }, + { + "url": "/summary", + "state": "item.itemType.card.summary", + "component": "vn-item-type-summary", + "description": "Summary", + "params": { + "item-type": "$ctrl.itemType" + }, + "acl": ["buyer"] + }, + { + "url": "/basic-data", + "state": "item.itemType.card.basicData", + "component": "vn-item-type-basic-data", + "description": "Basic data", + "params": { + "item-type": "$ctrl.itemType" + }, + "acl": ["buyer"] } ] } \ No newline at end of file