diff --git a/db/changes/10291-invoiceIn/.keep b/db/changes/10291-invoiceIn/.keep deleted file mode 100644 index 3a94d75a8..000000000 --- a/db/changes/10291-invoiceIn/.keep +++ /dev/null @@ -1 +0,0 @@ -Delete me \ No newline at end of file diff --git a/db/changes/10300-newFacility/.keep b/db/changes/10300-newFacility/.keep new file mode 100644 index 000000000..3ece1d69e --- /dev/null +++ b/db/changes/10300-newFacility/.keep @@ -0,0 +1 @@ +Delete this \ No newline at end of file diff --git a/e2e/paths/14-account/01_create_and_basic_data.spec.js b/e2e/paths/14-account/01_create_and_basic_data.spec.js index a4be62549..d1b825a0a 100644 --- a/e2e/paths/14-account/01_create_and_basic_data.spec.js +++ b/e2e/paths/14-account/01_create_and_basic_data.spec.js @@ -1,8 +1,7 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; -// #2833 Refactor account.basicData -xdescribe('Account create and basic data path', () => { +describe('Account create and basic data path', () => { let browser; let page; @@ -37,40 +36,23 @@ xdescribe('Account create and basic data path', () => { await page.waitForState('account.card.basicData'); }); - it('should edit the basic data', async() => { - await page.overwrite(selectors.accountBasicData.name, 'Anna'); - await page.overwrite(selectors.accountBasicData.nickname, 'Rogue'); - await page.overwrite(selectors.accountBasicData.email, 'AnnaMarieLeBeau@verdnatura.es'); - await page.autocompleteSearch(selectors.accountBasicData.language, 'english'); - await page.waitToClick(selectors.accountBasicData.save); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it('should reload the section and check the name was edited successfully', async() => { + it('should reload the section and check the name is as expected', async() => { await page.reloadSection('account.card.basicData'); const result = await page.waitToGetProperty(selectors.accountBasicData.name, 'value'); - expect(result).toEqual('Anna'); + expect(result).toEqual('Remy'); }); - it('should check the nickname was edited successfully', async() => { + it('should check the nickname is as expected', async() => { const result = await page.waitToGetProperty(selectors.accountBasicData.nickname, 'value'); - expect(result).toEqual('Rogue'); + expect(result).toEqual('Gambit'); }); - it('should check the email was edited successfully', async() => { + it('should check the email is as expected', async() => { const result = await page.waitToGetProperty(selectors.accountBasicData.email, 'value'); - expect(result).toEqual('AnnaMarieLeBeau@verdnatura.es'); - }); - - it('should check the language was edited successfully', async() => { - const result = await page.waitToGetProperty(selectors.accountBasicData.language, 'value'); - - expect(result).toEqual('English'); + expect(result).toEqual('RemyEtienneLeBeau@verdnatura.es'); }); it('should navigate to the roles section to check the roles are correct', async() => { diff --git a/front/salix/components/descriptor/index.html b/front/salix/components/descriptor/index.html index c786ebb93..5b4c6f12c 100644 --- a/front/salix/components/descriptor/index.html +++ b/front/salix/components/descriptor/index.html @@ -32,7 +32,7 @@
-
{{$ctrl.description}}
+
{{$ctrl.description}}
{{$ctrl.descriptor.id | id}}
diff --git a/front/salix/locale/es.yml b/front/salix/locale/es.yml index f2d81ee23..ae7eb1da7 100644 --- a/front/salix/locale/es.yml +++ b/front/salix/locale/es.yml @@ -42,7 +42,7 @@ Travels: Envíos Workers: Trabajadores Routes: Rutas Locator: Localizador -Invoices out: Facturas emitidas +Invoices out: Fact. emitidas Invoices in: Fact. recibidas Entries: Entradas Users: Usuarios diff --git a/loopback/common/models/loggable.js b/loopback/common/models/loggable.js index 557aad66a..956762be2 100644 --- a/loopback/common/models/loggable.js +++ b/loopback/common/models/loggable.js @@ -25,8 +25,8 @@ module.exports = function(Self) { if (ctx.data) { const changes = pick(ctx.currentInstance, Object.keys(ctx.data)); - newInstance = await fkToValue(ctx.data, ctx); - oldInstance = await fkToValue(changes, ctx); + newInstance = ctx.data; + oldInstance = changes; if (ctx.where && !ctx.currentInstance) { const fields = Object.keys(ctx.data); @@ -41,7 +41,7 @@ module.exports = function(Self) { // Get changes from created instance if (ctx.isNewInstance) - newInstance = await fkToValue(ctx.instance.__data, ctx); + newInstance = ctx.instance.__data; ctx.hookState.oldInstance = oldInstance; ctx.hookState.newInstance = newInstance; @@ -261,6 +261,9 @@ module.exports = function(Self) { removeUnloggable(definition, oldInstance); removeUnloggable(definition, newInstance); + oldInstance = await fkToValue(oldInstance, ctx); + newInstance = await fkToValue(newInstance, ctx); + // Prevent log with no new changes const hasNewChanges = Object.keys(newInstance).length; if (!hasNewChanges) return; diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 65028a8a8..c147e6c10 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -93,5 +93,7 @@ "New ticket request has been created": "New ticket request has been created *'{{description}}'* for day *{{shipped}}*, with a quantity of *{{quantity}}*", "There's a new urgent ticket": "There's a new urgent ticket: [{{title}}](https://cau.verdnatura.es/WorkOrder.do?woMode=viewWO&woID={{issueId}})", "Swift / BIC cannot be empty": "Swift / BIC cannot be empty", - "Role name must be written in camelCase": "Role name must be written in camelCase" + "Role name must be written in camelCase": "Role name must be written in camelCase", + "Client assignment has changed": "I did change the salesperson ~*\"<{{previousWorkerName}}>\"*~ by *\"<{{currentWorkerName}}>\"* from the client [{{clientName}} ({{clientId}})]({{{url}}})", + "None": "None" } \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 96858eb4a..b325b9176 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -176,5 +176,7 @@ "Invalid account": "Cuenta inválida", "Compensation account is empty": "La cuenta para compensar está vacia", "This genus already exist": "Este genus ya existe", - "This specie already exist": "Esta especie ya existe" + "This specie already exist": "Esta especie ya existe", + "Client assignment has changed": "He cambiado el comercial ~*\"<{{previousWorkerName}}>\"*~ por *\"<{{currentWorkerName}}>\"* del cliente [{{clientName}} ({{clientId}})]({{{url}}})", + "None": "Ninguno" } \ No newline at end of file diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 1e535a5d7..e1de363b2 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -227,36 +227,6 @@ module.exports = Self => { await Self.app.models.ClientCredit.create(newCredit); } }); - const app = require('vn-loopback/server/server'); - - app.on('started', function() { - let account = app.models.Account; - - account.observe('before save', async ctx => { - if (ctx.isNewInstance) return; - ctx.hookState.oldInstance = JSON.parse(JSON.stringify(ctx.currentInstance)); - }); - - account.observe('after save', async ctx => { - let changes = ctx.data || ctx.instance; - if (!ctx.isNewInstance && changes) { - let oldData = ctx.hookState.oldInstance; - let hasChanges = oldData.name != changes.name || oldData.active != changes.active; - if (!hasChanges) return; - - let userId = ctx.options.accessToken.userId; - let logRecord = { - originFk: oldData.id, - userFk: userId, - action: 'update', - changedModel: 'Account', - oldInstance: {name: oldData.name, active: oldData.active}, - newInstance: {name: changes.name, active: changes.active} - }; - await Self.app.models.ClientLog.create(logRecord); - } - }); - }); Self.observe('after save', async ctx => { if (ctx.isNewInstance) return; @@ -303,8 +273,58 @@ module.exports = Self => { query: params }); } + + const workerIdBefore = oldInstance.salesPersonFk; + const workerIdAfter = newInstance.salesPersonFk; + const assignmentChanged = workerIdBefore != workerIdAfter; + if (assignmentChanged) + await Self.notifyAssignment(instance, workerIdBefore, workerIdAfter); }); + // Send notification on client worker assignment + Self.notifyAssignment = async function notifyAssignment(client, previousWorkerId, currentWorkerId) { + const loopBackContext = LoopBackContext.getCurrentContext(); + const httpCtx = {req: loopBackContext.active}; + const httpRequest = httpCtx.req.http.req; + const $t = httpRequest.__; + const headers = httpRequest.headers; + const origin = headers.origin; + const models = Self.app.models; + + let previousWorker = {name: $t('None')}; + let currentWorker = {name: $t('None')}; + if (previousWorkerId) { + const worker = await models.Worker.findById(previousWorkerId, { + include: {relation: 'user'} + }); + previousWorker.user = worker && worker.user().name; + previousWorker.name = worker && worker.user().nickname; + } + + if (currentWorkerId) { + const worker = await models.Worker.findById(currentWorkerId, { + include: {relation: 'user'} + }); + currentWorker.user = worker && worker.user().name; + currentWorker.name = worker && worker.user().nickname; + } + + const fullUrl = `${origin}/#!/client/${client.id}/basic-data`; + const message = $t('Client assignment has changed', { + clientId: client.id, + clientName: client.name, + url: fullUrl, + previousWorkerName: previousWorker.name, + currentWorkerName: currentWorker.name + }); + + if (previousWorkerId) + await models.Chat.send(httpCtx, `@${previousWorker.user}`, message); + + if (currentWorkerId) + await models.Chat.send(httpCtx, `@${currentWorker.user}`, message); + }; + async function validateCreditChange(ctx, finalState) { let models = Self.app.models; let userId = ctx.options.accessToken.userId; @@ -341,4 +361,34 @@ module.exports = Self => { if (count <= 0) throw new UserError('The role cannot set this credit amount'); } + + const app = require('vn-loopback/server/server'); + app.on('started', function() { + let account = app.models.Account; + + account.observe('before save', async ctx => { + if (ctx.isNewInstance) return; + ctx.hookState.oldInstance = JSON.parse(JSON.stringify(ctx.currentInstance)); + }); + + account.observe('after save', async ctx => { + let changes = ctx.data || ctx.instance; + if (!ctx.isNewInstance && changes) { + let oldData = ctx.hookState.oldInstance; + let hasChanges = oldData.name != changes.name || oldData.active != changes.active; + if (!hasChanges) return; + + let userId = ctx.options.accessToken.userId; + let logRecord = { + originFk: oldData.id, + userFk: userId, + action: 'update', + changedModel: 'Account', + oldInstance: {name: oldData.name, active: oldData.active}, + newInstance: {name: changes.name, active: changes.active} + }; + await Self.app.models.ClientLog.create(logRecord); + } + }); + }); }; diff --git a/modules/client/back/models/specs/client.spec.js b/modules/client/back/models/specs/client.spec.js new file mode 100644 index 000000000..a9d479516 --- /dev/null +++ b/modules/client/back/models/specs/client.spec.js @@ -0,0 +1,54 @@ +const app = require('vn-loopback/server/server'); +const LoopBackContext = require('loopback-context'); + +describe('Client Model', () => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'}, + [`__`]: value => { + return value; + } + } + } + }; + const ctx = {req: activeCtx}; + const chatModel = app.models.Chat; + const client = {id: 101, name: 'Bruce Banner'}; + const previousWorkerId = 106; // DavidCharlesHaller + const currentWorkerId = 107; // HankPym + + beforeEach(() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + + describe('notifyAssignment()', () => { + it('should call to the Chat send() method for both workers', async() => { + spyOn(chatModel, 'send').and.callThrough(); + + await app.models.Client.notifyAssignment(client, previousWorkerId, currentWorkerId); + + expect(chatModel.send).toHaveBeenCalledWith(ctx, '@DavidCharlesHaller', `Client assignment has changed`); + expect(chatModel.send).toHaveBeenCalledWith(ctx, '@HankPym', `Client assignment has changed`); + }); + + it('should call to the Chat send() method for the previous worker', async() => { + spyOn(chatModel, 'send').and.callThrough(); + + await app.models.Client.notifyAssignment(client, null, currentWorkerId); + + expect(chatModel.send).toHaveBeenCalledWith(ctx, '@HankPym', `Client assignment has changed`); + }); + + it('should call to the Chat send() method for the current worker', async() => { + spyOn(chatModel, 'send').and.callThrough(); + + await app.models.Client.notifyAssignment(client, previousWorkerId, null); + + expect(chatModel.send).toHaveBeenCalledWith(ctx, '@DavidCharlesHaller', `Client assignment has changed`); + }); + }); +}); diff --git a/modules/entry/front/buy/locale/es.yml b/modules/entry/front/buy/locale/es.yml index b5a82948b..c77587758 100644 --- a/modules/entry/front/buy/locale/es.yml +++ b/modules/entry/front/buy/locale/es.yml @@ -2,4 +2,5 @@ reference: Referencia Observation: Observación Box: Embalaje Import buys: Importar compras -Some of the imported buys doesn't have an item: Algunas de las compras importadas no tienen un artículo \ No newline at end of file +Some of the imported buys doesn't have an item: Algunas de las compras importadas no tienen un artículo +JSON files only: Solo ficheros JSON \ No newline at end of file