diff --git a/db/changes/10460-motherDay/delete.keep b/db/changes/10460-motherDay/delete.keep new file mode 100644 index 000000000..0e7498f40 --- /dev/null +++ b/db/changes/10460-motherDay/delete.keep @@ -0,0 +1 @@ +Delete file \ No newline at end of file diff --git a/e2e/paths/02-client/12_lock_of_verified_data.spec.js b/e2e/paths/02-client/12_lock_of_verified_data.spec.js index 701531c76..af42e2a4b 100644 --- a/e2e/paths/02-client/12_lock_of_verified_data.spec.js +++ b/e2e/paths/02-client/12_lock_of_verified_data.spec.js @@ -111,7 +111,7 @@ describe('Client lock verified data path', () => { await page.waitToClick(selectors.clientFiscalData.saveButton); const message = await page.waitForSnackbar(); - expect(message.text).toContain(`You can't make changes on a client with verified data`); + expect(message.text).toContain(`Not enough privileges to edit a client with verified data`); }); }); @@ -123,19 +123,19 @@ describe('Client lock verified data path', () => { await page.accessToSection('client.card.fiscalData'); }, 20000); - it('should confirm verified data button is enabled for salesAssistant', async() => { + it('should confirm verified data button is disabled for salesAssistant', async() => { const isDisabled = await page.isDisabled(selectors.clientFiscalData.verifiedDataCheckbox); - expect(isDisabled).toBeFalsy(); + expect(isDisabled).toBeTrue(); }); - it('should now edit the social name', async() => { + it('should return error when edit the social name', async() => { await page.clearInput(selectors.clientFiscalData.socialName); await page.write(selectors.clientFiscalData.socialName, 'new social name edition'); await page.waitToClick(selectors.clientFiscalData.saveButton); const message = await page.waitForSnackbar(); - expect(message.text).toContain('Data saved!'); + expect(message.text).toContain(`Not enough privileges to edit a client with verified data`); }); it('should now confirm the social name have been edited once and for all', async() => { diff --git a/loopback/locale/en.json b/loopback/locale/en.json index b7242befb..b7e9b43d3 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -12,7 +12,6 @@ "That payment method requires an IBAN": "That payment method requires an IBAN", "That payment method requires a BIC": "That payment method requires a BIC", "The default consignee can not be unchecked": "The default consignee can not be unchecked", - "You can't make changes on a client with verified data": "You can't make changes on a client with verified data", "Enter an integer different to zero": "Enter an integer different to zero", "Package cannot be blank": "Package cannot be blank", "The new quantity should be smaller than the old one": "The new quantity should be smaller than the old one", @@ -123,5 +122,6 @@ "The type of business must be filled in basic data": "The type of business must be filled in basic data", "The worker has hours recorded that day": "The worker has hours recorded that day", "isWithoutNegatives": "isWithoutNegatives", - "routeFk": "routeFk" + "routeFk": "routeFk", + "Not enough privileges to edit a client with verified data": "Not enough privileges to edit a client with verified data" } \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 77bd21780..a44ba2da8 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -50,7 +50,7 @@ "You don't have enough privileges to change that field": "No tienes permisos para cambiar ese campo", "Warehouse cannot be blank": "El almacén no puede quedar en blanco", "Agency cannot be blank": "La agencia no puede quedar en blanco", - "You can't make changes on a client with verified data": "No puedes hacer cambios en un cliente con datos comprobados", + "Not enough privileges to edit a client with verified data": "No tienes permisos para hacer cambios en un cliente con datos comprobados", "This address doesn't exist": "Este consignatario no existe", "You must delete the claim id %d first": "Antes debes borrar la reclamación %d", "You don't have enough privileges": "No tienes suficientes permisos", diff --git a/modules/client/back/methods/client/specs/addressesPropagateRe.spec.js b/modules/client/back/methods/client/specs/addressesPropagateRe.spec.js index 069c7bd25..74d80b964 100644 --- a/modules/client/back/methods/client/specs/addressesPropagateRe.spec.js +++ b/modules/client/back/methods/client/specs/addressesPropagateRe.spec.js @@ -1,6 +1,22 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('Client addressesPropagateRe', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should propagate the isEqualizated on both addresses of Mr Wayne and set hasToInvoiceByAddress to false', async() => { const tx = await models.Client.beginTransaction({}); diff --git a/modules/client/back/methods/client/specs/createAddress.spec.js b/modules/client/back/methods/client/specs/createAddress.spec.js index d6178ae0d..0841ad98c 100644 --- a/modules/client/back/methods/client/specs/createAddress.spec.js +++ b/modules/client/back/methods/client/specs/createAddress.spec.js @@ -1,4 +1,5 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('Address createAddress', () => { const clientFk = 1101; @@ -6,6 +7,21 @@ describe('Address createAddress', () => { const incotermsFk = 'FAS'; const customAgentOneId = 1; + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should throw a non uee member error if no incoterms is defined', async() => { const tx = await models.Client.beginTransaction({}); diff --git a/modules/client/back/methods/client/specs/createWithUser.spec.js b/modules/client/back/methods/client/specs/createWithUser.spec.js index 4c827c745..7d4261aee 100644 --- a/modules/client/back/methods/client/specs/createWithUser.spec.js +++ b/modules/client/back/methods/client/specs/createWithUser.spec.js @@ -1,4 +1,5 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('Client Create', () => { const newAccount = { @@ -12,6 +13,21 @@ describe('Client Create', () => { businessTypeFk: 'florist' }; + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it(`should not find Deadpool as he's not created yet`, async() => { const tx = await models.Client.beginTransaction({}); diff --git a/modules/client/back/methods/client/specs/updateAddress.spec.js b/modules/client/back/methods/client/specs/updateAddress.spec.js index 2ad564cc5..6f02323c5 100644 --- a/modules/client/back/methods/client/specs/updateAddress.spec.js +++ b/modules/client/back/methods/client/specs/updateAddress.spec.js @@ -1,4 +1,5 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('Address updateAddress', () => { const clientId = 1101; @@ -13,6 +14,21 @@ describe('Address updateAddress', () => { } }; + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should throw the non uee member error if no incoterms is defined', async() => { const tx = await models.Client.beginTransaction({}); @@ -93,6 +109,7 @@ describe('Address updateAddress', () => { try { const options = {transaction: tx}; + ctx.req.accessToken.userId = employeeId; ctx.args = { isLogifloraAllowed: true }; diff --git a/modules/client/back/methods/client/specs/updateFiscalData.spec.js b/modules/client/back/methods/client/specs/updateFiscalData.spec.js index 7c0bc0599..a08f97faf 100644 --- a/modules/client/back/methods/client/specs/updateFiscalData.spec.js +++ b/modules/client/back/methods/client/specs/updateFiscalData.spec.js @@ -1,10 +1,25 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('Client updateFiscalData', () => { const clientId = 1101; const employeeId = 1; const salesAssistantId = 21; const administrativeId = 5; + const activeCtx = { + accessToken: {userId: employeeId}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + + beforeEach(() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); it('should return an error if the user is not salesAssistant and the isTaxDataChecked value is true', async() => { const tx = await models.Client.beginTransaction({}); @@ -24,7 +39,7 @@ describe('Client updateFiscalData', () => { error = e; } - expect(error.message).toEqual(`You can't make changes on a client with verified data`); + expect(error.message).toEqual(`Not enough privileges to edit a client with verified data`); }); it('should return an error if the salesAssistant did not fill the sage data before checking verified data', async() => { diff --git a/modules/client/back/methods/client/updateFiscalData.js b/modules/client/back/methods/client/updateFiscalData.js index 539d89d3a..c2de8f927 100644 --- a/modules/client/back/methods/client/updateFiscalData.js +++ b/modules/client/back/methods/client/updateFiscalData.js @@ -125,11 +125,11 @@ module.exports = Self => { } try { - const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant', myOptions); + const isAdministrative = await models.Account.hasRole(userId, 'administrative', myOptions); const client = await models.Client.findById(clientId, null, myOptions); - if (!isSalesAssistant && client.isTaxDataChecked) - throw new UserError(`You can't make changes on a client with verified data`); + if (!isAdministrative && client.isTaxDataChecked) + throw new UserError(`Not enough privileges to edit a client with verified data`); // Sage data validation const taxDataChecked = args.isTaxDataChecked; diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 9b4d411c8..5ed777ab5 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -224,6 +224,34 @@ module.exports = Self => { throw new UserError(`The type of business must be filled in basic data`); }); + Self.observe('before save', async ctx => { + const changes = ctx.data || ctx.instance; + const orgData = ctx.currentInstance; + const models = Self.app.models; + + const loopBackContext = LoopBackContext.getCurrentContext(); + const userId = loopBackContext.active.accessToken.userId; + + const isAdministrative = await models.Account.hasRole(userId, 'administrative', ctx.options); + const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant', ctx.options); + const hasChanges = orgData && changes; + + const isTaxDataChecked = hasChanges && (changes.isTaxDataChecked || orgData.isTaxDataChecked); + const isTaxDataCheckedChanged = hasChanges && orgData.isTaxDataChecked != isTaxDataChecked; + + const sageTaxType = hasChanges && (changes.sageTaxTypeFk || orgData.sageTaxTypeFk); + const sageTaxTypeChanged = hasChanges && orgData.sageTaxTypeFk != sageTaxType; + + const sageTransactionType = hasChanges && (changes.sageTransactionTypeFk || orgData.sageTransactionTypeFk); + const sageTransactionTypeChanged = hasChanges && orgData.sageTransactionTypeFk != sageTransactionType; + + const cantEditVerifiedData = isTaxDataCheckedChanged && !isAdministrative; + const cantChangeSageData = (sageTaxTypeChanged || sageTransactionTypeChanged) && !isSalesAssistant; + + if (cantEditVerifiedData || cantChangeSageData) + throw new UserError(`You don't have enough privileges`); + }); + Self.observe('before save', async function(ctx) { const changes = ctx.data || ctx.instance; const orgData = ctx.currentInstance; @@ -237,10 +265,10 @@ module.exports = Self => { const socialNameChanged = hasChanges && orgData.socialName != socialName; - const dataCheckedChanged = hasChanges + const isTaxDataCheckedChanged = hasChanges && orgData.isTaxDataChecked != isTaxDataChecked; - if ((socialNameChanged || dataCheckedChanged) && !isAlpha(socialName)) + if ((socialNameChanged || isTaxDataCheckedChanged) && !isAlpha(socialName)) throw new UserError(`The social name has an invalid format`); if (changes.salesPerson === null) { diff --git a/modules/client/back/models/specs/address.spec.js b/modules/client/back/models/specs/address.spec.js index cae18258f..81af6ee28 100644 --- a/modules/client/back/models/specs/address.spec.js +++ b/modules/client/back/models/specs/address.spec.js @@ -1,20 +1,36 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('loopback model address', () => { let createdAddressId; const clientId = 1101; - afterAll(async() => { - let client = await app.models.Client.findById(clientId); + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; - await app.models.Address.destroyById(createdAddressId); + beforeEach(() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + + afterAll(async() => { + const client = await models.Client.findById(clientId); + + await models.Address.destroyById(createdAddressId); await client.updateAttribute('isEqualizated', false); }); describe('observe()', () => { it('should throw an error when deactivating a consignee if its the default address', async() => { let error; - let address = await app.models.Address.findById(1); + const address = await models.Address.findById(1); await address.updateAttribute('isActive', false) .catch(e => { @@ -27,13 +43,13 @@ 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(clientId); + const client = await models.Client.findById(clientId); expect(client.isEqualizated).toBeFalsy(); await client.updateAttribute('isEqualizated', true); - let newAddress = await app.models.Address.create({ + const newAddress = await models.Address.create({ clientFk: clientId, agencyModeFk: 5, city: 'here', diff --git a/modules/client/front/fiscal-data/index.html b/modules/client/front/fiscal-data/index.html index f3fd42e76..2249127c5 100644 --- a/modules/client/front/fiscal-data/index.html +++ b/modules/client/front/fiscal-data/index.html @@ -33,7 +33,7 @@ label="Social name" ng-model="$ctrl.client.socialName" rule - info="You can use letters and spaces" + info="Only letters, numbers and spaces can be used" required="true"> + vn-acl="administrative"> diff --git a/modules/client/front/fiscal-data/locale/es.yml b/modules/client/front/fiscal-data/locale/es.yml index 18c24604a..ed107ef4b 100644 --- a/modules/client/front/fiscal-data/locale/es.yml +++ b/modules/client/front/fiscal-data/locale/es.yml @@ -3,7 +3,7 @@ You changed the equalization tax: Has cambiado el recargo de equivalencia Do you want to spread the change?: ¿Deseas propagar el cambio a sus consignatarios? Frozen: Congelado In order to invoice, this field is not consulted, but the consignee's ET. When modifying this field if the invoice by address option is not checked, the change will be automatically propagated to all addresses, otherwise the user will be asked if he wants to propagate it or not.: Para facturar no se consulta este campo, sino el RE de consignatario. Al modificar este campo si no esta marcada la casilla Facturar por consignatario, se propagará automáticamente el cambio a todos los consignatarios, en caso contrario preguntará al usuario si quiere o no propagar. -You can use letters and spaces: Se pueden utilizar letras y espacios +Only letters, numbers and spaces can be used: Sólo se pueden usar letras, numeros y espacios Found a client with this data: Se ha encontrado un cliente con estos datos Found a client with this phone or email: El cliente con id {{clientId}} ya tiene este teléfono o email.
¿Quieres continuar? Sage tax type: Tipo de impuesto Sage diff --git a/modules/entry/front/summary/index.html b/modules/entry/front/summary/index.html index f443a94fe..a95b2f18a 100644 --- a/modules/entry/front/summary/index.html +++ b/modules/entry/front/summary/index.html @@ -1,6 +1,6 @@ diff --git a/modules/entry/front/summary/index.js b/modules/entry/front/summary/index.js index c949dba64..6e18bc959 100644 --- a/modules/entry/front/summary/index.js +++ b/modules/entry/front/summary/index.js @@ -4,6 +4,9 @@ import Summary from 'salix/components/summary'; class Controller extends Summary { get entry() { + if (!this._entry) + return this.$params; + return this._entry; } diff --git a/modules/invoiceIn/back/methods/invoice-in/filter.js b/modules/invoiceIn/back/methods/invoice-in/filter.js index 7e497d39a..f5eab9099 100644 --- a/modules/invoiceIn/back/methods/invoice-in/filter.js +++ b/modules/invoiceIn/back/methods/invoice-in/filter.js @@ -144,6 +144,7 @@ module.exports = Self => { ii.isBooked, ii.supplierRef, ii.docFk AS dmsFk, + dm.file, ii.supplierFk, ii.expenceFkDeductible deductibleExpenseFk, s.name AS supplierName, @@ -156,7 +157,8 @@ module.exports = Self => { LEFT JOIN duaInvoiceIn dii ON dii.invoiceInFk = ii.id LEFT JOIN dua d ON d.id = dii.duaFk LEFT JOIN awb ON awb.id = d.awbFk - LEFT JOIN company co ON co.id = ii.companyFk` + LEFT JOIN company co ON co.id = ii.companyFk + LEFT JOIN dms dm ON dm.id = ii.docFk` ); const sqlWhere = conn.makeWhere(filter.where); diff --git a/modules/invoiceIn/front/index/index.html b/modules/invoiceIn/front/index/index.html index 62074be33..008d615b1 100644 --- a/modules/invoiceIn/front/index/index.html +++ b/modules/invoiceIn/front/index/index.html @@ -13,7 +13,7 @@ Supplier ref. Serial number Serial - Account + File Issued Is booked AWB @@ -27,7 +27,7 @@ class="clickable vn-tr search-result" ui-sref="invoiceIn.card.summary({id: {{::invoiceIn.id}}})"> {{::invoiceIn.id}} - + @@ -36,8 +36,13 @@ {{::invoiceIn.supplierRef | dashIfEmpty}} {{::invoiceIn.serialNumber}} - {{::invoiceIn.serial}} - {{::invoiceIn.account}} + {{::invoiceIn.serial}} + + + {{::invoiceIn.file}} + + {{::invoiceIn.issued | date:'dd/MM/yyyy' | dashIfEmpty}} { it('should throw an error for a non-invoiceable client', async() => { spyOn(models.InvoiceOut, 'createPdf').and.returnValue(new Promise(resolve => resolve(true))); + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); const tx = await models.InvoiceOut.beginTransaction({}); const options = {transaction: tx}; diff --git a/modules/supplier/front/fiscal-data/index.html b/modules/supplier/front/fiscal-data/index.html index fc44468f4..4f34528f2 100644 --- a/modules/supplier/front/fiscal-data/index.html +++ b/modules/supplier/front/fiscal-data/index.html @@ -38,7 +38,7 @@ vn-focus label="Social name" ng-model="$ctrl.supplier.name" - info="You can use letters and spaces" + info="Only letters, numbers and spaces can be used" required="true" rule>