diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 25dc82324..6ef96c488 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -78,7 +78,7 @@ INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossF INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`) VALUES - (1, 'España', 0, 'ES', 1, 24), + (1, 'España', 1, 'ES', 1, 24), (2, 'Italia', 1, 'IT', 1, 27), (3, 'Alemania', 1, 'DE', 1, 22), (4, 'Rumania', 1, 'RO', 1, 24), @@ -182,8 +182,8 @@ INSERT INTO `vn`.`province`(`id`, `name`, `countryFk`, `warehouseFk`) (1, 'Province one', 1, NULL), (2, 'Province two', 1, NULL), (3, 'Province three', 1, NULL), - (4, 'Province four', 1, NULL), - (5, 'Province five', 2, NULL); + (4, 'Province four', 2, NULL), + (5, 'Province five', 13, NULL); INSERT INTO `vn`.`town`(`id`, `name`, `provinceFk`) VALUES @@ -1966,3 +1966,8 @@ INSERT INTO `vn`.`travelThermograph`(`thermographFk`, `created`, `warehouseFk`, INSERT INTO `vn`.`incoterms` (`code`, `name`) VALUES ('FAS', 'Free Alongside Ship'); + +INSERT INTO `vn`.`customsAgent` (`id`, `fiscalName`, `street`, `nif`, `phone`, `email`) + VALUES + (1, 'Agent one', '1007 Mountain Drive, Gotham', 'N1111111111', '111111111', 'agentone@gotham.com'), + (2, 'Agent two', '1007 Mountain Drive, Gotham', 'N2222222222', '222222222', 'agenttwo@gotham.com'); \ No newline at end of file diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 70d06c9bd..584ecbedd 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -61,5 +61,7 @@ "MESSAGE_BOUGHT_UNITS": "Bought {{quantity}} units of {{concept}} (#{{itemId}}) for the ticket id [#{{ticketId}}]({{{url}}})", "MESSAGE_INSURANCE_CHANGE": "I have changed the insurence credit of client [{{clientName}} (#{{clientId}})]({{{url}}}) to *{{credit}} €*", "MESSAGE_CHANGED_PAYMETHOD": "I have changed the pay method for client [{{clientName}} (#{{clientId}})]({{{url}}})", - "MESSAGE_CLAIM_ITEM_REGULARIZE": "I sent *{{quantity}}* units of [{{concept}} (#{{itemId}})]({{{itemUrl}}}) to {{nickname}} coming from ticket id [#{{ticketId}}]({{{ticketUrl}}})" + "MESSAGE_CLAIM_ITEM_REGULARIZE": "I sent *{{quantity}}* units of [{{concept}} (#{{itemId}})]({{{itemUrl}}}) to {{nickname}} coming from ticket id [#{{ticketId}}]({{{ticketUrl}}})", + "Customs agent is required for a non UEE member": "Customs agent is required for a non UEE member", + "Incoterms is required for a non UEE member": "Incoterms is required for a non UEE member" } \ No newline at end of file diff --git a/modules/client/back/methods/address/createDefaultAddress.js b/modules/client/back/methods/address/createDefaultAddress.js deleted file mode 100644 index e524a6017..000000000 --- a/modules/client/back/methods/address/createDefaultAddress.js +++ /dev/null @@ -1,44 +0,0 @@ -module.exports = function(Self) { - Self.remoteMethod('createDefaultAddress', { - description: 'Creates both client and its web account', - accepts: { - arg: 'data', - type: 'object', - http: {source: 'body'} - }, - returns: { - root: true, - type: 'Object' - }, - http: { - verb: 'post', - path: '/createDefaultAddress' - } - }); - - Self.createDefaultAddress = async data => { - const Address = Self.app.models.Address; - const Client = Self.app.models.Client; - const tx = await Address.beginTransaction({}); - - try { - let options = {transaction: tx}; - - let address = data.address; - let newAddress = await Address.create(address, options); - let client = await Client.findById(address.clientFk, null, options); - - if (data.isDefaultAddress) { - await client.updateAttributes({ - defaultAddressFk: newAddress.id - }, options); - } - - await tx.commit(); - return newAddress; - } catch (e) { - await tx.rollback(); - throw e; - } - }; -}; diff --git a/modules/client/back/methods/address/specs/createDefaultAddress.spec.js b/modules/client/back/methods/address/specs/createDefaultAddress.spec.js deleted file mode 100644 index 452d9c9b7..000000000 --- a/modules/client/back/methods/address/specs/createDefaultAddress.spec.js +++ /dev/null @@ -1,37 +0,0 @@ -const app = require('vn-loopback/server/server'); - -describe('Address createDefaultAddress', () => { - let address; - let client; - - afterAll(async done => { - await client.updateAttributes({defaultAddressFk: 1}); - await address.destroy(); - - done(); - }); - - it('should verify that client defaultAddressFk is untainted', async() => { - client = await app.models.Client.findById(101); - - expect(client.defaultAddressFk).toEqual(1); - }); - - it('should create a new address and set as a client default address', async() => { - let data = { - address: { - clientFk: 101, - nickname: 'My address', - street: 'Wall Street', - city: 'New York', - - }, - isDefaultAddress: true - }; - - address = await app.models.Address.createDefaultAddress(data); - client = await app.models.Client.findById(101); - - expect(client.defaultAddressFk).toEqual(address.id); - }); -}); diff --git a/modules/client/back/methods/client/createAddress.js b/modules/client/back/methods/client/createAddress.js new file mode 100644 index 000000000..0319fc386 --- /dev/null +++ b/modules/client/back/methods/client/createAddress.js @@ -0,0 +1,121 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = function(Self) { + Self.remoteMethodCtx('createAddress', { + description: 'Creates client address updating default address', + accepts: [{ + arg: 'id', + type: 'Number', + description: 'The client 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: 'provinceId', + type: 'Number' + }, + { + arg: 'agencyModeId', + type: 'Number' + }, + { + arg: 'incotermsId', + type: 'String' + }, + { + arg: 'customsAgentId', + type: 'Number' + }, + { + arg: 'isActive', + type: 'Boolean' + }, + { + arg: 'isDefaultAddress', + type: 'Boolean' + }], + returns: { + root: true, + type: 'Object' + }, + http: { + verb: 'post', + path: '/:id/createAddress' + } + }); + + Self.createAddress = async(ctx, clientId) => { + 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.provinceId, { + include: { + relation: 'country' + } + }, options); + + const isUeeMember = province.country().isUeeMember; + if (!isUeeMember && !args.incotermsId) + throw new UserError(`Incoterms is required for a non UEE member`); + + if (!isUeeMember && !args.customsAgentId) + throw new UserError(`Customs agent is required for a non UEE member`); + + const newAddress = await models.Address.create({ + clientFk: clientId, + nickname: args.nickname, + incotermsFk: args.incotermsId, + customsAgentFk: args.customsAgentId, + city: args.city, + street: args.street, + phone: args.phone, + postalCode: args.postalCode, + provinceFk: args.provinceId, + agencyModeFk: args.agencyModeId, + isActive: args.isActive + }, options); + const client = await Self.findById(clientId, 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/client/back/methods/client/specs/createAddress.spec.js b/modules/client/back/methods/client/specs/createAddress.spec.js new file mode 100644 index 000000000..29f9e145f --- /dev/null +++ b/modules/client/back/methods/client/specs/createAddress.spec.js @@ -0,0 +1,87 @@ +const app = require('vn-loopback/server/server'); + +describe('Address createAddress', () => { + const clientId = 101; + const provinceId = 5; + const incotermsId = 'FAS'; + const customAgentOneId = 1; + let address; + let client; + + afterAll(async done => { + await client.updateAttributes({defaultAddressFk: 1}); + await address.destroy(); + + done(); + }); + + it('should throw a non uee member error if no incoterms is defined', async() => { + const expectedResult = 'My edited address'; + const ctx = { + args: { + provinceId: provinceId, + nickname: expectedResult, + street: 'Wall Street', + city: 'New York', + customsAgentId: customAgentOneId + } + }; + + try { + await app.models.Client.createAddress(ctx, clientId); + } catch (e) { + err = e; + } + + expect(err).toBeDefined(); + expect(err.message).toEqual('Incoterms is required for a non UEE member'); + }); + + it('should throw a non uee member error if no customsAgent is defined', async() => { + const expectedResult = 'My edited address'; + const ctx = { + args: { + provinceId: provinceId, + nickname: expectedResult, + street: 'Wall Street', + city: 'New York', + incotermsId: incotermsId + } + }; + + + try { + await app.models.Client.createAddress(ctx, clientId); + } catch (e) { + err = e; + } + + expect(err).toBeDefined(); + expect(err.message).toEqual('Customs agent is required for a non UEE member'); + }); + + it('should verify that client defaultAddressFk is untainted', async() => { + client = await app.models.Client.findById(clientId); + + expect(client.defaultAddressFk).toEqual(1); + }); + + it('should create a new address and set as a client default address', async() => { + const ctx = { + args: { + provinceId: 1, + nickname: 'My address', + street: 'Wall Street', + city: 'New York', + incotermsId: incotermsId, + customsAgentId: customAgentOneId, + isDefaultAddress: true + } + }; + + address = await app.models.Client.createAddress(ctx, clientId); + client = await app.models.Client.findById(clientId); + + expect(client.defaultAddressFk).toEqual(address.id); + }); +}); diff --git a/modules/client/back/methods/client/specs/updateAddress.spec.js b/modules/client/back/methods/client/specs/updateAddress.spec.js new file mode 100644 index 000000000..a4cf07891 --- /dev/null +++ b/modules/client/back/methods/client/specs/updateAddress.spec.js @@ -0,0 +1,100 @@ +const app = require('vn-loopback/server/server'); + +describe('Address updateAddress', () => { + const clientId = 101; + const addressId = 1; + const provinceId = 5; + const incotermsId = 'FAS'; + const customAgentOneId = 1; + let oldAddress; + let address; + + afterAll(async done => { + await address.updateAttributes({ + nickname: oldAddress.nickname, + provinceFk: 1, + customsAgentFk: null, + incotermsFk: null + }); + + done(); + }); + + it('should throw a non uee member error if no incoterms is defined', async() => { + const expectedResult = 'My edited address'; + const ctx = { + args: { + provinceFk: provinceId, + nickname: expectedResult, + customsAgentFk: customAgentOneId + } + }; + + try { + await app.models.Client.updateAddress(ctx, clientId, addressId); + } catch (e) { + err = e; + } + + expect(err).toBeDefined(); + expect(err.message).toEqual('Incoterms is required for a non UEE member'); + }); + + it('should throw a non uee member error if no customsAgent is defined', async() => { + const expectedResult = 'My edited address'; + const ctx = { + args: { + provinceFk: provinceId, + nickname: expectedResult, + incotermsFk: incotermsId + } + }; + + + try { + await app.models.Client.updateAddress(ctx, clientId, addressId); + } catch (e) { + err = e; + } + + expect(err).toBeDefined(); + expect(err.message).toEqual('Customs agent is required for a non UEE member'); + }); + + it('should update the adress from a non uee member and not throw an error', async() => { + const expectedResult = 'My edited address'; + const ctx = { + args: { + provinceFk: provinceId, + nickname: expectedResult, + incotermsFk: incotermsId, + customsAgentFk: customAgentOneId + } + }; + + oldAddress = await app.models.Address.findById(addressId); + + await app.models.Client.updateAddress(ctx, clientId, addressId); + + address = await app.models.Address.findById(addressId); + + expect(address.nickname).toEqual(expectedResult); + }); + + it('should update the address', async() => { + const expectedResult = 'My second time edited address'; + const ctx = { + args: { + nickname: expectedResult + } + }; + + oldAddress = await app.models.Address.findById(addressId); + + await app.models.Client.updateAddress(ctx, clientId, addressId); + + address = await app.models.Address.findById(addressId); + + expect(address.nickname).toEqual(expectedResult); + }); +}); diff --git a/modules/client/back/methods/client/updateAddress.js b/modules/client/back/methods/client/updateAddress.js new file mode 100644 index 000000000..b9270600f --- /dev/null +++ b/modules/client/back/methods/client/updateAddress.js @@ -0,0 +1,119 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = function(Self) { + Self.remoteMethod('updateAddress', { + description: 'Updates a client address updating default address', + accepts: [{ + arg: 'ctx', + type: 'Object', + http: {source: 'context'} + }, + { + arg: 'clientId', + type: 'Number', + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'addressId', + type: 'Number', + description: 'The address id', + http: {source: 'path'} + }, + { + arg: 'nickname', + type: 'String' + }, + { + arg: 'city', + type: 'String' + }, + { + arg: 'street', + type: 'String' + }, + { + arg: 'phone', + type: 'String' + }, + { + arg: 'mobile', + type: 'String' + }, + { + arg: 'postalCode', + type: 'String' + }, + { + arg: 'provinceFk', + type: 'Number' + }, + { + arg: 'agencyModeFk', + type: 'Number' + }, + { + arg: 'incotermsFk', + type: 'String' + }, + { + arg: 'customsAgentFk', + type: 'Number' + }, + { + arg: 'isActive', + type: 'Boolean' + }, + { + arg: 'isEqualizated', + type: 'Boolean' + }], + returns: { + root: true, + type: 'Object' + }, + http: { + verb: 'patch', + path: '/:clientId/updateAddress/:addressId' + } + }); + + Self.updateAddress = async(ctx, clientId, addressId) => { + const models = Self.app.models; + const args = ctx.args; + const tx = await models.Address.beginTransaction({}); + try { + const options = {transaction: tx}; + const address = await models.Address.findOne({ + where: { + id: addressId, + clientFk: clientId + } + }); + const provinceId = args.provinceFk || address.provinceFk; + const province = await models.Province.findById(provinceId, { + include: { + relation: 'country' + } + }, options); + + const isUeeMember = province.country().isUeeMember; + const incotermsId = args.incotermsFk || address.incotermsFk; + if (!isUeeMember && !incotermsId) + throw new UserError(`Incoterms is required for a non UEE member`); + + const customsAgentId = args.customsAgentFk || address.customsAgentFk; + if (!isUeeMember && !customsAgentId) + throw new UserError(`Customs agent is required for a non UEE member`); + + delete args.ctx; // Remove unwanted properties + const updatedAddress = await address.updateAttributes(ctx.args, options); + + await tx.commit(); + return updatedAddress; + } catch (e) { + await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/client/back/models/address.js b/modules/client/back/models/address.js index 4e23f5d12..ffcaf39da 100644 --- a/modules/client/back/models/address.js +++ b/modules/client/back/models/address.js @@ -3,9 +3,6 @@ let getFinalState = require('vn-loopback/util/hook').getFinalState; let isMultiple = require('vn-loopback/util/hook').isMultiple; module.exports = Self => { - // Methods - require('../methods/address/createDefaultAddress')(Self); - Self.validateAsync('isEqualizated', cannotHaveET, { message: 'Cannot check Equalization Tax in this NIF/CIF' }); @@ -25,35 +22,6 @@ module.exports = Self => { done(); } - Self.validateAsync('customsAgentFk', validateCustomsAgent, - {message: 'Customs agent is required for a non UEE member'} - ); - - async function validateCustomsAgent(err, done) { - if (!await isUeeMember(this.provinceFk) && !this.customsAgentFk) err(); - done(); - } - - Self.validateAsync('incotermsFk', validateIncoterms, - {message: 'Incoterms is required for a non UEE member'} - ); - - async function validateIncoterms(err, done) { - if (!await isUeeMember(this.provinceFk) && !this.incotermsFk) err(); - done(); - } - - async function isUeeMember(provinceId) { - const models = Self.app.models; - const province = await models.Province.findById(provinceId, { - include: { - relation: 'country' - } - }); - - return province.country().isUeeMember; - } - Self.validateAsync('postalCode', hasValidPostcode, { message: `The postcode doesn't exists. Ensure you put the correct format` }); diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 1dba6c6db..198aae2cd 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -25,6 +25,8 @@ module.exports = Self => { require('../methods/client/uploadFile')(Self); require('../methods/client/lastActiveTickets')(Self); require('../methods/client/sendSms')(Self); + require('../methods/client/createAddress')(Self); + require('../methods/client/updateAddress')(Self); // Validations diff --git a/modules/client/back/models/specs/address.spec.js b/modules/client/back/models/specs/address.spec.js index 49fb709bf..685acc80d 100644 --- a/modules/client/back/models/specs/address.spec.js +++ b/modules/client/back/models/specs/address.spec.js @@ -2,9 +2,10 @@ const app = require('vn-loopback/server/server'); describe('loopback model address', () => { let createdAddressId; + const clientId = 101; afterAll(async done => { - let client = await app.models.Client.findById(101); + let client = await app.models.Client.findById(clientId); await app.models.Address.destroyById(createdAddressId); await client.updateAttribute('isEqualizated', false); @@ -28,14 +29,14 @@ describe('loopback model address', () => { }); it('should set isEqualizated to true of a given Client to trigger any new address to have it', async() => { - let client = await app.models.Client.findById(101); + let client = await app.models.Client.findById(clientId); expect(client.isEqualizated).toBeFalsy(); await client.updateAttribute('isEqualizated', true); let newAddress = await app.models.Address.create({ - clientFk: 101, + clientFk: clientId, agencyModeFk: 5, city: 'here', isActive: true, @@ -44,7 +45,9 @@ describe('loopback model address', () => { phone: '555555555', postalCode: '46000', provinceFk: 1, - street: 'Test address' + street: 'Test address', + incotermsFk: 'FAS', + customsAgentFk: 1 }); expect(newAddress.isEqualizated).toBeTruthy(); diff --git a/modules/client/front/address/create/index.html b/modules/client/front/address/create/index.html index 3fe51a16e..fabc12bf9 100644 --- a/modules/client/front/address/create/index.html +++ b/modules/client/front/address/create/index.html @@ -1,8 +1,9 @@ @@ -19,7 +20,7 @@ + label="Default" ng-model="$ctrl.address.isDefaultAddress"> @@ -41,7 +42,7 @@ { - if (res.data && this.data.isDefaultAddress) + if (this.address.isDefaultAddress) this.client.defaultAddressFk = res.data.id; this.$state.go('client.card.address.index'); diff --git a/modules/client/front/address/create/index.spec.js b/modules/client/front/address/create/index.spec.js index 0b1f5c532..6bd53cb72 100644 --- a/modules/client/front/address/create/index.spec.js +++ b/modules/client/front/address/create/index.spec.js @@ -30,14 +30,13 @@ describe('Client', () => { })); it('should define and set address property', () => { - expect(controller.data.address.clientFk).toBe(1234); - expect(controller.data.address.isActive).toBe(true); + expect(controller.address.isActive).toBe(true); }); describe('onSubmit()', () => { it('should perform a PATCH and not set value to defaultAddressFk property', () => { spyOn(controller.$state, 'go'); - controller.data.isDefaultAddress = false; + controller.address.isDefaultAddress = false; controller.onSubmit(); expect(controller.client.defaultAddressFk).toEqual(121); @@ -46,7 +45,7 @@ describe('Client', () => { it('should perform a PATCH and set a value to defaultAddressFk property', () => { spyOn(controller.$state, 'go'); - controller.data.isDefaultAddress = true; + controller.address.isDefaultAddress = true; controller.onSubmit(); expect(controller.client.defaultAddressFk).toEqual(124); diff --git a/modules/client/front/address/edit/index.html b/modules/client/front/address/edit/index.html index 1032e25f5..ed331de2e 100644 --- a/modules/client/front/address/edit/index.html +++ b/modules/client/front/address/edit/index.html @@ -6,9 +6,9 @@ this.$.model.save(true)) .then(() => { - this.$.watcher.notifySaved(); this.card.reload(); this.goToIndex(); });