From 330b6bdf8afd957882e95aa43f83e537a66bc0e5 Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 29 Apr 2021 14:41:10 +0200 Subject: [PATCH 1/7] 2770 - Added supplier addresses section --- .../10310-mothersDay/00-supplierAddress.sql | 18 +++ modules/client/front/address/index/index.html | 8 +- modules/client/front/address/locale/es.yml | 4 +- modules/client/front/locale/es.yml | 6 +- modules/client/front/routes.json | 2 +- .../back/methods/supplier/createAddress.js | 90 +++++++++++++++ modules/supplier/back/model-config.json | 11 +- .../supplier/back/models/supplier-address.js | 16 +++ .../back/models/supplier-address.json | 55 +++++++++ modules/supplier/back/models/supplier.json | 5 + .../supplier/front/address/create/index.html | 109 ++++++++++++++++++ .../supplier/front/address/create/index.js | 74 ++++++++++++ .../front/address/create/index.spec.js | 102 ++++++++++++++++ .../supplier/front/address/edit/index.html | 104 +++++++++++++++++ modules/supplier/front/address/edit/index.js | 62 ++++++++++ .../supplier/front/address/edit/index.spec.js | 39 +++++++ .../supplier/front/address/index/index.html | 79 +++++++++++++ modules/supplier/front/address/index/index.js | 46 ++++++++ .../front/address/index/index.spec.js | 34 ++++++ .../supplier/front/address/index/style.scss | 21 ++++ modules/supplier/front/address/locale/es.yml | 18 +++ modules/supplier/front/index.js | 3 + modules/supplier/front/routes.json | 43 ++++++- 23 files changed, 931 insertions(+), 18 deletions(-) create mode 100644 db/changes/10310-mothersDay/00-supplierAddress.sql create mode 100644 modules/supplier/back/methods/supplier/createAddress.js create mode 100644 modules/supplier/back/models/supplier-address.js create mode 100644 modules/supplier/back/models/supplier-address.json create mode 100644 modules/supplier/front/address/create/index.html create mode 100644 modules/supplier/front/address/create/index.js create mode 100644 modules/supplier/front/address/create/index.spec.js create mode 100644 modules/supplier/front/address/edit/index.html create mode 100644 modules/supplier/front/address/edit/index.js create mode 100644 modules/supplier/front/address/edit/index.spec.js create mode 100644 modules/supplier/front/address/index/index.html create mode 100644 modules/supplier/front/address/index/index.js create mode 100644 modules/supplier/front/address/index/index.spec.js create mode 100644 modules/supplier/front/address/index/style.scss create mode 100644 modules/supplier/front/address/locale/es.yml diff --git a/db/changes/10310-mothersDay/00-supplierAddress.sql b/db/changes/10310-mothersDay/00-supplierAddress.sql new file mode 100644 index 000000000..e15a25a81 --- /dev/null +++ b/db/changes/10310-mothersDay/00-supplierAddress.sql @@ -0,0 +1,18 @@ +CREATE TABLE `vn`.`supplierAddress` +( + id INT NULL AUTO_INCREMENT, + supplierFk INT NULL, + nickname VARCHAR(40) NULL, + street VARCHAR(255) NULL, + provinceFk SMALLINT(6) UNSIGNED NULL, + postalCode VARCHAR(10) NULL, + city VARCHAR(50) NULL, + phone VARCHAR(15) NULL, + mobile VARCHAR(15) NULL, + CONSTRAINT supplierAddress_pk + PRIMARY KEY (id), + CONSTRAINT supplierAddress_province_fk + FOREIGN KEY (provinceFk) REFERENCES province (id) + ON UPDATE CASCADE +); + diff --git a/modules/client/front/address/index/index.html b/modules/client/front/address/index/index.html index 51b310128..ebdc44724 100644 --- a/modules/client/front/address/index/index.html +++ b/modules/client/front/address/index/index.html @@ -8,8 +8,8 @@ @@ -26,7 +26,7 @@ ui-sref="client.card.address.edit({addressId: {{::address.id}}})" class="vn-pa-sm border-solid border-radius" ng-class="{'item-disabled': !address.isActive}" - translate-attr="{title: 'Edit address'}"> + translate-attr="{title: 'Edit consignee'}"> @@ -78,7 +78,7 @@ diff --git a/modules/client/front/address/locale/es.yml b/modules/client/front/address/locale/es.yml index 06d9e76f7..e1383fab5 100644 --- a/modules/client/front/address/locale/es.yml +++ b/modules/client/front/address/locale/es.yml @@ -1,8 +1,8 @@ # Index Set as default: Establecer como predeterminado Active first to set as default: Active primero para marcar como predeterminado -Search by address: Buscar por consignatario -You can search by address id or name: Puedes buscar por el id o nombre del consignatario +Search by consignee: Buscar por consignatario +You can search by consignee id or name: Puedes buscar por el id o nombre del consignatario # Edit Enabled: Activo Is equalizated: Recargo de equivalencia diff --git a/modules/client/front/locale/es.yml b/modules/client/front/locale/es.yml index 82cbb129e..1a5a570a7 100644 --- a/modules/client/front/locale/es.yml +++ b/modules/client/front/locale/es.yml @@ -36,9 +36,9 @@ Clients: Clientes New client: Nuevo cliente Fiscal data: Datos fiscales Billing data: Forma de pago -Addresses: Consignatarios -New address: Nuevo consignatario -Edit address: Editar consignatario +Consignees: Consignatarios +New consignee: Nuevo consignatario +Edit consignee: Editar consignatario Web access: Acceso web Notes: Notas New note: Nueva nota diff --git a/modules/client/front/routes.json b/modules/client/front/routes.json index a2d559645..4bd4086e0 100644 --- a/modules/client/front/routes.json +++ b/modules/client/front/routes.json @@ -102,7 +102,7 @@ "url": "/index?q", "state": "client.card.address.index", "component": "vn-client-address-index", - "description": "Addresses", + "description": "Consignees", "params": { "client": "$ctrl.client" } diff --git a/modules/supplier/back/methods/supplier/createAddress.js b/modules/supplier/back/methods/supplier/createAddress.js new file mode 100644 index 000000000..63995ba8f --- /dev/null +++ b/modules/supplier/back/methods/supplier/createAddress.js @@ -0,0 +1,90 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = function(Self) { + Self.remoteMethodCtx('createAddress', { + description: 'Creates a supplier address', + accepts: [{ + arg: 'id', + type: 'number', + description: 'The supplier id', + http: {source: 'path'} + }, + { + arg: 'nickname', + type: 'string', + required: true + }, + { + arg: 'city', + type: 'string', + required: true + }, + { + arg: 'street', + type: 'string', + required: true + }, + { + arg: 'phone', + type: 'string' + }, + { + arg: 'mobile', + type: 'string' + }, + { + arg: 'postalCode', + type: 'string' + }, + { + arg: 'provinceFk', + type: 'number' + }], + returns: { + root: true, + type: 'Object' + }, + http: { + verb: 'post', + path: '/:id/createAddress' + } + }); + + Self.createAddress = async(ctx, clientFk) => { + const models = Self.app.models; + const args = ctx.args; + const tx = await models.Address.beginTransaction({}); + + try { + const options = {transaction: tx}; + const province = await models.Province.findById(args.provinceFk, { + include: { + relation: 'country' + } + }, options); + + const isUeeMember = province.country().isUeeMember; + if (!isUeeMember && !args.incotermsFk) + throw new UserError(`Incoterms is required for a non UEE member`); + + if (!isUeeMember && !args.customsAgentFk) + throw new UserError(`Customs agent is required for a non UEE member`); + + delete args.ctx; // Remove unwanted properties + const newAddress = await models.Address.create(args, options); + const client = await Self.findById(clientFk, null, options); + + if (args.isDefaultAddress) { + await client.updateAttributes({ + defaultAddressFk: newAddress.id + }, options); + } + + await tx.commit(); + return newAddress; + } catch (e) { + await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/supplier/back/model-config.json b/modules/supplier/back/model-config.json index 62c580aca..7febc17b4 100644 --- a/modules/supplier/back/model-config.json +++ b/modules/supplier/back/model-config.json @@ -1,8 +1,14 @@ { + "PayDem": { + "dataSource": "vn" + }, "Supplier": { "dataSource": "vn" }, - "PayDem": { + "SupplierAddress": { + "dataSource": "vn" + }, + "SupplierAccount": { "dataSource": "vn" }, "SupplierLog": { @@ -10,8 +16,5 @@ }, "SupplierContact": { "dataSource": "vn" - }, - "SupplierAccount": { - "dataSource": "vn" } } diff --git a/modules/supplier/back/models/supplier-address.js b/modules/supplier/back/models/supplier-address.js new file mode 100644 index 000000000..ca08fa719 --- /dev/null +++ b/modules/supplier/back/models/supplier-address.js @@ -0,0 +1,16 @@ +module.exports = Self => { + Self.validateAsync('postalCode', hasValidPostcode, { + message: `The postcode doesn't exist. Please enter a correct one` + }); + + async function hasValidPostcode(err, done) { + if (!this.postalCode) + return done(); + + const models = Self.app.models; + const postcode = await models.Postcode.findById(this.postalCode); + + if (!postcode) err(); + done(); + } +}; diff --git a/modules/supplier/back/models/supplier-address.json b/modules/supplier/back/models/supplier-address.json new file mode 100644 index 000000000..d1cee2d50 --- /dev/null +++ b/modules/supplier/back/models/supplier-address.json @@ -0,0 +1,55 @@ +{ + "name": "SupplierAddress", + "description": "Supplier addresses", + "base": "Loggable", + "log": { + "model": "SupplierLog", + "relation": "supplier", + "showField": "name" + }, + "options": { + "mysql": { + "table": "supplierAddress" + } + }, + "properties": { + "id": { + "type": "Number", + "id": true, + "description": "Identifier" + }, + "nickname": { + "type": "string", + "required": true + }, + "street": { + "type": "string", + "required": true + }, + "city": { + "type": "string", + "required": true + }, + "postalCode": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "mobile": { + "type": "string" + } + }, + "relations": { + "province": { + "type": "belongsTo", + "model": "Province", + "foreignKey": "provinceFk" + }, + "supplier": { + "type": "belongsTo", + "model": "Supplier", + "foreignKey": "supplierFk" + } + } +} \ No newline at end of file diff --git a/modules/supplier/back/models/supplier.json b/modules/supplier/back/models/supplier.json index 4ec568c8b..9567be785 100644 --- a/modules/supplier/back/models/supplier.json +++ b/modules/supplier/back/models/supplier.json @@ -149,6 +149,11 @@ "type": "belongsTo", "model": "SageWithholding", "foreignKey": "sageWithholdingFk" + }, + "addresses": { + "type": "hasMany", + "model": "SupplierAddress", + "foreignKey": "supplierFk" } }, "acls": [ diff --git a/modules/supplier/front/address/create/index.html b/modules/supplier/front/address/create/index.html new file mode 100644 index 000000000..4d66b70f0 --- /dev/null +++ b/modules/supplier/front/address/create/index.html @@ -0,0 +1,109 @@ + + + + +
+ + + + + + + + + + + {{code}} - {{town.name}} ({{town.province.name}}, + {{town.province.country.country}}) + + + + + + + + + {{name}}, {{province.name}} + ({{province.country.country}}) + + + + {{name}} ({{country.country}}) + + + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/modules/supplier/front/address/create/index.js b/modules/supplier/front/address/create/index.js new file mode 100644 index 000000000..21b845881 --- /dev/null +++ b/modules/supplier/front/address/create/index.js @@ -0,0 +1,74 @@ +import ngModule from '../../module'; +import Section from 'salix/components/section'; + +export default class Controller extends Section { + constructor($element, $) { + super($element, $); + + this.address = { + supplierFk: this.$params.id + }; + } + + onSubmit() { + this.$.watcher.submit().then(res => { + this.$state.go('supplier.card.address.index'); + }); + } + + get town() { + return this._town; + } + + // Town auto complete + set town(selection) { + this._town = selection; + + if (!selection) return; + + const province = selection.province; + const postcodes = selection.postcodes; + + if (!this.address.provinceFk) + this.address.provinceFk = province.id; + + if (postcodes.length === 1) + this.address.postalCode = postcodes[0].code; + } + + get postcode() { + return this._postcode; + } + + // Postcode auto complete + set postcode(selection) { + this._postcode = selection; + + if (!selection) return; + + const town = selection.town; + const province = town.province; + + if (!this.address.city) + this.address.city = town.name; + + if (!this.address.provinceFk) + this.address.provinceFk = province.id; + } + + onResponse(response) { + this.address.postalCode = response.code; + this.address.city = response.city; + this.address.provinceFk = response.provinceFk; + } +} + +Controller.$inject = ['$element', '$scope']; + +ngModule.vnComponent('vnSupplierAddressCreate', { + template: require('./index.html'), + controller: Controller, + bindings: { + supplier: '<' + } +}); diff --git a/modules/supplier/front/address/create/index.spec.js b/modules/supplier/front/address/create/index.spec.js new file mode 100644 index 000000000..026de3769 --- /dev/null +++ b/modules/supplier/front/address/create/index.spec.js @@ -0,0 +1,102 @@ +import './index'; +import watcher from 'core/mocks/watcher'; + +describe('Supplier', () => { + describe('Component vnSupplierAddressCreate', () => { + let $scope; + let controller; + let $element; + let $state; + + beforeEach(ngModule('supplier')); + + beforeEach(inject(($componentController, $rootScope, _$state_) => { + $scope = $rootScope.$new(); + $state = _$state_; + $state.params.id = '1234'; + $element = angular.element(''); + controller = $componentController('vnSupplierAddressCreate', {$element, $scope}); + controller.$.watcher = watcher; + controller.$.watcher.submit = () => { + return { + then: callback => { + callback({data: {id: 124}}); + } + }; + }; + controller.supplier = {id: 1}; + })); + + describe('onSubmit()', () => { + it('should perform a PATCH and then redirect to the main section', () => { + jest.spyOn(controller.$state, 'go'); + controller.onSubmit(); + + expect(controller.$state.go).toHaveBeenCalledWith('supplier.card.address.index'); + }); + }); + + describe('town() setter', () => { + it(`should set provinceFk property`, () => { + controller.town = { + provinceFk: 1, + code: 46001, + province: { + id: 1, + name: 'New york', + country: { + id: 2, + name: 'USA' + } + }, + postcodes: [] + }; + + expect(controller.address.provinceFk).toEqual(1); + }); + + it(`should set provinceFk property and fill the postalCode if there's just one`, () => { + controller.town = { + provinceFk: 1, + code: 46001, + province: { + id: 1, + name: 'New york', + country: { + id: 2, + name: 'USA' + } + }, + postcodes: [{code: '46001'}] + }; + + expect(controller.address.provinceFk).toEqual(1); + expect(controller.address.postalCode).toEqual('46001'); + }); + }); + + describe('postcode() setter', () => { + it(`should set the town and province properties`, () => { + controller.postcode = { + townFk: 1, + code: 46001, + town: { + id: 1, + name: 'New York', + province: { + id: 1, + name: 'New york', + country: { + id: 2, + name: 'USA' + } + } + } + }; + + expect(controller.address.city).toEqual('New York'); + expect(controller.address.provinceFk).toEqual(1); + }); + }); + }); +}); diff --git a/modules/supplier/front/address/edit/index.html b/modules/supplier/front/address/edit/index.html new file mode 100644 index 000000000..dd4cbb4d2 --- /dev/null +++ b/modules/supplier/front/address/edit/index.html @@ -0,0 +1,104 @@ + + + + + +
+ + + + + + + + + + + {{code}} - {{town.name}} ({{town.province.name}}, + {{town.province.country.country}}) + + + + + + + + + {{name}}, {{province.name}} + ({{province.country.country}}) + + + + {{name}} ({{country.country}}) + + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/modules/supplier/front/address/edit/index.js b/modules/supplier/front/address/edit/index.js new file mode 100644 index 000000000..4c7450666 --- /dev/null +++ b/modules/supplier/front/address/edit/index.js @@ -0,0 +1,62 @@ +import ngModule from '../../module'; +import Section from 'salix/components/section'; + +export default class Controller extends Section { + onSubmit() { + this.$.watcher.submit() + .then(() => this.$state.go('supplier.card.address.index')); + } + + get town() { + return this._town; + } + + // Town auto complete + set town(selection) { + const oldValue = this._town; + this._town = selection; + + if (!selection || !oldValue) return; + + const province = selection.province; + const postcodes = selection.postcodes; + + if (!this.address.provinceFk) + this.address.provinceFk = province.id; + + if (!this.address.postalCode && postcodes.length === 1) + this.address.postalCode = postcodes[0].code; + } + + get postcode() { + return this._postcode; + } + + // Postcode auto complete + set postcode(selection) { + const oldValue = this._postcode; + this._postcode = selection; + + if (!selection || !oldValue) return; + + const town = selection.town; + const province = town.province; + + if (!this.address.city) + this.address.city = town.name; + + if (!this.address.provinceFk) + this.address.provinceFk = province.id; + } + + onResponse(response) { + this.address.postalCode = response.code; + this.address.city = response.city; + this.address.provinceFk = response.provinceFk; + } +} + +ngModule.vnComponent('vnSupplierAddressEdit', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/supplier/front/address/edit/index.spec.js b/modules/supplier/front/address/edit/index.spec.js new file mode 100644 index 000000000..991163baa --- /dev/null +++ b/modules/supplier/front/address/edit/index.spec.js @@ -0,0 +1,39 @@ +import './index'; +import watcher from 'core/mocks/watcher'; + +describe('Supplier', () => { + describe('Component vnSupplierAddressEdit', () => { + let $scope; + let controller; + let $element; + let $state; + + beforeEach(ngModule('supplier')); + + beforeEach(inject(($componentController, $rootScope, _$state_) => { + $scope = $rootScope.$new(); + $state = _$state_; + $state.params.addressId = '1'; + $element = angular.element(''); + controller = $componentController('vnSupplierAddressEdit', {$element, $scope}); + controller.address = {id: 1}; + controller.$.watcher = watcher; + controller.$.watcher.submit = () => { + return { + then: callback => { + callback({data: {id: 124}}); + } + }; + }; + })); + + describe('onSubmit()', () => { + it('should perform a PATCH and then redirect to the main section', () => { + jest.spyOn(controller.$state, 'go'); + controller.onSubmit(); + + expect(controller.$state.go).toHaveBeenCalledWith('supplier.card.address.index'); + }); + }); + }); +}); diff --git a/modules/supplier/front/address/index/index.html b/modules/supplier/front/address/index/index.html new file mode 100644 index 000000000..ad8f6f250 --- /dev/null +++ b/modules/supplier/front/address/index/index.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + + diff --git a/modules/supplier/front/address/index/index.js b/modules/supplier/front/address/index/index.js new file mode 100644 index 000000000..c3985a0c1 --- /dev/null +++ b/modules/supplier/front/address/index/index.js @@ -0,0 +1,46 @@ +import ngModule from '../../module'; +import Section from 'salix/components/section'; +import './style.scss'; + +class Controller extends Section { + constructor($element, $) { + super($element, $); + this.filter = { + fields: [ + 'id', + 'nickname', + 'street', + 'city', + 'provinceFk', + 'phone', + 'mobile', + 'postalCode' + ], + order: ['nickname ASC'], + include: [{ + relation: 'province', + scope: { + fields: ['id', 'name'] + } + }] + }; + } + + exprBuilder(param, value) { + switch (param) { + case 'search': + return /^\d+$/.test(value) + ? {id: value} + : {nickname: {like: `%${value}%`}}; + } + } +} +Controller.$inject = ['$element', '$scope']; + +ngModule.vnComponent('vnSupplierAddressIndex', { + template: require('./index.html'), + controller: Controller, + bindings: { + supplier: '<' + } +}); diff --git a/modules/supplier/front/address/index/index.spec.js b/modules/supplier/front/address/index/index.spec.js new file mode 100644 index 000000000..086d3a9fa --- /dev/null +++ b/modules/supplier/front/address/index/index.spec.js @@ -0,0 +1,34 @@ +import './index'; + +describe('Supplier', () => { + describe('Component vnSupplierAddressIndex', () => { + let controller; + let $scope; + let $stateParams; + + beforeEach(ngModule('supplier')); + + beforeEach(inject(($componentController, $rootScope, _$stateParams_) => { + $stateParams = _$stateParams_; + $stateParams.id = 1; + $scope = $rootScope.$new(); + const $element = angular.element(''); + controller = $componentController('vnSupplierAddressIndex', {$element, $scope}); + controller.supplier = {id: 1}; + })); + + 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', () => { + const filter = controller.exprBuilder('search', 'Arkham Chemicals'); + + expect(filter).toEqual({nickname: {like: '%Arkham Chemicals%'}}); + }); + }); + }); +}); diff --git a/modules/supplier/front/address/index/style.scss b/modules/supplier/front/address/index/style.scss new file mode 100644 index 000000000..44ce07b3c --- /dev/null +++ b/modules/supplier/front/address/index/style.scss @@ -0,0 +1,21 @@ +@import "variables"; +@import "./effects"; + +vn-supplier-address-index { + .address { + padding-bottom: $spacing-md; + + &:last-child { + padding-bottom: 0; + } + & > a { + @extend %clickable; + box-sizing: border-box; + display: flex; + align-items: center; + width: 100%; + color: inherit; + overflow: hidden; + } + } +} \ No newline at end of file diff --git a/modules/supplier/front/address/locale/es.yml b/modules/supplier/front/address/locale/es.yml new file mode 100644 index 000000000..30009fa87 --- /dev/null +++ b/modules/supplier/front/address/locale/es.yml @@ -0,0 +1,18 @@ +# Index +Search by address: Buscar por dirección +You can search by address id or name: Puedes buscar por el id o nombre de la dirección + +# Create +Street address: Dirección postal +Postcode: Código postal +Town/City: Ciudad +Province: Provincia +Phone: Teléfono +Mobile: Móvil + +# Common +Fiscal name: Nombre fiscal +Street: Dirección fiscal +Addresses: Direcciones +New address: Nueva dirección +Edit address: Editar dirección \ No newline at end of file diff --git a/modules/supplier/front/index.js b/modules/supplier/front/index.js index 9c5cd4195..dc131ef4a 100644 --- a/modules/supplier/front/index.js +++ b/modules/supplier/front/index.js @@ -15,3 +15,6 @@ import './log'; import './consumption'; import './consumption-search-panel'; import './billing-data'; +import './address/index'; +import './address/create'; +import './address/edit'; diff --git a/modules/supplier/front/routes.json b/modules/supplier/front/routes.json index 5dc6a29b0..9a0dee48b 100644 --- a/modules/supplier/front/routes.json +++ b/modules/supplier/front/routes.json @@ -12,6 +12,7 @@ {"state": "supplier.card.basicData", "icon": "settings"}, {"state": "supplier.card.fiscalData", "icon": "account_balance"}, {"state": "supplier.card.billingData", "icon": "icon-payment"}, + {"state": "supplier.card.address.index", "icon": "icon-delivery"}, {"state": "supplier.card.account", "icon": "contact_support"}, {"state": "supplier.card.contact", "icon": "contact_phone"}, {"state": "supplier.card.log", "icon": "history"}, @@ -49,7 +50,8 @@ "params": { "supplier": "$ctrl.supplier" } - }, { + }, + { "url": "/basic-data", "state": "supplier.card.basicData", "component": "vn-supplier-basic-data", @@ -58,7 +60,8 @@ "params": { "supplier": "$ctrl.supplier" } - }, { + }, + { "url": "/fiscal-data", "state": "supplier.card.fiscalData", "component": "vn-supplier-fiscal-data", @@ -67,7 +70,8 @@ "supplier": "$ctrl.supplier" }, "acl": ["administrative"] - }, { + }, + { "url" : "/log", "state": "supplier.card.log", "component": "vn-supplier-log", @@ -100,7 +104,8 @@ "supplier": "$ctrl.supplier" }, "acl": ["administrative"] - },{ + }, + { "url": "/account", "state": "supplier.card.account", "component": "vn-supplier-account", @@ -109,6 +114,36 @@ "supplier": "$ctrl.supplier" }, "acl": ["administrative"] + }, + { + "url": "/address", + "state": "supplier.card.address", + "component": "ui-view", + "abstract": true + }, + { + "url": "/index?q", + "state": "supplier.card.address.index", + "component": "vn-supplier-address-index", + "description": "Addresses", + "params": { + "supplier": "$ctrl.supplier" + } + }, + { + "url": "/create", + "state": "supplier.card.address.create", + "component": "vn-supplier-address-create", + "description": "New address", + "params": { + "supplier": "$ctrl.supplier" + } + }, + { + "url": "/:addressId/edit", + "state": "supplier.card.address.edit", + "component": "vn-supplier-address-edit", + "description": "Edit address" } ] } \ No newline at end of file From 5445764043a5739805183d897a2863002009b647 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 30 Apr 2021 08:26:05 +0200 Subject: [PATCH 2/7] Added supplier address fixtures --- db/dump/fixtures.sql | 9 +++++++++ modules/supplier/front/address/index/index.html | 15 --------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index b215d0edd..bb3f88894 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1244,6 +1244,15 @@ INSERT INTO `vn`.`supplierActivity`(`code`, `name`) ('flowerPlants', 'Wholesale of flowers and plants'), ('vegetablesFruits', 'Fruit and vegetable trade'); +INSERT INTO `vn`.`supplierAddress`(`id`, `supplierFk`, `nickname`, `street`, `provinceFk`, `postalCode`, `city`, `phone`, `mobile`) + VALUES + (1, 1, 'Ace Chemicals', 'The Midtown', 1, '46000', 'Valencia', '111111111', '222222222'), + (2, 1, 'Arkham Asylum', 'Grand Avenue', 1, '46000', 'Valencia', '111111111', '222222222'), + (3, 2, 'Wayne Tower', 'Grand Avenue', 1, '46000', 'Valencia', '111111111', '222222222'), + (4, 2, 'Bank of Gotham', 'Founders Island', 1, '46000', 'Valencia', '111111111', '222222222'), + (5, 3, 'GCR building', 'Bristol district', 1, '46000', 'Valencia', '111111111', '222222222'), + (6, 3, 'The Gotham Tonight building', 'Bristol district', 1, '46000', 'Valencia', '111111111', '222222222'); + INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`) VALUES (1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants'), diff --git a/modules/supplier/front/address/index/index.html b/modules/supplier/front/address/index/index.html index ad8f6f250..cb7b3d56c 100644 --- a/modules/supplier/front/address/index/index.html +++ b/modules/supplier/front/address/index/index.html @@ -26,21 +26,6 @@ ui-sref="supplier.card.address.edit({addressId: {{::address.id}}})" class="vn-pa-sm border-solid border-radius" translate-attr="{title: 'Edit address'}"> -
{{::address.nickname}} - #{{::address.id}}
From d77e06a5a0c96f0ac948e33901929d5116ccf46b Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 30 Apr 2021 08:30:21 +0200 Subject: [PATCH 3/7] Changed city name --- db/dump/fixtures.sql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index bb3f88894..dd2b74739 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1246,12 +1246,12 @@ INSERT INTO `vn`.`supplierActivity`(`code`, `name`) INSERT INTO `vn`.`supplierAddress`(`id`, `supplierFk`, `nickname`, `street`, `provinceFk`, `postalCode`, `city`, `phone`, `mobile`) VALUES - (1, 1, 'Ace Chemicals', 'The Midtown', 1, '46000', 'Valencia', '111111111', '222222222'), - (2, 1, 'Arkham Asylum', 'Grand Avenue', 1, '46000', 'Valencia', '111111111', '222222222'), - (3, 2, 'Wayne Tower', 'Grand Avenue', 1, '46000', 'Valencia', '111111111', '222222222'), - (4, 2, 'Bank of Gotham', 'Founders Island', 1, '46000', 'Valencia', '111111111', '222222222'), - (5, 3, 'GCR building', 'Bristol district', 1, '46000', 'Valencia', '111111111', '222222222'), - (6, 3, 'The Gotham Tonight building', 'Bristol district', 1, '46000', 'Valencia', '111111111', '222222222'); + (1, 1, 'Ace Chemicals', 'The Midtown', 1, '46000', 'Gotham', '111111111', '222222222'), + (2, 1, 'Arkham Asylum', 'Grand Avenue', 1, '46000', 'Gotham', '111111111', '222222222'), + (3, 2, 'Wayne Tower', 'Grand Avenue', 1, '46000', 'Gotham', '111111111', '222222222'), + (4, 2, 'Bank of Gotham', 'Founders Island', 1, '46000', 'Gotham', '111111111', '222222222'), + (5, 3, 'GCR building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222'), + (6, 3, 'The Gotham Tonight building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222'); INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`) VALUES From 29b5cac35104878a820e912f971d59287da9afe4 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 30 Apr 2021 09:48:28 +0200 Subject: [PATCH 4/7] Fixtures for supplier 442 --- db/dump/fixtures.sql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index dd2b74739..f386ad780 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1246,12 +1246,12 @@ INSERT INTO `vn`.`supplierActivity`(`code`, `name`) INSERT INTO `vn`.`supplierAddress`(`id`, `supplierFk`, `nickname`, `street`, `provinceFk`, `postalCode`, `city`, `phone`, `mobile`) VALUES - (1, 1, 'Ace Chemicals', 'The Midtown', 1, '46000', 'Gotham', '111111111', '222222222'), - (2, 1, 'Arkham Asylum', 'Grand Avenue', 1, '46000', 'Gotham', '111111111', '222222222'), - (3, 2, 'Wayne Tower', 'Grand Avenue', 1, '46000', 'Gotham', '111111111', '222222222'), - (4, 2, 'Bank of Gotham', 'Founders Island', 1, '46000', 'Gotham', '111111111', '222222222'), - (5, 3, 'GCR building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222'), - (6, 3, 'The Gotham Tonight building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222'); + (1, 1, 'Ace Chemicals', 'The Midtown', 1, '46000', 'Gotham', '111111111', '222222222'), + (2, 1, 'Arkham Asylum', 'Grand Avenue', 1, '46000', 'Gotham', '111111111', '222222222'), + (3, 2, 'Wayne Tower', 'Grand Avenue', 1, '46000', 'Gotham', '111111111', '222222222'), + (4, 2, 'Bank of Gotham', 'Founders Island', 1, '46000', 'Gotham', '111111111', '222222222'), + (5, 442, 'GCR building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222'), + (6, 442, 'The Gotham Tonight building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222'); INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`) VALUES From dbe22844a6087dc926fa3007cf4ed0a07f4681d3 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 30 Apr 2021 09:53:20 +0200 Subject: [PATCH 5/7] Removed unused method --- .../back/methods/supplier/createAddress.js | 90 ------------------- 1 file changed, 90 deletions(-) delete mode 100644 modules/supplier/back/methods/supplier/createAddress.js diff --git a/modules/supplier/back/methods/supplier/createAddress.js b/modules/supplier/back/methods/supplier/createAddress.js deleted file mode 100644 index 63995ba8f..000000000 --- a/modules/supplier/back/methods/supplier/createAddress.js +++ /dev/null @@ -1,90 +0,0 @@ -const UserError = require('vn-loopback/util/user-error'); - -module.exports = function(Self) { - Self.remoteMethodCtx('createAddress', { - description: 'Creates a supplier address', - accepts: [{ - arg: 'id', - type: 'number', - description: 'The supplier id', - http: {source: 'path'} - }, - { - arg: 'nickname', - type: 'string', - required: true - }, - { - arg: 'city', - type: 'string', - required: true - }, - { - arg: 'street', - type: 'string', - required: true - }, - { - arg: 'phone', - type: 'string' - }, - { - arg: 'mobile', - type: 'string' - }, - { - arg: 'postalCode', - type: 'string' - }, - { - arg: 'provinceFk', - type: 'number' - }], - returns: { - root: true, - type: 'Object' - }, - http: { - verb: 'post', - path: '/:id/createAddress' - } - }); - - Self.createAddress = async(ctx, clientFk) => { - const models = Self.app.models; - const args = ctx.args; - const tx = await models.Address.beginTransaction({}); - - try { - const options = {transaction: tx}; - const province = await models.Province.findById(args.provinceFk, { - include: { - relation: 'country' - } - }, options); - - const isUeeMember = province.country().isUeeMember; - if (!isUeeMember && !args.incotermsFk) - throw new UserError(`Incoterms is required for a non UEE member`); - - if (!isUeeMember && !args.customsAgentFk) - throw new UserError(`Customs agent is required for a non UEE member`); - - delete args.ctx; // Remove unwanted properties - const newAddress = await models.Address.create(args, options); - const client = await Self.findById(clientFk, null, options); - - if (args.isDefaultAddress) { - await client.updateAttributes({ - defaultAddressFk: newAddress.id - }, options); - } - - await tx.commit(); - return newAddress; - } catch (e) { - await tx.rollback(); - throw e; - } - }; -}; From fcc8ab423631228509e243c56c6d9801974ffd28 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 30 Apr 2021 10:08:40 +0200 Subject: [PATCH 6/7] Added model ACL --- db/changes/10310-mothersDay/00-ACL.sql | 2 ++ modules/supplier/back/models/supplier-address.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 db/changes/10310-mothersDay/00-ACL.sql diff --git a/db/changes/10310-mothersDay/00-ACL.sql b/db/changes/10310-mothersDay/00-ACL.sql new file mode 100644 index 000000000..a2ae1e40f --- /dev/null +++ b/db/changes/10310-mothersDay/00-ACL.sql @@ -0,0 +1,2 @@ +INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId) +VALUES ('SupplierAddress', '*', '*', 'ALLOW', 'ROLE', 'employee'); diff --git a/modules/supplier/back/models/supplier-address.json b/modules/supplier/back/models/supplier-address.json index d1cee2d50..302f15e4b 100644 --- a/modules/supplier/back/models/supplier-address.json +++ b/modules/supplier/back/models/supplier-address.json @@ -14,7 +14,7 @@ }, "properties": { "id": { - "type": "Number", + "type": "number", "id": true, "description": "Identifier" }, From d16a39b1808f636a88ace35639e1b36c9884e8a8 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Mon, 3 May 2021 13:31:43 +0200 Subject: [PATCH 7/7] e2e path for supplier address --- e2e/helpers/selectors.js | 44 ++++++++--- ...g_data.spec.js => 04_billing_data.spec.js} | 0 e2e/paths/13-supplier/05_address.spec.js | 79 +++++++++++++++++++ ...{04_contact.spec.js => 06_contact.spec.js} | 0 4 files changed, 111 insertions(+), 12 deletions(-) rename e2e/paths/13-supplier/{05_billing_data.spec.js => 04_billing_data.spec.js} (100%) create mode 100644 e2e/paths/13-supplier/05_address.spec.js rename e2e/paths/13-supplier/{04_contact.spec.js => 06_contact.spec.js} (100%) diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index dd80f0021..f8e0cbf47 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -1097,17 +1097,6 @@ export default { clientButton: 'vn-supplier-descriptor vn-icon[icon="person"]', entriesButton: 'vn-supplier-descriptor vn-icon[icon="icon-entry"]', }, - supplierContact: { - anyContact: 'vn-supplier-contact > form > vn-card > div', - addNewContact: 'vn-supplier-contact vn-icon[icon="add_circle"]', - thirdContactName: 'vn-supplier-contact div:nth-child(3) vn-textfield[ng-model="contact.name"]', - thirdContactPhone: 'vn-supplier-contact div:nth-child(3) vn-textfield[ng-model="contact.phone"]', - thirdContactMobile: 'vn-supplier-contact div:nth-child(3) vn-textfield[ng-model="contact.mobile"]', - thirdContactEmail: 'vn-supplier-contact div:nth-child(3) vn-textfield[ng-model="contact.email"]', - thirdContactNotes: 'vn-supplier-contact div:nth-child(3) vn-textfield[ng-model="contact.observation"]', - saveButton: 'vn-supplier-contact button[type="submit"]', - thirdContactDeleteButton: 'vn-supplier-contact div:nth-child(3) vn-icon-button[icon="delete"]' - }, supplierBasicData: { alias: 'vn-supplier-basic-data vn-textfield[ng-model="$ctrl.supplier.nickname"]', isSerious: 'vn-supplier-basic-data vn-check[ng-model="$ctrl.supplier.isSerious"]', @@ -1132,5 +1121,36 @@ export default { payDem: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payDemFk"]', payDay: 'vn-supplier-billing-data vn-input-number[ng-model="$ctrl.supplier.payDay"]', saveButton: 'vn-supplier-billing-data button[type=submit]' - } + }, + supplierAddress: { + anyAddress: 'vn-supplier-address-index a', + thirdAddress: 'vn-supplier-address-index vn-card > div:nth-child(3) > a', + newAddress: 'vn-supplier-address-index vn-float-button[icon="add"]', + newNickname: 'vn-supplier-address-create vn-textfield[ng-model="$ctrl.address.nickname"]', + newStreet: 'vn-supplier-address-create vn-textfield[ng-model="$ctrl.address.street"]', + newPostcode: 'vn-supplier-address-create vn-datalist[ng-model="$ctrl.address.postalCode"]', + newCity: 'vn-supplier-address-create vn-datalist[ng-model="$ctrl.address.city"]', + newProvince: 'vn-supplier-address-create vn-autocomplete[ng-model="$ctrl.address.provinceFk"]', + newPhone: 'vn-supplier-address-create vn-textfield[ng-model="$ctrl.address.phone"]', + newMobile: 'vn-supplier-address-create vn-textfield[ng-model="$ctrl.address.mobile"]', + editNickname: 'vn-supplier-address-edit vn-textfield[ng-model="$ctrl.address.nickname"]', + editStreet: 'vn-supplier-address-edit vn-textfield[ng-model="$ctrl.address.street"]', + editPostcode: 'vn-supplier-address-edit vn-datalist[ng-model="$ctrl.address.postalCode"]', + editCity: 'vn-supplier-address-edit vn-datalist[ng-model="$ctrl.address.city"]', + editProvince: 'vn-supplier-address-edit vn-autocomplete[ng-model="$ctrl.address.provinceFk"]', + editPhone: 'vn-supplier-address-edit vn-textfield[ng-model="$ctrl.address.phone"]', + editMobile: 'vn-supplier-address-edit vn-textfield[ng-model="$ctrl.address.mobile"]', + saveButton: 'button[type="submit"]' + }, + supplierContact: { + anyContact: 'vn-supplier-contact > form > vn-card > div', + addNewContact: 'vn-supplier-contact vn-icon[icon="add_circle"]', + thirdContactName: 'vn-supplier-contact div:nth-child(3) vn-textfield[ng-model="contact.name"]', + thirdContactPhone: 'vn-supplier-contact div:nth-child(3) vn-textfield[ng-model="contact.phone"]', + thirdContactMobile: 'vn-supplier-contact div:nth-child(3) vn-textfield[ng-model="contact.mobile"]', + thirdContactEmail: 'vn-supplier-contact div:nth-child(3) vn-textfield[ng-model="contact.email"]', + thirdContactNotes: 'vn-supplier-contact div:nth-child(3) vn-textfield[ng-model="contact.observation"]', + saveButton: 'vn-supplier-contact button[type="submit"]', + thirdContactDeleteButton: 'vn-supplier-contact div:nth-child(3) vn-icon-button[icon="delete"]' + }, }; diff --git a/e2e/paths/13-supplier/05_billing_data.spec.js b/e2e/paths/13-supplier/04_billing_data.spec.js similarity index 100% rename from e2e/paths/13-supplier/05_billing_data.spec.js rename to e2e/paths/13-supplier/04_billing_data.spec.js diff --git a/e2e/paths/13-supplier/05_address.spec.js b/e2e/paths/13-supplier/05_address.spec.js new file mode 100644 index 000000000..5bccba3ee --- /dev/null +++ b/e2e/paths/13-supplier/05_address.spec.js @@ -0,0 +1,79 @@ +import selectors from '../../helpers/selectors.js'; +import getBrowser from '../../helpers/puppeteer'; + +describe('Supplier address path', () => { + let browser; + let page; + + beforeAll(async() => { + browser = await getBrowser(); + page = browser.page; + await page.loginAndModule('employee', 'supplier'); + await page.accessToSearchResult('1'); + await page.accessToSection('supplier.card.address.index'); + }); + + afterAll(async() => { + await browser.close(); + }); + + it('should count the addresses before creating one', async() => { + const count = await page.countElement(selectors.supplierAddress.anyAddress); + + expect(count).toEqual(2); + }); + + it('should open the new address form by clicking the add button', async() => { + await page.waitToClick(selectors.supplierAddress.newAddress); + await page.waitForState('supplier.card.address.create'); + }); + + it('should create a new address', async() => { + await page.write(selectors.supplierAddress.newNickname, 'Darkest dungeon'); + await page.write(selectors.supplierAddress.newStreet, 'Wayne manor'); + await page.write(selectors.supplierAddress.newPostcode, '46000'); + await page.write(selectors.supplierAddress.newCity, 'Valencia'); + await page.autocompleteSearch(selectors.supplierAddress.newProvince, 'Province one'); + await page.write(selectors.supplierAddress.newPhone, '888888888'); + await page.write(selectors.supplierAddress.newMobile, '444444444'); + await page.waitToClick(selectors.supplierAddress.saveButton); + const message = await page.waitForSnackbar(); + + expect(message.text).toContain('Data saved!'); + }); + + it('should have been redirected to the addresses index', async() => { + await page.waitForState('supplier.card.address.index'); + }); + + it('should count the addresses and find one more now', async() => { + const count = await page.countElement(selectors.supplierAddress.anyAddress); + + expect(count).toEqual(3); + }); + + it('should open the edit address form by clicking the new address', async() => { + await page.waitToClick(selectors.supplierAddress.thirdAddress); + await page.waitForState('supplier.card.address.edit'); + }); + + it('should edit the address', async() => { + await page.overwrite(selectors.supplierAddress.editNickname, 'Wayne manor'); + await page.overwrite(selectors.supplierAddress.editStreet, '1007 Mountain Drive'); + await page.overwrite(selectors.supplierAddress.editPostcode, '46000'); + await page.overwrite(selectors.supplierAddress.editCity, 'Valencia'); + await page.autocompleteSearch(selectors.supplierAddress.editProvince, 'Province one'); + await page.overwrite(selectors.supplierAddress.editPhone, '777777777'); + await page.overwrite(selectors.supplierAddress.editMobile, '555555555'); + await page.waitToClick(selectors.supplierAddress.saveButton); + const message = await page.waitForSnackbar(); + + expect(message.text).toContain('Data saved!'); + }); + + it('should check the address has now the expected data', async() => { + let thirdAddress = await page.waitToGetProperty(selectors.supplierAddress.thirdAddress, 'innerText'); + + expect(thirdAddress).toContain('Wayne manor'); + }); +}); diff --git a/e2e/paths/13-supplier/04_contact.spec.js b/e2e/paths/13-supplier/06_contact.spec.js similarity index 100% rename from e2e/paths/13-supplier/04_contact.spec.js rename to e2e/paths/13-supplier/06_contact.spec.js