diff --git a/CHANGELOG.md b/CHANGELOG.md index a346591d8..e64b0a400 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2320.01] - 2023-05-25 + +### Added +- (Tickets -> Crear Factura) Al facturar se envia automáticamente el pdf al cliente + + +### Changed +- (Trabajadores -> Nuevo trabajador) Los clientes se crean sin 'TR' pero se añade tipo de negocio 'Trabajador' + +### Fixed +- + + + +## [2318.01] - 2023-05-08 + +### Added +- (Usuarios -> Histórico) Nueva sección +- (Roles -> Histórico) Nueva sección +- (General -> Traducciones) Correo de bienvenida a clientes al portugués y al francés + +### Changed +- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral + +### Fixed +- (Ticket -> Boxing) Arreglado selección de horas +- (Cesta -> Índice) Optimizada búsqueda + + + ## [2314.01] - 2023-04-20 ### Added @@ -12,9 +42,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - (Monitor tickets) Muestra un icono al lado de la zona, si el ticket es frágil y se envía por agencia - (Facturas recibidas -> Bases negativas) Nueva sección -### Changed -- - ### Fixed - (Clientes -> Morosos) Ahora se mantienen los elementos seleccionados al hacer sroll. diff --git a/Jenkinsfile b/Jenkinsfile index b1706d802..5f329ee61 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -52,6 +52,7 @@ pipeline { }}} environment { NODE_ENV = "" + TZ = 'Europe/Madrid' } parallel { stage('Frontend') { diff --git a/back/methods/campaign/spec/latest.spec.js b/back/methods/campaign/spec/latest.spec.js index 59e4c1e7a..d03d970c9 100644 --- a/back/methods/campaign/spec/latest.spec.js +++ b/back/methods/campaign/spec/latest.spec.js @@ -1,9 +1,9 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('campaign latest()', () => { it('should return the campaigns from the last year', async() => { const now = Date.vnNew(); - const result = await app.models.Campaign.latest(); + const result = await models.Campaign.latest(); const randomIndex = Math.floor(Math.random() * result.length); const campaignDated = result[randomIndex].dated; @@ -14,7 +14,7 @@ describe('campaign latest()', () => { it('should return the campaigns from the current year', async() => { const now = Date.vnNew(); const currentYear = now.getFullYear(); - const result = await app.models.Campaign.latest({ + const result = await models.Campaign.latest({ where: {dated: {like: `%${currentYear}%`}} }); diff --git a/back/methods/campaign/spec/upcoming.spec.js b/back/methods/campaign/spec/upcoming.spec.js index 2aec5117f..c43444b40 100644 --- a/back/methods/campaign/spec/upcoming.spec.js +++ b/back/methods/campaign/spec/upcoming.spec.js @@ -1,8 +1,8 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('campaign upcoming()', () => { it('should return the upcoming campaign but from the last year', async() => { - const response = await app.models.Campaign.upcoming(); + const response = await models.Campaign.upcoming(); const campaignDated = response.dated; const now = Date.vnNew(); diff --git a/back/methods/chat/send.js b/back/methods/chat/send.js index 79b20e307..ab84b0ec3 100644 --- a/back/methods/chat/send.js +++ b/back/methods/chat/send.js @@ -26,7 +26,7 @@ module.exports = Self => { Self.send = async(ctx, to, message) => { const models = Self.app.models; const accessToken = ctx.req.accessToken; - const sender = await models.Account.findById(accessToken.userId); + const sender = await models.VnUser.findById(accessToken.userId); const recipient = to.replace('@', ''); if (sender.name != recipient) { diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js index 29232490a..274ec3a5b 100644 --- a/back/methods/chat/sendCheckingPresence.js +++ b/back/methods/chat/sendCheckingPresence.js @@ -29,8 +29,8 @@ module.exports = Self => { const models = Self.app.models; const userId = ctx.req.accessToken.userId; - const sender = await models.Account.findById(userId, {fields: ['id']}); - const recipient = await models.Account.findById(recipientId, null); + const sender = await models.VnUser.findById(userId, {fields: ['id']}); + const recipient = await models.VnUser.findById(recipientId, null); // Prevent sending messages to yourself if (recipientId == userId) return false; diff --git a/back/methods/chat/sendQueued.js b/back/methods/chat/sendQueued.js index ef1a417ab..9a23af379 100644 --- a/back/methods/chat/sendQueued.js +++ b/back/methods/chat/sendQueued.js @@ -58,7 +58,7 @@ module.exports = Self => { const models = Self.app.models; const recipientName = chat.recipient.slice(1); - const recipient = await models.Account.findOne({ + const recipient = await models.VnUser.findOne({ where: { name: recipientName } @@ -104,7 +104,7 @@ module.exports = Self => { } const models = Self.app.models; - const sender = await models.Account.findById(senderFk); + const sender = await models.VnUser.findById(senderFk); const login = await Self.getServiceAuth(); const avatar = `${login.host}/avatar/${sender.name}`; diff --git a/back/methods/chat/spec/notifyIssue.spec.js b/back/methods/chat/spec/notifyIssue.spec.js index 1aab51793..64aeebbb1 100644 --- a/back/methods/chat/spec/notifyIssue.spec.js +++ b/back/methods/chat/spec/notifyIssue.spec.js @@ -1,12 +1,12 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('Chat notifyIssue()', () => { const ctx = {req: {accessToken: {userId: 1}}}; ctx.req.__ = value => { return value; }; - const chatModel = app.models.Chat; - const osTicketModel = app.models.OsTicket; + const chatModel = models.Chat; + const osTicketModel = models.OsTicket; const departmentId = 31; it(`should not call to the send() method and neither return a response`, async() => { @@ -29,7 +29,7 @@ describe('Chat notifyIssue()', () => { // eslint-disable-next-line max-len const expectedMessage = `@all ➔ There's a new urgent ticket:\r\n[ID: 00001 - Issue title @batman](https://cau.verdnatura.es/scp/tickets.php?id=1)`; - const department = await app.models.Department.findById(departmentId); + const department = await models.Department.findById(departmentId); let orgChatName = department.chatName; await department.updateAttribute('chatName', 'IT'); diff --git a/back/methods/chat/spec/send.spec.js b/back/methods/chat/spec/send.spec.js index dd07a1342..e910f3fab 100644 --- a/back/methods/chat/spec/send.spec.js +++ b/back/methods/chat/spec/send.spec.js @@ -1,16 +1,16 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('Chat send()', () => { it('should return true as response', async() => { let ctx = {req: {accessToken: {userId: 1}}}; - let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something'); + let response = await models.Chat.send(ctx, '@salesPerson', 'I changed something'); expect(response).toEqual(true); }); it('should return false as response', async() => { let ctx = {req: {accessToken: {userId: 18}}}; - let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something'); + let response = await models.Chat.send(ctx, '@salesPerson', 'I changed something'); expect(response).toEqual(false); }); diff --git a/back/methods/collection/setSaleQuantity.js b/back/methods/collection/setSaleQuantity.js index 4ac3d6d4b..0638539e3 100644 --- a/back/methods/collection/setSaleQuantity.js +++ b/back/methods/collection/setSaleQuantity.js @@ -40,8 +40,7 @@ module.exports = Self => { try { const sale = await models.Sale.findById(saleId, null, myOptions); const saleUpdated = await sale.updateAttributes({ - originalQuantity: sale.quantity, - quantity: quantity + quantity }, myOptions); if (tx) await tx.commit(); diff --git a/back/methods/collection/spec/getSectors.spec.js b/back/methods/collection/spec/getSectors.spec.js index d453220a0..d8fa60663 100644 --- a/back/methods/collection/spec/getSectors.spec.js +++ b/back/methods/collection/spec/getSectors.spec.js @@ -1,8 +1,8 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('getSectors()', () => { it('return list of sectors', async() => { - let response = await app.models.Collection.getSectors(); + let response = await models.Collection.getSectors(); expect(response.length).toBeGreaterThan(0); expect(response[0].id).toEqual(1); diff --git a/back/methods/collection/spec/newCollection.spec.js b/back/methods/collection/spec/newCollection.spec.js index 6abe73f8e..e729594d1 100644 --- a/back/methods/collection/spec/newCollection.spec.js +++ b/back/methods/collection/spec/newCollection.spec.js @@ -1,10 +1,10 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('newCollection()', () => { it('should return a new collection', async() => { pending('#3400 analizar que hacer con rutas de back collection'); let ctx = {req: {accessToken: {userId: 1106}}}; - let response = await app.models.Collection.newCollection(ctx, 1, 1, 1); + let response = await models.Collection.newCollection(ctx, 1, 1, 1); expect(response.length).toBeGreaterThan(0); expect(response[0].ticketFk).toEqual(2); diff --git a/back/methods/collection/spec/setSaleQuantity.spec.js b/back/methods/collection/spec/setSaleQuantity.spec.js index acdf2ebb5..fdc1bce1a 100644 --- a/back/methods/collection/spec/setSaleQuantity.spec.js +++ b/back/methods/collection/spec/setSaleQuantity.spec.js @@ -30,7 +30,7 @@ describe('setSaleQuantity()', () => { await models.Collection.setSaleQuantity(saleId, newQuantity, options); const updateSale = await models.Sale.findById(saleId, null, options); - expect(updateSale.originalQuantity).toEqual(originalSale.quantity); + expect(updateSale.quantity).not.toEqual(originalSale.quantity); expect(updateSale.quantity).toEqual(newQuantity); await tx.rollback(); diff --git a/back/methods/dms/specs/downloadFile.spec.js b/back/methods/dms/specs/downloadFile.spec.js index 763c2a0c1..1cfc944ce 100644 --- a/back/methods/dms/specs/downloadFile.spec.js +++ b/back/methods/dms/specs/downloadFile.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('dms downloadFile()', () => { let dmsId = 1; @@ -6,7 +6,7 @@ describe('dms downloadFile()', () => { it('should return a response for an employee with text content-type', async() => { let workerId = 1107; let ctx = {req: {accessToken: {userId: workerId}}}; - const result = await app.models.Dms.downloadFile(ctx, dmsId); + const result = await models.Dms.downloadFile(ctx, dmsId); expect(result[1]).toEqual('text/plain'); }); @@ -16,7 +16,7 @@ describe('dms downloadFile()', () => { let ctx = {req: {accessToken: {userId: clientId}}}; let error; - await app.models.Dms.downloadFile(ctx, dmsId).catch(e => { + await models.Dms.downloadFile(ctx, dmsId).catch(e => { error = e; }).finally(() => { expect(error.message).toEqual(`You don't have enough privileges`); diff --git a/back/methods/dms/specs/removeFile.spec.js b/back/methods/dms/specs/removeFile.spec.js index 28ce5d0fd..59a2acecb 100644 --- a/back/methods/dms/specs/removeFile.spec.js +++ b/back/methods/dms/specs/removeFile.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('dms removeFile()', () => { let dmsId = 1; @@ -8,7 +8,7 @@ describe('dms removeFile()', () => { let ctx = {req: {accessToken: {userId: clientId}}}; let error; - await app.models.Dms.removeFile(ctx, dmsId).catch(e => { + await models.Dms.removeFile(ctx, dmsId).catch(e => { error = e; }).finally(() => { expect(error.message).toEqual(`You don't have enough privileges`); diff --git a/back/methods/dms/specs/updateFile.spec.js b/back/methods/dms/specs/updateFile.spec.js index 87ee372ec..c99bdda02 100644 --- a/back/methods/dms/specs/updateFile.spec.js +++ b/back/methods/dms/specs/updateFile.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('dms updateFile()', () => { it(`should return an error for a user without enough privileges`, async() => { @@ -11,7 +11,7 @@ describe('dms updateFile()', () => { let ctx = {req: {accessToken: {userId: clientId}}, args: {dmsTypeId: dmsTypeId}}; let error; - await app.models.Dms.updateFile(ctx, dmsId, warehouseId, companyId, dmsTypeId).catch(e => { + await models.Dms.updateFile(ctx, dmsId, warehouseId, companyId, dmsTypeId).catch(e => { error = e; }).finally(() => { expect(error.message).toEqual(`You don't have enough privileges`); diff --git a/back/methods/dms/specs/uploadFile.spec.js b/back/methods/dms/specs/uploadFile.spec.js index fda911bad..862f9fc47 100644 --- a/back/methods/dms/specs/uploadFile.spec.js +++ b/back/methods/dms/specs/uploadFile.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('dms uploadFile()', () => { it(`should return an error for a user without enough privileges`, async() => { @@ -7,7 +7,7 @@ describe('dms uploadFile()', () => { let ctx = {req: {accessToken: {userId: clientId}}, args: {dmsTypeId: ticketDmsTypeId}}; let error; - await app.models.Dms.uploadFile(ctx).catch(e => { + await models.Dms.uploadFile(ctx).catch(e => { error = e; }).finally(() => { expect(error.message).toEqual(`You don't have enough privileges`); diff --git a/back/methods/docuware/deliveryNoteEmail.js b/back/methods/docuware/deliveryNoteEmail.js index 1f9d7556f..1557a3a87 100644 --- a/back/methods/docuware/deliveryNoteEmail.js +++ b/back/methods/docuware/deliveryNoteEmail.js @@ -4,25 +4,25 @@ module.exports = Self => { Self.remoteMethodCtx('deliveryNoteEmail', { description: 'Sends the delivery note email with an docuware attached PDF', accessType: 'WRITE', + accessScopes: ['docuwareDeliveryNoteEmail'], accepts: [ { arg: 'id', - type: 'string', + type: 'number', required: true, description: 'The ticket id', - http: {source: 'path'} - }, - { - arg: 'recipient', - type: 'string', - description: 'The recipient email', - required: true, }, { arg: 'recipientId', type: 'number', description: 'The client id', - required: false + required: true + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: false, } ], returns: [ @@ -41,12 +41,13 @@ module.exports = Self => { } ], http: { - path: '/:id/delivery-note-email', + path: '/delivery-note-email', verb: 'POST' } }); - Self.deliveryNoteEmail = async(ctx, id) => { + Self.deliveryNoteEmail = async(ctx, id, recipientId, recipient) => { + const models = Self.app.models; const args = Object.assign({}, ctx.args); const params = { recipient: args.recipient, @@ -57,9 +58,14 @@ module.exports = Self => { for (const param in args) params[param] = args[param]; + if (!recipient) { + client = await models.Client.findById(recipientId, {fields: ['email']}); + params.recipient = client.email; + } + const email = new Email('delivery-note', params); - const docuwareFile = await Self.app.models.Docuware.download(ctx, id, 'deliveryNote'); + const docuwareFile = await models.Docuware.download(ctx, id, 'deliveryNote'); return email.send({ overrideAttachments: true, diff --git a/back/methods/image/specs/download.spec.js b/back/methods/image/specs/download.spec.js index 758f884ae..1258a916a 100644 --- a/back/methods/image/specs/download.spec.js +++ b/back/methods/image/specs/download.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('image download()', () => { const collection = 'user'; @@ -8,7 +8,7 @@ describe('image download()', () => { it('should return the image content-type of the user', async() => { const userId = 9; - const image = await app.models.Image.download(ctx, collection, size, userId); + const image = await models.Image.download(ctx, collection, size, userId); const contentType = image[1]; expect(contentType).toEqual('image/png'); @@ -16,7 +16,7 @@ describe('image download()', () => { it(`should return false if the user doesn't have image`, async() => { const userId = 1110; - const image = await app.models.Image.download(ctx, collection, size, userId); + const image = await models.Image.download(ctx, collection, size, userId); expect(image).toBeFalse(); }); diff --git a/back/methods/image/specs/upload.spec.js b/back/methods/image/specs/upload.spec.js index 7cb2ae6f9..144770bcf 100644 --- a/back/methods/image/specs/upload.spec.js +++ b/back/methods/image/specs/upload.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('image upload()', () => { describe('as buyer', () => { @@ -16,7 +16,7 @@ describe('image upload()', () => { let error; try { - await app.models.Image.upload(ctx); + await models.Image.upload(ctx); } catch (err) { error = err; } @@ -25,7 +25,7 @@ describe('image upload()', () => { }); it('should call to the TempContainer upload method for the collection "catalog"', async() => { - const containerModel = app.models.TempContainer; + const containerModel = models.TempContainer; spyOn(containerModel, 'upload'); const ctx = {req: {accessToken: {userId: buyerId}}, @@ -36,7 +36,7 @@ describe('image upload()', () => { }; try { - await app.models.Image.upload(ctx); + await models.Image.upload(ctx); } catch (err) { } expect(containerModel.upload).toHaveBeenCalled(); @@ -49,7 +49,7 @@ describe('image upload()', () => { const itemId = 4; it('should be able to call to the TempContainer upload method for the collection "user"', async() => { - const containerModel = app.models.TempContainer; + const containerModel = models.TempContainer; spyOn(containerModel, 'upload'); const ctx = {req: {accessToken: {userId: marketingId}}, @@ -60,14 +60,14 @@ describe('image upload()', () => { }; try { - await app.models.Image.upload(ctx); + await models.Image.upload(ctx); } catch (err) { } expect(containerModel.upload).toHaveBeenCalled(); }); it('should be able to call to the TempContainer upload method for the collection "catalog"', async() => { - const containerModel = app.models.TempContainer; + const containerModel = models.TempContainer; spyOn(containerModel, 'upload'); const ctx = {req: {accessToken: {userId: marketingId}}, @@ -78,7 +78,7 @@ describe('image upload()', () => { }; try { - await app.models.Image.upload(ctx); + await models.Image.upload(ctx); } catch (err) { } expect(containerModel.upload).toHaveBeenCalled(); @@ -91,7 +91,7 @@ describe('image upload()', () => { const itemId = 4; it('should upload a file for the collection "user" and call to the TempContainer upload method', async() => { - const containerModel = app.models.TempContainer; + const containerModel = models.TempContainer; spyOn(containerModel, 'upload'); const ctx = {req: {accessToken: {userId: hhrrId}}, @@ -102,7 +102,7 @@ describe('image upload()', () => { }; try { - await app.models.Image.upload(ctx); + await models.Image.upload(ctx); } catch (err) { } expect(containerModel.upload).toHaveBeenCalled(); @@ -118,7 +118,7 @@ describe('image upload()', () => { let error; try { - await app.models.Image.upload(ctx); + await models.Image.upload(ctx); } catch (err) { error = err; } diff --git a/back/methods/starred-module/specs/getStarredModules.spec.js b/back/methods/starred-module/specs/getStarredModules.spec.js index c962bc471..bf9bd1d73 100644 --- a/back/methods/starred-module/specs/getStarredModules.spec.js +++ b/back/methods/starred-module/specs/getStarredModules.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); const LoopBackContext = require('loopback-context'); describe('getStarredModules()', () => { @@ -19,13 +19,13 @@ describe('getStarredModules()', () => { }); it(`should return the starred modules for a given user`, async() => { - const newStarred = await app.models.StarredModule.create({workerFk: 9, moduleFk: 'customer', position: 1}); - const starredModules = await app.models.StarredModule.getStarredModules(ctx); + const newStarred = await models.StarredModule.create({workerFk: 9, moduleFk: 'customer', position: 1}); + const starredModules = await models.StarredModule.getStarredModules(ctx); expect(starredModules.length).toEqual(1); expect(starredModules[0].moduleFk).toEqual('customer'); // restores - await app.models.StarredModule.destroyById(newStarred.id); + await models.StarredModule.destroyById(newStarred.id); }); }); diff --git a/back/methods/starred-module/specs/setPosition.spec.js b/back/methods/starred-module/specs/setPosition.spec.js index 5421bd62b..a428fcf22 100644 --- a/back/methods/starred-module/specs/setPosition.spec.js +++ b/back/methods/starred-module/specs/setPosition.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); const LoopBackContext = require('loopback-context'); describe('setPosition()', () => { @@ -21,7 +21,7 @@ describe('setPosition()', () => { }); it('should increase the orders module position by replacing it with clients and vice versa', async() => { - const tx = await app.models.StarredModule.beginTransaction({}); + const tx = await models.StarredModule.beginTransaction({}); const filter = { where: { @@ -32,24 +32,24 @@ describe('setPosition()', () => { try { const options = {transaction: tx}; - await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); + await models.StarredModule.toggleStarredModule(ctx, 'order', options); + await models.StarredModule.toggleStarredModule(ctx, 'customer', options); - let orders = await app.models.StarredModule.findOne(filter, options); + let orders = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'customer'; - let clients = await app.models.StarredModule.findOne(filter, options); + let clients = await models.StarredModule.findOne(filter, options); expect(orders.position).toEqual(1); expect(clients.position).toEqual(2); - await app.models.StarredModule.setPosition(ctx, 'customer', 'left', options); + await models.StarredModule.setPosition(ctx, 'customer', 'left', options); filter.where.moduleFk = 'customer'; - clients = await app.models.StarredModule.findOne(filter, options); + clients = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'order'; - orders = await app.models.StarredModule.findOne(filter, options); + orders = await models.StarredModule.findOne(filter, options); expect(clients.position).toEqual(1); expect(orders.position).toEqual(2); @@ -62,7 +62,7 @@ describe('setPosition()', () => { }); it('should decrease the orders module position by replacing it with clients and vice versa', async() => { - const tx = await app.models.StarredModule.beginTransaction({}); + const tx = await models.StarredModule.beginTransaction({}); const filter = { where: { @@ -73,24 +73,24 @@ describe('setPosition()', () => { try { const options = {transaction: tx}; - await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); + await models.StarredModule.toggleStarredModule(ctx, 'order', options); + await models.StarredModule.toggleStarredModule(ctx, 'customer', options); - let orders = await app.models.StarredModule.findOne(filter, options); + let orders = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'customer'; - let clients = await app.models.StarredModule.findOne(filter, options); + let clients = await models.StarredModule.findOne(filter, options); expect(orders.position).toEqual(1); expect(clients.position).toEqual(2); - await app.models.StarredModule.setPosition(ctx, 'order', 'right', options); + await models.StarredModule.setPosition(ctx, 'order', 'right', options); filter.where.moduleFk = 'order'; - orders = await app.models.StarredModule.findOne(filter, options); + orders = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'customer'; - clients = await app.models.StarredModule.findOne(filter, options); + clients = await models.StarredModule.findOne(filter, options); expect(orders.position).toEqual(2); expect(clients.position).toEqual(1); @@ -103,7 +103,7 @@ describe('setPosition()', () => { }); it('should switch two modules after adding and deleting several modules', async() => { - const tx = await app.models.StarredModule.beginTransaction({}); + const tx = await models.StarredModule.beginTransaction({}); const filter = { where: { @@ -115,29 +115,29 @@ describe('setPosition()', () => { try { const options = {transaction: tx}; - await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'item', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'claim', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'zone', options); + await models.StarredModule.toggleStarredModule(ctx, 'customer', options); + await models.StarredModule.toggleStarredModule(ctx, 'order', options); + await models.StarredModule.toggleStarredModule(ctx, 'customer', options); + await models.StarredModule.toggleStarredModule(ctx, 'order', options); + await models.StarredModule.toggleStarredModule(ctx, 'item', options); + await models.StarredModule.toggleStarredModule(ctx, 'claim', options); + await models.StarredModule.toggleStarredModule(ctx, 'customer', options); + await models.StarredModule.toggleStarredModule(ctx, 'order', options); + await models.StarredModule.toggleStarredModule(ctx, 'zone', options); - const items = await app.models.StarredModule.findOne(filter, options); + const items = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'claim'; - const claims = await app.models.StarredModule.findOne(filter, options); + const claims = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'customer'; - let clients = await app.models.StarredModule.findOne(filter, options); + let clients = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'order'; - let orders = await app.models.StarredModule.findOne(filter, options); + let orders = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'zone'; - const zones = await app.models.StarredModule.findOne(filter, options); + const zones = await models.StarredModule.findOne(filter, options); expect(items.position).toEqual(1); expect(claims.position).toEqual(2); @@ -145,13 +145,13 @@ describe('setPosition()', () => { expect(orders.position).toEqual(4); expect(zones.position).toEqual(5); - await app.models.StarredModule.setPosition(ctx, 'customer', 'right', options); + await models.StarredModule.setPosition(ctx, 'customer', 'right', options); filter.where.moduleFk = 'order'; - orders = await app.models.StarredModule.findOne(filter, options); + orders = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'customer'; - clients = await app.models.StarredModule.findOne(filter, options); + clients = await models.StarredModule.findOne(filter, options); expect(orders.position).toEqual(3); expect(clients.position).toEqual(4); @@ -164,7 +164,7 @@ describe('setPosition()', () => { }); it('should switch two modules after adding and deleting a module between them', async() => { - const tx = await app.models.StarredModule.beginTransaction({}); + const tx = await models.StarredModule.beginTransaction({}); const filter = { where: { @@ -176,25 +176,25 @@ describe('setPosition()', () => { try { const options = {transaction: tx}; - await app.models.StarredModule.toggleStarredModule(ctx, 'item', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'customer', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'claim', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'order', options); - await app.models.StarredModule.toggleStarredModule(ctx, 'zone', options); + await models.StarredModule.toggleStarredModule(ctx, 'item', options); + await models.StarredModule.toggleStarredModule(ctx, 'customer', options); + await models.StarredModule.toggleStarredModule(ctx, 'claim', options); + await models.StarredModule.toggleStarredModule(ctx, 'order', options); + await models.StarredModule.toggleStarredModule(ctx, 'zone', options); - const items = await app.models.StarredModule.findOne(filter, options); + const items = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'customer'; - let clients = await app.models.StarredModule.findOne(filter, options); + let clients = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'claim'; - const claims = await app.models.StarredModule.findOne(filter, options); + const claims = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'order'; - let orders = await app.models.StarredModule.findOne(filter, options); + let orders = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'zone'; - const zones = await app.models.StarredModule.findOne(filter, options); + const zones = await models.StarredModule.findOne(filter, options); expect(items.position).toEqual(1); expect(clients.position).toEqual(2); @@ -202,14 +202,14 @@ describe('setPosition()', () => { expect(orders.position).toEqual(4); expect(zones.position).toEqual(5); - await app.models.StarredModule.toggleStarredModule(ctx, 'claim', options); - await app.models.StarredModule.setPosition(ctx, 'customer', 'right', options); + await models.StarredModule.toggleStarredModule(ctx, 'claim', options); + await models.StarredModule.setPosition(ctx, 'customer', 'right', options); filter.where.moduleFk = 'customer'; - clients = await app.models.StarredModule.findOne(filter, options); + clients = await models.StarredModule.findOne(filter, options); filter.where.moduleFk = 'order'; - orders = await app.models.StarredModule.findOne(filter, options); + orders = await models.StarredModule.findOne(filter, options); expect(orders.position).toEqual(2); expect(clients.position).toEqual(4); diff --git a/back/methods/starred-module/specs/toggleStarredModule.spec.js b/back/methods/starred-module/specs/toggleStarredModule.spec.js index 1195834e7..848c1475a 100644 --- a/back/methods/starred-module/specs/toggleStarredModule.spec.js +++ b/back/methods/starred-module/specs/toggleStarredModule.spec.js @@ -1,4 +1,4 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); const LoopBackContext = require('loopback-context'); describe('toggleStarredModule()', () => { @@ -21,16 +21,16 @@ describe('toggleStarredModule()', () => { }); it('should create a new starred module and then remove it by calling the method again with same args', async() => { - const starredModule = await app.models.StarredModule.toggleStarredModule(ctx, 'order'); - let starredModules = await app.models.StarredModule.getStarredModules(ctx); + const starredModule = await models.StarredModule.toggleStarredModule(ctx, 'order'); + let starredModules = await models.StarredModule.getStarredModules(ctx); expect(starredModules.length).toEqual(1); expect(starredModule.moduleFk).toEqual('order'); expect(starredModule.workerFk).toEqual(activeCtx.accessToken.userId); expect(starredModule.position).toEqual(starredModules.length); - await app.models.StarredModule.toggleStarredModule(ctx, 'order'); - starredModules = await app.models.StarredModule.getStarredModules(ctx); + await models.StarredModule.toggleStarredModule(ctx, 'order'); + starredModules = await models.StarredModule.getStarredModules(ctx); expect(starredModules.length).toEqual(0); }); diff --git a/back/methods/account/acl.js b/back/methods/vn-user/acl.js similarity index 95% rename from back/methods/account/acl.js rename to back/methods/vn-user/acl.js index bc1990e1d..4f4bf0623 100644 --- a/back/methods/account/acl.js +++ b/back/methods/vn-user/acl.js @@ -22,7 +22,7 @@ module.exports = Self => { let userId = ctx.req.accessToken.userId; let models = Self.app.models; - let user = await models.Account.findById(userId, { + let user = await Self.findById(userId, { fields: ['id', 'name', 'nickname', 'email', 'lang'], include: { relation: 'userConfig', diff --git a/back/methods/account/privileges.js b/back/methods/vn-user/privileges.js similarity index 78% rename from back/methods/account/privileges.js rename to back/methods/vn-user/privileges.js index 5c5e7409d..690ce74a3 100644 --- a/back/methods/account/privileges.js +++ b/back/methods/vn-user/privileges.js @@ -1,9 +1,14 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { - Self.remoteMethodCtx('privileges', { + Self.remoteMethod('privileges', { description: 'Change role and hasGrant if user has privileges', accepts: [ + { + arg: 'ctx', + type: 'Object', + http: {source: 'context'} + }, { arg: 'id', type: 'number', @@ -39,9 +44,9 @@ module.exports = Self => { if (typeof options == 'object') Object.assign(myOptions, options); - const user = await models.Account.findById(userId, {fields: ['hasGrant']}, myOptions); + const user = await Self.findById(userId, {fields: ['hasGrant']}, myOptions); - const userToUpdate = await models.Account.findById(id, { + const userToUpdate = await Self.findById(id, { fields: ['id', 'name', 'hasGrant', 'roleFk', 'password'], include: { relation: 'role', @@ -54,7 +59,7 @@ module.exports = Self => { if (!user.hasGrant) throw new UserError(`You don't have grant privilege`); - const hasRoleFromUser = await models.Account.hasRole(userId, userToUpdate.role().name, myOptions); + const hasRoleFromUser = await Self.hasRole(userId, userToUpdate.role().name, myOptions); if (!hasRoleFromUser) throw new UserError(`You don't own the role and you can't assign it to another user`); @@ -64,7 +69,7 @@ module.exports = Self => { if (roleFk) { const role = await models.Role.findById(roleFk, {fields: ['name']}, myOptions); - const hasRole = await models.Account.hasRole(userId, role.name, myOptions); + const hasRole = await Self.hasRole(userId, role.name, myOptions); if (!hasRole) throw new UserError(`You don't own the role and you can't assign it to another user`); @@ -73,6 +78,6 @@ module.exports = Self => { } await userToUpdate.save(userToUpdate); - await models.UserAccount.sync(userToUpdate.name); + await models.Account.sync(userToUpdate.name); }; }; diff --git a/back/methods/account/recover-password.js b/back/methods/vn-user/recover-password.js similarity index 85% rename from back/methods/account/recover-password.js rename to back/methods/vn-user/recover-password.js index 787a45284..34f5dd545 100644 --- a/back/methods/account/recover-password.js +++ b/back/methods/vn-user/recover-password.js @@ -20,7 +20,7 @@ module.exports = Self => { const usesEmail = user.indexOf('@') !== -1; if (!usesEmail) { - const account = await models.Account.findOne({ + const account = await models.VnUser.findOne({ fields: ['email'], where: {name: user} }); @@ -28,7 +28,7 @@ module.exports = Self => { } try { - await models.user.resetPassword({email: user, emailTemplate: 'recover-password'}); + await Self.resetPassword({email: user, emailTemplate: 'recover-password'}); } catch (err) { if (err.code === 'EMAIL_NOT_FOUND') return; diff --git a/back/methods/account/login.js b/back/methods/vn-user/signIn.js similarity index 67% rename from back/methods/account/login.js rename to back/methods/vn-user/signIn.js index 7393e8374..da3172ae4 100644 --- a/back/methods/account/login.js +++ b/back/methods/vn-user/signIn.js @@ -1,14 +1,14 @@ -const md5 = require('md5'); const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { - Self.remoteMethod('login', { + Self.remoteMethod('signIn', { description: 'Login a user with username/email and password', accepts: [ { arg: 'user', type: 'String', description: 'The user name or email', + http: {source: 'form'}, required: true }, { arg: 'password', @@ -21,20 +21,20 @@ module.exports = Self => { root: true }, http: { - path: `/login`, + path: `/signIn`, verb: 'POST' } }); - Self.login = async function(user, password) { - let $ = Self.app.models; + Self.signIn = async function(user, password) { + let models = Self.app.models; let token; let usesEmail = user.indexOf('@') !== -1; let userInfo = usesEmail ? {email: user} : {username: user}; - let instance = await $.User.findOne({ + let instance = await Self.findOne({ fields: ['username', 'password'], where: userInfo }); @@ -42,29 +42,27 @@ module.exports = Self => { let where = usesEmail ? {email: user} : {name: user}; - let account = await Self.findOne({ - fields: ['active', 'password'], + let vnUser = await Self.findOne({ + fields: ['active'], where }); - let validCredentials = instance && ( - await instance.hasPassword(password) || - account.password == md5(password || '') - ); + let validCredentials = instance + && await instance.hasPassword(password); if (validCredentials) { - if (!account.active) + if (!vnUser.active) throw new UserError('User disabled'); try { - await $.UserAccount.sync(instance.username, password); + await models.Account.sync(instance.username, password); } catch (err) { console.warn(err); } } let loginInfo = Object.assign({password}, userInfo); - token = await $.User.login(loginInfo, 'user'); + token = await Self.login(loginInfo, 'user'); return {token: token.id}; }; }; diff --git a/back/methods/account/specs/privileges.spec.js b/back/methods/vn-user/specs/privileges.spec.js similarity index 74% rename from back/methods/account/specs/privileges.spec.js rename to back/methods/vn-user/specs/privileges.spec.js index edfe0f03f..3d25eecf9 100644 --- a/back/methods/account/specs/privileges.spec.js +++ b/back/methods/vn-user/specs/privileges.spec.js @@ -1,6 +1,6 @@ const models = require('vn-loopback/server/server').models; -describe('account privileges()', () => { +describe('VnUser privileges()', () => { const employeeId = 1; const developerId = 9; const sysadminId = 66; @@ -10,13 +10,13 @@ describe('account privileges()', () => { it('should throw an error when user not has privileges', async() => { const ctx = {req: {accessToken: {userId: developerId}}}; - const tx = await models.Account.beginTransaction({}); + const tx = await models.VnUser.beginTransaction({}); let error; try { const options = {transaction: tx}; - await models.Account.privileges(ctx, employeeId, null, true, options); + await models.VnUser.privileges(ctx, employeeId, null, true, options); await tx.rollback(); } catch (e) { @@ -29,13 +29,13 @@ describe('account privileges()', () => { it('should throw an error when user has privileges but not has the role', async() => { const ctx = {req: {accessToken: {userId: sysadminId}}}; - const tx = await models.Account.beginTransaction({}); + const tx = await models.VnUser.beginTransaction({}); let error; try { const options = {transaction: tx}; - await models.Account.privileges(ctx, employeeId, rootId, null, options); + await models.VnUser.privileges(ctx, employeeId, rootId, null, options); await tx.rollback(); } catch (e) { @@ -48,13 +48,13 @@ describe('account privileges()', () => { it('should throw an error when user has privileges but not has the role from user', async() => { const ctx = {req: {accessToken: {userId: sysadminId}}}; - const tx = await models.Account.beginTransaction({}); + const tx = await models.VnUser.beginTransaction({}); let error; try { const options = {transaction: tx}; - await models.Account.privileges(ctx, itBossId, developerId, null, options); + await models.VnUser.privileges(ctx, itBossId, developerId, null, options); await tx.rollback(); } catch (e) { @@ -67,7 +67,7 @@ describe('account privileges()', () => { it('should change role', async() => { const ctx = {req: {accessToken: {userId: sysadminId}}}; - const tx = await models.Account.beginTransaction({}); + const tx = await models.VnUser.beginTransaction({}); const options = {transaction: tx}; const agency = await models.Role.findOne({ @@ -79,8 +79,8 @@ describe('account privileges()', () => { let error; let result; try { - await models.Account.privileges(ctx, clarkKent, agency.id, null, options); - result = await models.Account.findById(clarkKent, null, options); + await models.VnUser.privileges(ctx, clarkKent, agency.id, null, options); + result = await models.VnUser.findById(clarkKent, null, options); await tx.rollback(); } catch (e) { @@ -94,14 +94,14 @@ describe('account privileges()', () => { it('should change hasGrant', async() => { const ctx = {req: {accessToken: {userId: sysadminId}}}; - const tx = await models.Account.beginTransaction({}); + const tx = await models.VnUser.beginTransaction({}); let error; let result; try { const options = {transaction: tx}; - await models.Account.privileges(ctx, clarkKent, null, true, options); - result = await models.Account.findById(clarkKent, null, options); + await models.VnUser.privileges(ctx, clarkKent, null, true, options); + result = await models.VnUser.findById(clarkKent, null, options); await tx.rollback(); } catch (e) { diff --git a/back/methods/account/specs/login.spec.js b/back/methods/vn-user/specs/signIn.js similarity index 57% rename from back/methods/account/specs/login.spec.js rename to back/methods/vn-user/specs/signIn.js index 59eea2612..b46c645d6 100644 --- a/back/methods/account/specs/login.spec.js +++ b/back/methods/vn-user/specs/signIn.js @@ -1,25 +1,25 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); -describe('account login()', () => { +describe('VnUser signIn()', () => { describe('when credentials are correct', () => { it('should return the token', async() => { - let login = await app.models.Account.login('salesAssistant', 'nightmare'); - let accessToken = await app.models.AccessToken.findById(login.token); + let login = await models.VnUser.signIn('salesAssistant', 'nightmare'); + let accessToken = await models.AccessToken.findById(login.token); let ctx = {req: {accessToken: accessToken}}; expect(login.token).toBeDefined(); - await app.models.Account.logout(ctx); + await models.VnUser.signOut(ctx); }); it('should return the token if the user doesnt exist but the client does', async() => { - let login = await app.models.Account.login('PetterParker', 'nightmare'); - let accessToken = await app.models.AccessToken.findById(login.token); + let login = await models.VnUser.signIn('PetterParker', 'nightmare'); + let accessToken = await models.AccessToken.findById(login.token); let ctx = {req: {accessToken: accessToken}}; expect(login.token).toBeDefined(); - await app.models.Account.logout(ctx); + await models.VnUser.signOut(ctx); }); }); @@ -28,7 +28,7 @@ describe('account login()', () => { let error; try { - await app.models.Account.login('IDontExist', 'TotallyWrongPassword'); + await models.VnUser.signIn('IDontExist', 'TotallyWrongPassword'); } catch (e) { error = e; } diff --git a/back/methods/account/specs/logout.spec.js b/back/methods/vn-user/specs/signOut.js similarity index 59% rename from back/methods/account/specs/logout.spec.js rename to back/methods/vn-user/specs/signOut.js index b3d69d6ef..c84e86f05 100644 --- a/back/methods/account/specs/logout.spec.js +++ b/back/methods/vn-user/specs/signOut.js @@ -1,13 +1,13 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); -describe('account logout()', () => { +describe('VnUser signOut()', () => { it('should logout and remove token after valid login', async() => { - let loginResponse = await app.models.Account.login('buyer', 'nightmare'); - let accessToken = await app.models.AccessToken.findById(loginResponse.token); + let loginResponse = await models.VnUser.signOut('buyer', 'nightmare'); + let accessToken = await models.AccessToken.findById(loginResponse.token); let ctx = {req: {accessToken: accessToken}}; - let logoutResponse = await app.models.Account.logout(ctx); - let tokenAfterLogout = await app.models.AccessToken.findById(loginResponse.token); + let logoutResponse = await models.VnUser.signOut(ctx); + let tokenAfterLogout = await models.AccessToken.findById(loginResponse.token); expect(logoutResponse).toBeTrue(); expect(tokenAfterLogout).toBeNull(); @@ -18,7 +18,7 @@ describe('account logout()', () => { let ctx = {req: {accessToken: {id: 'invalidToken'}}}; try { - response = await app.models.Account.logout(ctx); + response = await models.VnUser.signOut(ctx); } catch (e) { error = e; } @@ -32,7 +32,7 @@ describe('account logout()', () => { let ctx = {req: {accessToken: null}}; try { - response = await app.models.Account.logout(ctx); + response = await models.VnUser.signOut(ctx); } catch (e) { error = e; } diff --git a/back/methods/account/validate-token.js b/back/methods/vn-user/validate-token.js similarity index 100% rename from back/methods/account/validate-token.js rename to back/methods/vn-user/validate-token.js diff --git a/back/model-config.json b/back/model-config.json index 29676e979..ff2bf5850 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -1,7 +1,4 @@ { - "Account": { - "dataSource": "vn" - }, "AccountingType": { "dataSource": "vn" }, @@ -125,10 +122,10 @@ "UserConfigView": { "dataSource": "vn" }, - "UserLog": { + "Warehouse": { "dataSource": "vn" }, - "Warehouse": { + "VnUser": { "dataSource": "vn" }, "OsTicket": { diff --git a/back/models/account.js b/back/models/account.js deleted file mode 100644 index 6d71a4e52..000000000 --- a/back/models/account.js +++ /dev/null @@ -1,139 +0,0 @@ -/* eslint max-len: ["error", { "code": 150 }]*/ -const md5 = require('md5'); -const LoopBackContext = require('loopback-context'); -const {Email} = require('vn-print'); - -module.exports = Self => { - require('../methods/account/login')(Self); - require('../methods/account/logout')(Self); - require('../methods/account/acl')(Self); - require('../methods/account/change-password')(Self); - require('../methods/account/set-password')(Self); - require('../methods/account/recover-password')(Self); - require('../methods/account/validate-token')(Self); - require('../methods/account/privileges')(Self); - - // Validations - - Self.validatesFormatOf('email', { - message: 'Invalid email', - allowNull: true, - allowBlank: true, - with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/ - }); - - Self.validatesUniquenessOf('name', { - message: `A client with that Web User name already exists` - }); - - Self.observe('before save', async function(ctx) { - if (ctx.currentInstance && ctx.currentInstance.id && ctx.data && ctx.data.password) - ctx.data.password = md5(ctx.data.password); - }); - - Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => { - if (!ctx.args || !ctx.args.data.email) return; - const models = Self.app.models; - - const loopBackContext = LoopBackContext.getCurrentContext(); - const httpCtx = {req: loopBackContext.active}; - const httpRequest = httpCtx.req.http.req; - const headers = httpRequest.headers; - const origin = headers.origin; - const url = origin.split(':'); - - const userId = ctx.instance.id; - const user = await models.user.findById(userId); - - class Mailer { - async send(verifyOptions, cb) { - const params = { - url: verifyOptions.verifyHref, - recipient: verifyOptions.to, - lang: ctx.req.getLocale() - }; - - const email = new Email('email-verify', params); - email.send(); - - cb(null, verifyOptions.to); - } - } - - const options = { - type: 'email', - to: instance.email, - from: {}, - redirect: `${origin}/#!/account/${instance.id}/basic-data?emailConfirmed`, - template: false, - mailer: new Mailer, - host: url[1].split('/')[2], - port: url[2], - protocol: url[0], - user: Self - }; - - await user.verify(options); - }); - - Self.remoteMethod('getCurrentUserData', { - description: 'Gets the current user data', - accepts: [ - { - arg: 'ctx', - type: 'object', - http: {source: 'context'} - } - ], - returns: { - type: 'object', - root: true - }, - http: { - verb: 'GET', - path: '/getCurrentUserData' - } - }); - - Self.getCurrentUserData = async function(ctx) { - let userId = ctx.req.accessToken.userId; - return await Self.findById(userId, { - fields: ['id', 'name', 'nickname'] - }); - }; - - /** - * Checks if user has a role. - * - * @param {Integer} userId The user id - * @param {String} name The role name - * @param {object} options Options - * @return {Boolean} %true if user has the role, %false otherwise - */ - Self.hasRole = async function(userId, name, options) { - let roles = await Self.getRoles(userId, options); - return roles.some(role => role == name); - }; - - /** - * Get all user roles. - * - * @param {Integer} userId The user id - * @param {object} options Options - * @return {object} User role list - */ - Self.getRoles = async(userId, options) => { - let result = await Self.rawSql( - `SELECT r.name - FROM account.user u - JOIN account.roleRole rr ON rr.role = u.role - JOIN account.role r ON r.id = rr.inheritsFrom - WHERE u.id = ?`, [userId], options); - - let roles = []; - for (const role of result) - roles.push(role.name); - - return roles; - }; -}; diff --git a/back/models/dms-type.js b/back/models/dms-type.js index 267c905e9..c9329f30b 100644 --- a/back/models/dms-type.js +++ b/back/models/dms-type.js @@ -54,8 +54,8 @@ module.exports = Self => { const writeRole = dmsType.writeRole() && dmsType.writeRole().name; const requiredRole = readRole || writeRole; - const hasRequiredRole = await models.Account.hasRole(myUserId, requiredRole, options); - const isRoot = await models.Account.hasRole(myUserId, 'root', options); + const hasRequiredRole = await models.VnUser.hasRole(myUserId, requiredRole, options); + const isRoot = await models.VnUser.hasRole(myUserId, 'root', options); if (isRoot || hasRequiredRole) return true; diff --git a/back/models/email-user.json b/back/models/email-user.json index 81c01ab0c..57935fe79 100644 --- a/back/models/email-user.json +++ b/back/models/email-user.json @@ -20,7 +20,7 @@ "relations": { "user": { "type": "belongsTo", - "model": "Account", + "model": "VnUser", "foreignKey": "userFk" } }, diff --git a/back/models/image-collection.js b/back/models/image-collection.js index 8ea3c6f12..2c4d274ee 100644 --- a/back/models/image-collection.js +++ b/back/models/image-collection.js @@ -53,8 +53,8 @@ module.exports = Self => { const writeRole = collection.writeRole() && collection.writeRole().name; const requiredRole = readRole || writeRole; - const hasRequiredRole = await models.Account.hasRole(myUserId, requiredRole, options); - const isRoot = await models.Account.hasRole(myUserId, 'root', options); + const hasRequiredRole = await models.VnUser.hasRole(myUserId, requiredRole, options); + const isRoot = await models.VnUser.hasRole(myUserId, 'root', options); if (isRoot || hasRequiredRole) return true; diff --git a/back/models/notificationQueue.json b/back/models/notificationQueue.json index 9790ea595..994230031 100644 --- a/back/models/notificationQueue.json +++ b/back/models/notificationQueue.json @@ -31,7 +31,7 @@ }, "author": { "type": "belongsTo", - "model": "Account", + "model": "VnUser", "foreignKey": "authorFk" } } diff --git a/back/models/notificationSubscription.json b/back/models/notificationSubscription.json index a640e0917..d1632f925 100644 --- a/back/models/notificationSubscription.json +++ b/back/models/notificationSubscription.json @@ -29,7 +29,7 @@ }, "user": { "type": "belongsTo", - "model": "Account", + "model": "VnUser", "foreignKey": "userFk" } } diff --git a/back/models/specs/company.spec.js b/back/models/specs/company.spec.js index 4adc6d96b..e30d45a59 100644 --- a/back/models/specs/company.spec.js +++ b/back/models/specs/company.spec.js @@ -1,8 +1,8 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('loopback model Company', () => { it('should check that the company FTH doesnt exists', async() => { - let result = await app.models.Company.findOne({where: {code: 'FTH'}}); + let result = await models.Company.findOne({where: {code: 'FTH'}}); expect(result).toBeFalsy(); }); diff --git a/back/models/specs/dms.spec.js b/back/models/specs/dms.spec.js index 93ae1d1e0..3f13e88ff 100644 --- a/back/models/specs/dms.spec.js +++ b/back/models/specs/dms.spec.js @@ -1,6 +1,6 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); describe('Dms', () => { - const Dms = app.models.Dms; + const Dms = models.Dms; describe('getFile()', () => { it('should return a response with text content-type', async() => { @@ -23,7 +23,7 @@ describe('Dms', () => { it('should return an error for a record does not exists', async() => { let error = {}; try { - await app.models.Dms.getFile('NotExistentId'); + await models.Dms.getFile('NotExistentId'); } catch (e) { error = e; } diff --git a/back/models/specs/user.spec.js b/back/models/specs/user.spec.js index 124afdc0c..78835e6eb 100644 --- a/back/models/specs/user.spec.js +++ b/back/models/specs/user.spec.js @@ -1,7 +1,7 @@ const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); -describe('account recoverPassword()', () => { +describe('VnUser recoverPassword()', () => { const userId = 1107; const activeCtx = { @@ -21,9 +21,9 @@ describe('account recoverPassword()', () => { it('should send email with token', async() => { const userId = 1107; - const user = await models.Account.findById(userId); + const user = await models.VnUser.findById(userId); - await models.Account.recoverPassword(user.email); + await models.VnUser.recoverPassword(user.email); const result = await models.AccessToken.findOne({where: {userId: userId}}); diff --git a/back/models/specs/account.spec.js b/back/models/specs/vn-user.spec.js similarity index 63% rename from back/models/specs/account.spec.js rename to back/models/specs/vn-user.spec.js index f31c81b75..3700b919a 100644 --- a/back/models/specs/account.spec.js +++ b/back/models/specs/vn-user.spec.js @@ -1,14 +1,14 @@ const models = require('vn-loopback/server/server').models; -describe('loopback model Account', () => { +describe('loopback model VnUser', () => { it('should return true if the user has the given role', async() => { - let result = await models.Account.hasRole(1, 'employee'); + let result = await models.VnUser.hasRole(1, 'employee'); expect(result).toBeTruthy(); }); it('should return false if the user doesnt have the given role', async() => { - let result = await models.Account.hasRole(1, 'administrator'); + let result = await models.VnUser.hasRole(1, 'administrator'); expect(result).toBeFalsy(); }); diff --git a/back/models/user-config-view.json b/back/models/user-config-view.json index f9235725c..ab9c37668 100644 --- a/back/models/user-config-view.json +++ b/back/models/user-config-view.json @@ -26,7 +26,7 @@ "relations": { "user": { "type": "belongsTo", - "model": "Account", + "model": "VnUser", "foreignKey": "userFk" } } diff --git a/back/models/user-config.json b/back/models/user-config.json index 8e4684713..52125dc01 100644 --- a/back/models/user-config.json +++ b/back/models/user-config.json @@ -39,9 +39,9 @@ "model": "Company", "foreignKey": "companyFk" }, - "account": { + "VnUser": { "type": "belongsTo", - "model": "Account", + "model": "VnUser", "foreignKey": "userFk" } } diff --git a/back/models/user.js b/back/models/user.js deleted file mode 100644 index b24d702b3..000000000 --- a/back/models/user.js +++ /dev/null @@ -1,27 +0,0 @@ -const LoopBackContext = require('loopback-context'); -const {Email} = require('vn-print'); - -module.exports = function(Self) { - Self.on('resetPasswordRequest', async function(info) { - const loopBackContext = LoopBackContext.getCurrentContext(); - const httpCtx = {req: loopBackContext.active}; - const httpRequest = httpCtx.req.http.req; - const headers = httpRequest.headers; - const origin = headers.origin; - - const user = await Self.app.models.Account.findById(info.user.id); - const params = { - recipient: info.email, - lang: user.lang, - url: `${origin}/#!/reset-password?access_token=${info.accessToken.id}` - }; - - const options = Object.assign({}, info.options); - for (const param in options) - params[param] = options[param]; - - const email = new Email(options.emailTemplate, params); - - return email.send(); - }); -}; diff --git a/back/models/user.json b/back/models/user.json deleted file mode 100644 index d992fd9db..000000000 --- a/back/models/user.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "user", - "base": "User", - "options": { - "mysql": { - "table": "salix.User" - }, - "resetPasswordTokenTTL": "604800" - }, - "properties": { - "id": { - "id": true, - "type": "number", - "forceId": false - }, - "username":{ - "type": "string" - } - } -} \ No newline at end of file diff --git a/back/models/vn-user.js b/back/models/vn-user.js new file mode 100644 index 000000000..84ba11794 --- /dev/null +++ b/back/models/vn-user.js @@ -0,0 +1,110 @@ +const vnModel = require('vn-loopback/common/models/vn-model'); +const LoopBackContext = require('loopback-context'); +const {Email} = require('vn-print'); + +module.exports = function(Self) { + vnModel(Self); + + require('../methods/vn-user/signIn')(Self); + require('../methods/vn-user/acl')(Self); + require('../methods/vn-user/recover-password')(Self); + require('../methods/vn-user/validate-token')(Self); + require('../methods/vn-user/privileges')(Self); + + // Validations + + Self.validatesFormatOf('email', { + message: 'Invalid email', + allowNull: true, + allowBlank: true, + with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/ + }); + + Self.validatesUniquenessOf('name', { + message: `A client with that Web User name already exists` + }); + + Self.remoteMethod('getCurrentUserData', { + description: 'Gets the current user data', + accepts: [ + { + arg: 'ctx', + type: 'Object', + http: {source: 'context'} + } + ], + returns: { + type: 'Object', + root: true + }, + http: { + verb: 'GET', + path: '/getCurrentUserData' + } + }); + + Self.getCurrentUserData = async function(ctx) { + let userId = ctx.req.accessToken.userId; + return await Self.findById(userId, { + fields: ['id', 'name', 'nickname'] + }); + }; + + /** + * Checks if user has a role. + * + * @param {Integer} userId The user id + * @param {String} name The role name + * @param {Object} options Options + * @return {Boolean} %true if user has the role, %false otherwise + */ + Self.hasRole = async function(userId, name, options) { + const roles = await Self.getRoles(userId, options); + return roles.some(role => role == name); + }; + + /** + * Get all user roles. + * + * @param {Integer} userId The user id + * @param {Object} options Options + * @return {Object} User role list + */ + Self.getRoles = async(userId, options) => { + const result = await Self.rawSql( + `SELECT r.name + FROM account.user u + JOIN account.roleRole rr ON rr.role = u.role + JOIN account.role r ON r.id = rr.inheritsFrom + WHERE u.id = ?`, [userId], options); + + const roles = []; + for (const role of result) + roles.push(role.name); + + return roles; + }; + + Self.on('resetPasswordRequest', async function(info) { + const loopBackContext = LoopBackContext.getCurrentContext(); + const httpCtx = {req: loopBackContext.active}; + const httpRequest = httpCtx.req.http.req; + const headers = httpRequest.headers; + const origin = headers.origin; + + const user = await Self.app.models.VnUser.findById(info.user.id); + const params = { + recipient: info.email, + lang: user.lang, + url: `${origin}/#!/reset-password?access_token=${info.accessToken.id}` + }; + + const options = Object.assign({}, info.options); + for (const param in options) + params[param] = options[param]; + + const email = new Email(options.emailTemplate, params); + + return email.send(); + }); +}; diff --git a/back/models/account.json b/back/models/vn-user.json similarity index 86% rename from back/models/account.json rename to back/models/vn-user.json index 5e35c711a..17efc8ce6 100644 --- a/back/models/account.json +++ b/back/models/vn-user.json @@ -1,11 +1,13 @@ { - "name": "Account", - "base": "VnModel", + "name": "VnUser", + "base": "User", + "validateUpsert": true, "options": { "mysql": { "table": "account.user" } }, + "resetPasswordTokenTTL": "604800", "properties": { "id": { "type": "number", @@ -15,6 +17,19 @@ "type": "string", "required": true }, + "username": { + "type": "string", + "mysql": { + "columnName": "name" + } + }, + "password": { + "type": "string", + "required": true, + "mysql": { + "columnName": "bcryptPassword" + } + }, "roleFk": { "type": "number", "mysql": { @@ -27,10 +42,6 @@ "lang": { "type": "string" }, - "password": { - "type": "string", - "required": true - }, "bcryptPassword": { "type": "string" }, @@ -40,9 +51,6 @@ "email": { "type": "string" }, - "emailVerified": { - "type": "boolean" - }, "created": { "type": "date" }, @@ -86,7 +94,7 @@ }, "acls": [ { - "property": "login", + "property": "signIn", "accessType": "EXECUTE", "principalType": "ROLE", "principalId": "$everyone", @@ -100,13 +108,6 @@ "permission": "ALLOW" }, { - "property": "logout", - "accessType": "EXECUTE", - "principalType": "ROLE", - "principalId": "$authenticated", - "permission": "ALLOW" - }, - { "property": "validateToken", "accessType": "EXECUTE", "principalType": "ROLE", diff --git a/back/tests.js b/back/tests.js index a377011d3..97e548d33 100644 --- a/back/tests.js +++ b/back/tests.js @@ -34,6 +34,8 @@ async function test() { app.boot(bootOptions, err => err ? reject(err) : resolve()); }); + // FIXME: Workaround to wait for loopback to be ready + await app.models.Application.status(); const Jasmine = require('jasmine'); const jasmine = new Jasmine(); diff --git a/db/.archive/225201/00-invoiceOut_new.sql b/db/.archive/225201/00-invoiceOut_new.sql index 10a42d40d..4c60b50bc 100644 --- a/db/.archive/225201/00-invoiceOut_new.sql +++ b/db/.archive/225201/00-invoiceOut_new.sql @@ -8,7 +8,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`( BEGIN /** * Creación de facturas emitidas. - * requiere previamente tabla ticketToInvoice(id). + * requiere previamente tabla tmp.ticketToInvoice(id). * * @param vSerial serie a la cual se hace la factura * @param vInvoiceDate fecha de la factura @@ -36,13 +36,13 @@ BEGIN SELECT t.clientFk, t.companyFk INTO vClient, vCompany - FROM ticketToInvoice tt + FROM tmp.ticketToInvoice tt JOIN ticket t ON t.id = tt.id LIMIT 1; - -- Eliminem de ticketToInvoice els tickets que no han de ser facturats + -- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats DELETE ti.* - FROM ticketToInvoice ti + FROM tmp.ticketToInvoice ti JOIN ticket t ON t.id = ti.id JOIN sale s ON s.ticketFk = t.id JOIN item i ON i.id = s.itemFk @@ -57,7 +57,7 @@ BEGIN SELECT SUM(s.quantity * s.price * (100 - s.discount)/100), ts.id INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice - FROM ticketToInvoice t + FROM tmp.ticketToInvoice t LEFT JOIN sale s ON s.ticketFk = t.id LEFT JOIN ticketService ts ON ts.ticketFk = t.id; @@ -100,13 +100,13 @@ BEGIN WHERE id = vNewInvoiceId; UPDATE ticket t - JOIN ticketToInvoice ti ON ti.id = t.id + JOIN tmp.ticketToInvoice ti ON ti.id = t.id SET t.refFk = vNewRef; DROP TEMPORARY TABLE IF EXISTS tmp.updateInter; CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador - FROM ticketToInvoice ti + FROM tmp.ticketToInvoice ti LEFT JOIN ticketState ts ON ti.id = ts.ticket JOIN state s WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id); @@ -116,7 +116,7 @@ BEGIN INSERT INTO ticketLog (action, userFk, originFk, description) SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef) - FROM ticketToInvoice ti; + FROM tmp.ticketToInvoice ti; CALL invoiceExpenceMake(vNewInvoiceId); CALL invoiceTaxMake(vNewInvoiceId,vTaxArea); @@ -159,7 +159,7 @@ BEGIN (KEY (ticketFk)) ENGINE = MEMORY SELECT id ticketFk - FROM ticketToInvoice; + FROM tmp.ticketToInvoice; CALL `ticket_getTax`('NATIONAL'); @@ -220,6 +220,6 @@ BEGIN END IF; - DROP TEMPORARY TABLE `ticketToInvoice`; + DROP TEMPORARY TABLE `tmp`.`ticketToInvoice`; END$$ DELIMITER ; diff --git a/db/changes/230401/00-ACL.sql b/db/changes/230401/00-ACL.sql new file mode 100644 index 000000000..ae9f781f7 --- /dev/null +++ b/db/changes/230401/00-ACL.sql @@ -0,0 +1,18 @@ +INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) +VALUES ('VnUser', '*', '*', 'ALLOW', 'ROLE', 'employee'); + +INSERT INTO `salix`.`ACL` (id, model, property, accessType, permission, principalType, principalId) +VALUES ('VnUser', 'acl', 'READ', 'ALLOW', 'ROLE', 'account'); + +INSERT INTO `salix`.`ACL` (id, model, property, accessType, permission, principalType, principalId) +VALUES ('VnUser', 'getCurrentUserData', 'READ', 'ALLOW', 'ROLE', 'account'); + +INSERT INTO `salix`.`ACL` (id, model, property, accessType, permission, principalType, principalId) +VALUES ('VnUser', 'changePassword', '*', 'ALLOW', 'ROLE', 'account'); + + + +UPDATE `hedera`.`imageCollection` t +SET t.model = 'VnUser' +WHERE t.id = 6; + diff --git a/db/changes/231001/02-invoiceOut_new.sql b/db/changes/231001/02-invoiceOut_new.sql index 0fd91ef58..d2b96eff7 100644 --- a/db/changes/231001/02-invoiceOut_new.sql +++ b/db/changes/231001/02-invoiceOut_new.sql @@ -10,14 +10,14 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`( BEGIN /** * Creación de facturas emitidas. - * requiere previamente tabla ticketToInvoice(id). + * requiere previamente tabla tmp.ticketToInvoice(id). * * @param vSerial serie a la cual se hace la factura * @param vInvoiceDate fecha de la factura * @param vTaxArea tipo de iva en relacion a la empresa y al cliente * @param vNewInvoiceId id de la factura que se acaba de generar * @return vNewInvoiceId - */ + */ DECLARE vIsAnySaleToInvoice BOOL; DECLARE vIsAnyServiceToInvoice BOOL; DECLARE vNewRef VARCHAR(255); @@ -37,32 +37,32 @@ BEGIN DECLARE vMaxShipped DATE; SET vInvoiceDate = IFNULL(vInvoiceDate, util.CURDATE()); - - SELECT t.clientFk, - t.companyFk, + + SELECT t.clientFk, + t.companyFk, MAX(DATE(t.shipped)), DATE(vInvoiceDate) >= invoiceOut_getMaxIssued( - vSerial, - t.companyFk, + vSerial, + t.companyFk, YEAR(vInvoiceDate)) - INTO vClientFk, + INTO vClientFk, vCompanyFk, vMaxShipped, vIsCorrectInvoiceDate - FROM ticketToInvoice tt + FROM tmp.ticketToInvoice tt JOIN ticket t ON t.id = tt.id; - IF(vMaxShipped > vInvoiceDate) THEN + IF(vMaxShipped > vInvoiceDate) THEN CALL util.throw("Invoice date can't be less than max date"); END IF; - + IF NOT vIsCorrectInvoiceDate THEN CALL util.throw('Exists an invoice with a previous date'); END IF; - - -- Eliminem de ticketToInvoice els tickets que no han de ser facturats + + -- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats DELETE ti.* - FROM ticketToInvoice ti + FROM tmp.ticketToInvoice ti JOIN ticket t ON t.id = ti.id JOIN sale s ON s.ticketFk = t.id JOIN item i ON i.id = s.itemFk @@ -77,11 +77,11 @@ BEGIN SELECT SUM(s.quantity * s.price * (100 - s.discount)/100) <> 0 INTO vIsAnySaleToInvoice - FROM ticketToInvoice t + FROM tmp.ticketToInvoice t JOIN sale s ON s.ticketFk = t.id; SELECT COUNT(*) > 0 INTO vIsAnyServiceToInvoice - FROM ticketToInvoice t + FROM tmp.ticketToInvoice t JOIN ticketService ts ON ts.ticketFk = t.id; IF (vIsAnySaleToInvoice OR vIsAnyServiceToInvoice) @@ -121,13 +121,13 @@ BEGIN WHERE id = vNewInvoiceId; UPDATE ticket t - JOIN ticketToInvoice ti ON ti.id = t.id + JOIN tmp.ticketToInvoice ti ON ti.id = t.id SET t.refFk = vNewRef; DROP TEMPORARY TABLE IF EXISTS tmp.updateInter; CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador - FROM ticketToInvoice ti + FROM tmp.ticketToInvoice ti LEFT JOIN ticketState ts ON ti.id = ts.ticket JOIN state s WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id); @@ -137,7 +137,7 @@ BEGIN INSERT INTO ticketLog (action, userFk, originFk, description) SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef) - FROM ticketToInvoice ti; + FROM tmp.ticketToInvoice ti; CALL invoiceExpenceMake(vNewInvoiceId); CALL invoiceTaxMake(vNewInvoiceId,vTaxArea); @@ -157,12 +157,12 @@ BEGIN WHERE io.id = vNewInvoiceId; DROP TEMPORARY TABLE tmp.updateInter; - - SELECT COUNT(*), id + + SELECT COUNT(*), id INTO vIsInterCompany, vInterCompanyFk - FROM company + FROM company WHERE clientFk = vClientFk; - + IF (vIsInterCompany) THEN INSERT INTO invoiceIn(supplierFk, supplierRef, issued, companyFk) @@ -175,7 +175,7 @@ BEGIN (KEY (ticketFk)) ENGINE = MEMORY SELECT id ticketFk - FROM ticketToInvoice; + FROM tmp.ticketToInvoice; CALL `ticket_getTax`('NATIONAL'); @@ -201,7 +201,7 @@ BEGIN ) sub; INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk) - SELECT vNewInvoiceInFk, + SELECT vNewInvoiceInFk, SUM(tt.taxableBase) - IF(tt.code = @vTaxCodeGeneral, @vTaxableBaseServices, 0) taxableBase, i.expenceFk, @@ -215,13 +215,13 @@ BEGIN ORDER BY tt.priority; CALL invoiceInDueDay_calculate(vNewInvoiceInFk); - - SELECT COUNT(*) INTO vIsCEESerial + + SELECT COUNT(*) INTO vIsCEESerial FROM invoiceOutSerial WHERE code = vSerial; IF vIsCEESerial THEN - + INSERT INTO invoiceInIntrastat ( invoiceInFk, intrastatFk, @@ -253,6 +253,6 @@ BEGIN DROP TEMPORARY TABLE tmp.ticketServiceTax; END IF; END IF; - DROP TEMPORARY TABLE `ticketToInvoice`; + DROP TEMPORARY TABLE tmp.`ticketToInvoice`; END$$ -DELIMITER ; \ No newline at end of file +DELIMITER ; diff --git a/db/changes/231201/00-wagon.sql b/db/changes/231201/00-wagon.sql index 3e4d225d7..9e817bac4 100644 --- a/db/changes/231201/00-wagon.sql +++ b/db/changes/231201/00-wagon.sql @@ -56,8 +56,6 @@ CREATE TABLE `vn`.`collectionWagonTicket` ( ALTER TABLE `vn`.`wagon` ADD `typeFk` int(11) unsigned NOT NULL; ALTER TABLE `vn`.`wagon` ADD `label` int(11) unsigned NOT NULL; -ALTER TABLE `vn`.`wagon` ADD CONSTRAINT `wagon_type` FOREIGN KEY (`typeFk`) REFERENCES `wagonType` (`id`) ON UPDATE CASCADE; - INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('WagonType', '*', '*', 'ALLOW', 'ROLE', 'productionAssi'), @@ -70,3 +68,4 @@ INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `pri ('WagonType', 'createWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi'), ('WagonType', 'deleteWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi'), ('WagonType', 'editWagonType', '*', 'ALLOW', 'ROLE', 'productionAssi'); + diff --git a/db/changes/231801/00-aclClientInforma.sql b/db/changes/231801/00-aclClientInforma.sql new file mode 100644 index 000000000..6222d2632 --- /dev/null +++ b/db/changes/231801/00-aclClientInforma.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) +VALUES ('ClientInforma', '*', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('ClientInforma', '*', 'WRITE', 'ALLOW', 'ROLE', 'financial'); diff --git a/db/changes/231801/00-acl_receiptEmail.sql b/db/changes/231801/00-acl_receiptEmail.sql new file mode 100644 index 000000000..2de8adf50 --- /dev/null +++ b/db/changes/231801/00-acl_receiptEmail.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('Receipt', 'receiptEmail', '*', 'ALLOW', 'ROLE', 'salesAssistant'); diff --git a/db/changes/231801/00-clientInforma.sql b/db/changes/231801/00-clientInforma.sql new file mode 100644 index 000000000..9bf757fc3 --- /dev/null +++ b/db/changes/231801/00-clientInforma.sql @@ -0,0 +1,16 @@ +ALTER TABLE `vn`.`client` ADD rating INT UNSIGNED DEFAULT NULL NULL COMMENT 'información proporcionada por Informa'; +ALTER TABLE `vn`.`client` ADD recommendedCredit INT UNSIGNED DEFAULT NULL NULL COMMENT 'información proporcionada por Informa'; + +CREATE TABLE `vn`.`clientInforma` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `clientFk` int(11) NOT NULL, + `rating` int(10) unsigned DEFAULT NULL, + `recommendedCredit` int(10) unsigned DEFAULT NULL, + `workerFk` int(10) unsigned NOT NULL, + `created` timestamp NOT NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`), + KEY `informaWorkers_fk_idx` (`workerFk`), + KEY `informaClientFk` (`clientFk`), + CONSTRAINT `informa_ClienteFk` FOREIGN KEY (`clientFk`) REFERENCES `client` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `informa_workers_fk` FOREIGN KEY (`workerFk`) REFERENCES `worker` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE +) ENGINE=InnoDB CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='información proporcionada por Informa, se actualiza desde el hook de client (salix)'; diff --git a/db/changes/231801/00-client_setRatingAcl.sql b/db/changes/231801/00-client_setRatingAcl.sql new file mode 100644 index 000000000..b041b131a --- /dev/null +++ b/db/changes/231801/00-client_setRatingAcl.sql @@ -0,0 +1,64 @@ +DELETE FROM `salix`.`ACL` WHERE id=7; + +INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) + VALUES + ('Client', 'setRating', 'WRITE', 'ALLOW', 'ROLE', 'financial'); + +INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) + VALUES + ('Client', '*', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'addressesPropagateRe', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'canBeInvoiced', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'canCreateTicket', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'consumption', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'createAddress', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'createWithUser', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'extendedListFilter', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'getAverageInvoiced', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'getCard', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'getDebt', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'getMana', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'transactions', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'hasCustomerRole', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'isValidClient', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'lastActiveTickets', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'sendSms', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'setPassword', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'summary', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'updateAddress', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'updateFiscalData', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'updateUser', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'uploadFile', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'campaignMetricsPdf', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'campaignMetricsEmail', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientWelcomeHtml', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientWelcomeEmail', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'printerSetupHtml', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'printerSetupEmail', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'sepaCoreEmail', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorPdf', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorStHtml', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorStEmail', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorNdHtml', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorNdEmail', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientDebtStatementPdf', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientDebtStatementHtml', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientDebtStatementEmail', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'creditRequestPdf', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'creditRequestHtml', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'creditRequestEmail', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'incotermsAuthorizationPdf', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'incotermsAuthorizationHtml', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'incotermsAuthorizationEmail', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'consumptionSendQueued', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'filter', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'getClientOrSupplierReference', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'upsert', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'create', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'replaceById', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'updateAttributes', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'updateAttributes', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'deleteById', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'replaceOrCreate', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'updateAll', '*', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'upsertWithWhere', '*', 'ALLOW', 'ROLE', 'employee'); diff --git a/db/changes/231801/00-deleteProcs_refund.sql b/db/changes/231801/00-deleteProcs_refund.sql new file mode 100644 index 000000000..8bf8982f4 --- /dev/null +++ b/db/changes/231801/00-deleteProcs_refund.sql @@ -0,0 +1,2 @@ +DROP PROCEDURE `vn`.`refund`; +DROP PROCEDURE `vn`.`ticket_doRefund`; diff --git a/db/changes/231801/00-deviceProduction.sql b/db/changes/231801/00-deviceProduction.sql new file mode 100644 index 000000000..37a2f1371 --- /dev/null +++ b/db/changes/231801/00-deviceProduction.sql @@ -0,0 +1,5 @@ +DROP TRIGGER `vn`.`deviceProduction_afterInsert`; +DROP TRIGGER `vn`.`deviceProduction_afterUpdate`; + +DROP TRIGGER `vn`.`deviceProductionUser_afterDelete`; + diff --git a/db/changes/231801/00-kkearEntryNotes.sql b/db/changes/231801/00-kkearEntryNotes.sql new file mode 100644 index 000000000..ff5c7ce29 --- /dev/null +++ b/db/changes/231801/00-kkearEntryNotes.sql @@ -0,0 +1 @@ +ALTER TABLE `vn`.`entry` DROP COLUMN `notes`; \ No newline at end of file diff --git a/db/changes/231801/00-newCompanyI18n.sql b/db/changes/231801/00-newCompanyI18n.sql new file mode 100644 index 000000000..948b9cb08 --- /dev/null +++ b/db/changes/231801/00-newCompanyI18n.sql @@ -0,0 +1,9 @@ +-- vn.companyI18n definition +CREATE TABLE `vn`.`companyI18n` ( + `companyFk` smallint(5) unsigned NOT NULL, + `lang` char(2) CHARACTER SET utf8mb3 NOT NULL, + `footnotes` longtext COLLATE utf8mb3_unicode_ci DEFAULT NULL, + PRIMARY KEY (`companyFk`,`lang`), + CONSTRAINT `companyI18n_FK` FOREIGN KEY (`companyFk`) REFERENCES `company` (`id`) ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; + diff --git a/db/changes/231801/00-newTableWeb.sql b/db/changes/231801/00-newTableWeb.sql new file mode 100644 index 000000000..1a2402956 --- /dev/null +++ b/db/changes/231801/00-newTableWeb.sql @@ -0,0 +1 @@ +ALTER TABLE `vn`.`company` ADD `web` varchar(100) NULL; \ No newline at end of file diff --git a/db/changes/231801/00-observationEmailACL.sql b/db/changes/231801/00-observationEmailACL.sql new file mode 100644 index 000000000..1a5d475e8 --- /dev/null +++ b/db/changes/231801/00-observationEmailACL.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('Defaulter', 'observationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'); diff --git a/db/changes/231801/00-optimiceZoneEstimatedDelivery.sql b/db/changes/231801/00-optimiceZoneEstimatedDelivery.sql new file mode 100644 index 000000000..209e1efc3 --- /dev/null +++ b/db/changes/231801/00-optimiceZoneEstimatedDelivery.sql @@ -0,0 +1,77 @@ +CREATE OR REPLACE +ALGORITHM = UNDEFINED VIEW `vn`.`zoneEstimatedDelivery` AS +select + `t`.`zoneFk` AS `zoneFk`, + cast(`util`.`VN_CURDATE`() + interval hour(ifnull(`zc`.`hour`, `z`.`hour`)) * 60 + minute(ifnull(`zc`.`hour`, `z`.`hour`)) minute as time) AS `hourTheoretical`, + cast(sum(`sv`.`volume`) as decimal(5, 1)) AS `totalVolume`, + cast(sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) as decimal(5, 1)) AS `remainingVolume`, + greatest( + ifnull(`lhp`.`m3`, 0), + ifnull(`dl`.`minSpeed`, 0) + ) AS `speed`, + cast(`zc`.`hour` + interval -sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) * 60 / greatest(ifnull(`lhp`.`m3`, 0), ifnull(`dl`.`minSpeed`, 0)) minute as time) AS `hourEffective`, + floor(-sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) * 60 / greatest(ifnull(`lhp`.`m3`, 0), ifnull(`dl`.`minSpeed`, 0))) AS `minutesLess`, + cast(`zc`.`hour` + interval -sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) * 60 / greatest(ifnull(`lhp`.`m3`, 0), ifnull(`dl`.`minSpeed`, 0)) minute as time) AS `etc` +from + ( + ( + ( + ( + ( + ( + ( + ( + ( + `vn`.`ticket` `t` + join `vn`.`ticketStateToday` `tst` on + ( + `tst`.`ticket` = `t`.`id` + ) + ) + join `vn`.`state` `s` on + ( + `s`.`id` = `tst`.`state` + ) + ) + join `vn`.`saleVolume` `sv` on + ( + `sv`.`ticketFk` = `t`.`id` + ) + ) + left join `vn`.`lastHourProduction` `lhp` on + ( + `lhp`.`warehouseFk` = `t`.`warehouseFk` + ) + ) + join `vn`.`warehouse` `w` on + ( + `w`.`id` = `t`.`warehouseFk` + ) + ) + join `vn`.`warehouseAlias` `wa` on + ( + `wa`.`id` = `w`.`aliasFk` + ) + ) + straight_join `vn`.`zone` `z` on + ( + `z`.`id` = `t`.`zoneFk` + ) + ) + left join `vn`.`zoneClosure` `zc` on + ( + `zc`.`zoneFk` = `t`.`zoneFk` + and `zc`.`dated` = `util`.`VN_CURDATE`() + ) + ) + left join `cache`.`departure_limit` `dl` on + ( + `dl`.`warehouse_id` = `t`.`warehouseFk` + and `dl`.`fecha` = `util`.`VN_CURDATE`() + ) + ) +where + `w`.`hasProduction` <> 0 + and cast(`t`.`shipped` as date) = `util`.`VN_CURDATE`() +group by + `t`.`zoneFk`; diff --git a/db/changes/231801/00-saleTracking.sql b/db/changes/231801/00-saleTracking.sql new file mode 100644 index 000000000..d651a2447 --- /dev/null +++ b/db/changes/231801/00-saleTracking.sql @@ -0,0 +1,5 @@ +DROP PROCEDURE IF EXISTS `vn`.`sale_setQuantity`; +DROP PROCEDURE IF EXISTS `vn`.`collection_updateSale`; +DROP PROCEDURE IF EXISTS `vn`.`replaceMovimientosMark`; +DROP PROCEDURE IF EXISTS `vn`.`saleTracking_Replace`; +DROP PROCEDURE IF EXISTS `vn`.`sale_updateOriginalQuantity`; diff --git a/db/changes/231801/00-ticketConfig.sql b/db/changes/231801/00-ticketConfig.sql new file mode 100644 index 000000000..7c8aa83a4 --- /dev/null +++ b/db/changes/231801/00-ticketConfig.sql @@ -0,0 +1 @@ +ALTER TABLE `vn`.`ticketConfig` ADD daysForWarningClaim INT DEFAULT 2 NOT NULL COMMENT 'dias restantes hasta que salte el aviso de reclamación fuera de plazo'; diff --git a/db/changes/231801/00-updateIsVies.sql b/db/changes/231801/00-updateIsVies.sql new file mode 100644 index 000000000..4e5277559 --- /dev/null +++ b/db/changes/231801/00-updateIsVies.sql @@ -0,0 +1,5 @@ + UPDATE `vn`.`supplier` s + JOIN `vn`.`country` c ON c.id = s.countryFk + SET s.nif = MID(REPLACE(s.nif, ' ', ''), 3, LENGTH(REPLACE(s.nif, ' ', '')) - 1) + WHERE s.isVies = TRUE + AND c.code = LEFT(REPLACE(s.nif, ' ', ''), 2); diff --git a/db/changes/231801/00-updateisViesClient.sql b/db/changes/231801/00-updateisViesClient.sql new file mode 100644 index 000000000..a153c5219 --- /dev/null +++ b/db/changes/231801/00-updateisViesClient.sql @@ -0,0 +1,5 @@ +UPDATE IGNORE `vn`.`client` c + JOIN `vn`.`country` co ON co.id = c.countryFk + SET c.fi = MID(REPLACE(c.fi, ' ', ''), 3, LENGTH(REPLACE(c.fi, ' ', '')) - 1) + WHERE c.isVies = TRUE + AND co.code = LEFT(REPLACE(c.fi, ' ', ''), 2); diff --git a/db/changes/231801/00-userAcl.sql b/db/changes/231801/00-userAcl.sql new file mode 100644 index 000000000..64803bf18 --- /dev/null +++ b/db/changes/231801/00-userAcl.sql @@ -0,0 +1,21 @@ +INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) + VALUES + ('VnUser', '*', '*', 'ALLOW', 'ROLE', 'employee'), + ('VnUser','acl','READ','ALLOW','ROLE','account'), + ('VnUser','getCurrentUserData','READ','ALLOW','ROLE','account'), + ('VnUser','changePassword', 'WRITE', 'ALLOW', 'ROLE', 'account'), + ('Account','exists','READ','ALLOW','ROLE','account'); + +INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) + VALUES + ('Account','exists','READ','ALLOW','ROLE','account'); + +DELETE FROM `salix`.`ACL` WHERE (model, property) = ('Account', 'acl'); +DELETE FROM `salix`.`ACL` WHERE (model, property) = ('Account', 'getCurrentUserData'); +DELETE FROM `salix`.`ACL` WHERE (model, property) = ('Account', 'changePassword'); +DELETE FROM `salix`.`ACL` WHERE model = 'UserAccount'; + +UPDATE `hedera`.`imageCollection` t +SET t.model = 'VnUser' +WHERE t.id = 6; + diff --git a/db/changes/231801/00-userRoleLog.sql b/db/changes/231801/00-userRoleLog.sql new file mode 100644 index 000000000..ae5da13cb --- /dev/null +++ b/db/changes/231801/00-userRoleLog.sql @@ -0,0 +1,4 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('UserLog', '*', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('RoleLog', '*', 'READ', 'ALLOW', 'ROLE', 'employee'); diff --git a/db/changes/231801/01-viewCompany10L.sql b/db/changes/231801/01-viewCompany10L.sql new file mode 100644 index 000000000..335827b42 --- /dev/null +++ b/db/changes/231801/01-viewCompany10L.sql @@ -0,0 +1,12 @@ +-- vn.companyL10n source + +CREATE OR REPLACE +ALGORITHM = UNDEFINED VIEW `vn`.`companyL10n` AS +select + `c`.`id` AS `id`, + ifnull(`ci`.`footnotes`, `c`.`footnotes`) AS `footnotes` +from + (`vn`.`company` `c` +left join `vn`.`companyI18n` `ci` on + (`ci`.`companyFk` = `c`.`id` + and `ci`.`lang` = `util`.`LANG`())); \ No newline at end of file diff --git a/db/changes/232001/.gitkeep b/db/changes/232001/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/db/changes/232001/00-clientWorkerName.sql b/db/changes/232001/00-clientWorkerName.sql new file mode 100644 index 000000000..676d26691 --- /dev/null +++ b/db/changes/232001/00-clientWorkerName.sql @@ -0,0 +1,73 @@ +DELIMITER $$ +CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`clientCreate`( + vFirstname VARCHAR(50), + vSurnames VARCHAR(50), + vFi VARCHAR(9), + vAddress TEXT, + vPostcode CHAR(5), + vCity VARCHAR(25), + vProvinceFk SMALLINT(5), + vCompanyFk SMALLINT(5), + vPhone VARCHAR(11), + vEmail VARCHAR(255), + vUserFk INT) +BEGIN +/** + * Create new client + * + */ + DECLARE vPayMethodFk INT DEFAULT 4; + DECLARE vDueDay INT DEFAULT 5; + DECLARE vDefaultCredit DECIMAL(10, 2) DEFAULT 300.00; + DECLARE vIsTaxDataChecked TINYINT(1) DEFAULT 1; + DECLARE vHasCoreVnl BOOLEAN DEFAULT TRUE; + DECLARE vMandateTypeFk INT DEFAULT 2; + + INSERT INTO `client` ( + id, + name, + street, + fi, + phone, + email, + provinceFk, + city, + postcode, + socialName, + payMethodFk, + dueDay, + credit, + isTaxDataChecked, + hasCoreVnl, + isEqualizated) + VALUES ( + vUserFk, + CONCAT(vFirstname, ' ', vSurnames), + vAddress, + TRIM(vFi), + vPhone, + vEmail, + vProvinceFk, + vCity, + vPostcode, + CONCAT(vSurnames, ' ', vFirstname), + vPayMethodFk, + vDueDay, + vDefaultCredit, + vIsTaxDataChecked, + vHasCoreVnl, + FALSE + ) ON duplicate key update + payMethodFk = vPayMethodFk, + dueDay = vDueDay, + credit = vDefaultCredit, + isTaxDataChecked = vIsTaxDataChecked, + hasCoreVnl = vHasCoreVnl, + isActive = TRUE; + + IF (SELECT COUNT(*) FROM mandate WHERE clientFk = vUserFk AND companyFk = vCompanyFk AND mandateTypeFk = vMandateTypeFk) = 0 THEN + INSERT INTO mandate (clientFk, companyFk, mandateTypeFk) + VALUES (vUserFk, vCompanyFk, vMandateTypeFk); + END IF; +END$$ +DELIMITER ; \ No newline at end of file diff --git a/db/changes/232001/00-createWorker.sql b/db/changes/232001/00-createWorker.sql new file mode 100644 index 000000000..0ea7ecbe8 --- /dev/null +++ b/db/changes/232001/00-createWorker.sql @@ -0,0 +1,14 @@ +INSERT INTO `vn`.`businessType` (`code`, `description`) + VALUES ('worker','Trabajador'); + +ALTER TABLE `vn`.`workerConfig` ADD businessTypeFk varchar(100) NULL + COMMENT 'Tipo de negocio por defecto al dar de alta un trabajador nuevo'; + +UPDATE `vn`.`workerConfig` + SET businessTypeFk = 'worker' + WHERE id = 1; + + UPDATE `vn`.`client` c + JOIN `vn`.`worker` w ON w.id = c.id + SET c.name = REPLACE(c.name, 'TR ', ''), + c.businessTypeFk = 'worker'; diff --git a/db/changes/232001/00-invoiceOut_new.sql b/db/changes/232001/00-invoiceOut_new.sql new file mode 100644 index 000000000..b4fc5c824 --- /dev/null +++ b/db/changes/232001/00-invoiceOut_new.sql @@ -0,0 +1,254 @@ +DROP PROCEDURE IF EXISTS `vn`.`invoiceOut_new`; + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`( + vSerial VARCHAR(255), + vInvoiceDate DATE, + vTaxArea VARCHAR(25), + OUT vNewInvoiceId INT) +BEGIN +/** + * Creación de facturas emitidas. + * requiere previamente tabla tmp.ticketToInvoice(id). + * + * @param vSerial serie a la cual se hace la factura + * @param vInvoiceDate fecha de la factura + * @param vTaxArea tipo de iva en relacion a la empresa y al cliente + * @param vNewInvoiceId id de la factura que se acaba de generar + * @return vNewInvoiceId + */ + DECLARE vIsAnySaleToInvoice BOOL; + DECLARE vIsAnyServiceToInvoice BOOL; + DECLARE vNewRef VARCHAR(255); + DECLARE vWorker INT DEFAULT account.myUser_getId(); + DECLARE vCompanyFk INT; + DECLARE vInterCompanyFk INT; + DECLARE vClientFk INT; + DECLARE vCplusStandardInvoiceTypeFk INT DEFAULT 1; + DECLARE vCplusCorrectingInvoiceTypeFk INT DEFAULT 6; + DECLARE vCplusSimplifiedInvoiceTypeFk INT DEFAULT 2; + DECLARE vCorrectingSerial VARCHAR(1) DEFAULT 'R'; + DECLARE vSimplifiedSerial VARCHAR(1) DEFAULT 'S'; + DECLARE vNewInvoiceInFk INT; + DECLARE vIsInterCompany BOOL DEFAULT FALSE; + DECLARE vIsCEESerial BOOL DEFAULT FALSE; + DECLARE vIsCorrectInvoiceDate BOOL; + DECLARE vMaxShipped DATE; + + SET vInvoiceDate = IFNULL(vInvoiceDate, util.VN_CURDATE()); + + SELECT t.clientFk, + t.companyFk, + MAX(DATE(t.shipped)), + DATE(vInvoiceDate) >= invoiceOut_getMaxIssued( + vSerial, + t.companyFk, + YEAR(vInvoiceDate)) + INTO vClientFk, + vCompanyFk, + vMaxShipped, + vIsCorrectInvoiceDate + FROM tmp.ticketToInvoice tt + JOIN ticket t ON t.id = tt.id; + + IF(vMaxShipped > vInvoiceDate) THEN + CALL util.throw("Invoice date can't be less than max date"); + END IF; + + IF NOT vIsCorrectInvoiceDate THEN + CALL util.throw('Exists an invoice with a previous date'); + END IF; + + -- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats + DELETE ti.* + FROM tmp.ticketToInvoice ti + JOIN ticket t ON t.id = ti.id + JOIN sale s ON s.ticketFk = t.id + JOIN item i ON i.id = s.itemFk + JOIN supplier su ON su.id = t.companyFk + JOIN client c ON c.id = t.clientFk + LEFT JOIN itemTaxCountry itc ON itc.itemFk = i.id AND itc.countryFk = su.countryFk + WHERE (YEAR(t.shipped) < 2001 AND t.isDeleted) + OR c.isTaxDataChecked = FALSE + OR t.isDeleted + OR c.hasToInvoice = FALSE + OR itc.id IS NULL; + + SELECT SUM(s.quantity * s.price * (100 - s.discount)/100) <> 0 + INTO vIsAnySaleToInvoice + FROM tmp.ticketToInvoice t + JOIN sale s ON s.ticketFk = t.id; + + SELECT COUNT(*) > 0 INTO vIsAnyServiceToInvoice + FROM tmp.ticketToInvoice t + JOIN ticketService ts ON ts.ticketFk = t.id; + + IF (vIsAnySaleToInvoice OR vIsAnyServiceToInvoice) + AND (vCorrectingSerial = vSerial OR NOT hasAnyNegativeBase()) + THEN + + -- el trigger añade el siguiente Id_Factura correspondiente a la vSerial + INSERT INTO invoiceOut( + ref, + serial, + issued, + clientFk, + dued, + companyFk, + cplusInvoiceType477Fk + ) + SELECT + 1, + vSerial, + vInvoiceDate, + vClientFk, + getDueDate(vInvoiceDate, dueDay), + vCompanyFk, + IF(vSerial = vCorrectingSerial, + vCplusCorrectingInvoiceTypeFk, + IF(vSerial = vSimplifiedSerial, + vCplusSimplifiedInvoiceTypeFk, + vCplusStandardInvoiceTypeFk)) + FROM client + WHERE id = vClientFk; + + SET vNewInvoiceId = LAST_INSERT_ID(); + + SELECT `ref` + INTO vNewRef + FROM invoiceOut + WHERE id = vNewInvoiceId; + + UPDATE ticket t + JOIN tmp.ticketToInvoice ti ON ti.id = t.id + SET t.refFk = vNewRef; + + DROP TEMPORARY TABLE IF EXISTS tmp.updateInter; + CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY + SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador + FROM tmp.ticketToInvoice ti + LEFT JOIN ticketState ts ON ti.id = ts.ticket + JOIN state s + WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id); + + INSERT INTO ticketTracking(stateFk,ticketFk,workerFk) + SELECT * FROM tmp.updateInter; + + CALL invoiceExpenceMake(vNewInvoiceId); + CALL invoiceTaxMake(vNewInvoiceId,vTaxArea); + + UPDATE invoiceOut io + JOIN ( + SELECT SUM(amount) total + FROM invoiceOutExpence + WHERE invoiceOutFk = vNewInvoiceId + ) base + JOIN ( + SELECT SUM(vat) total + FROM invoiceOutTax + WHERE invoiceOutFk = vNewInvoiceId + ) vat + SET io.amount = base.total + vat.total + WHERE io.id = vNewInvoiceId; + + DROP TEMPORARY TABLE tmp.updateInter; + + SELECT COUNT(*), id + INTO vIsInterCompany, vInterCompanyFk + FROM company + WHERE clientFk = vClientFk; + + IF (vIsInterCompany) THEN + + INSERT INTO invoiceIn(supplierFk, supplierRef, issued, companyFk) + SELECT vCompanyFk, vNewRef, vInvoiceDate, vInterCompanyFk; + + SET vNewInvoiceInFk = LAST_INSERT_ID(); + + DROP TEMPORARY TABLE IF EXISTS tmp.ticket; + CREATE TEMPORARY TABLE tmp.ticket + (KEY (ticketFk)) + ENGINE = MEMORY + SELECT id ticketFk + FROM tmp.ticketToInvoice; + + CALL `ticket_getTax`('NATIONAL'); + + SET @vTaxableBaseServices := 0.00; + SET @vTaxCodeGeneral := NULL; + + INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk) + SELECT vNewInvoiceInFk, + @vTaxableBaseServices, + sub.expenceFk, + sub.taxTypeSageFk, + sub.transactionTypeSageFk + FROM ( + SELECT @vTaxableBaseServices := SUM(tst.taxableBase) taxableBase, + i.expenceFk, + i.taxTypeSageFk, + i.transactionTypeSageFk, + @vTaxCodeGeneral := i.taxClassCodeFk + FROM tmp.ticketServiceTax tst + JOIN invoiceOutTaxConfig i ON i.taxClassCodeFk = tst.code + WHERE i.isService + HAVING taxableBase + ) sub; + + INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk) + SELECT vNewInvoiceInFk, + SUM(tt.taxableBase) - IF(tt.code = @vTaxCodeGeneral, + @vTaxableBaseServices, 0) taxableBase, + i.expenceFk, + i.taxTypeSageFk , + i.transactionTypeSageFk + FROM tmp.ticketTax tt + JOIN invoiceOutTaxConfig i ON i.taxClassCodeFk = tt.code + WHERE !i.isService + GROUP BY tt.pgcFk + HAVING taxableBase + ORDER BY tt.priority; + + CALL invoiceInDueDay_calculate(vNewInvoiceInFk); + + SELECT COUNT(*) INTO vIsCEESerial + FROM invoiceOutSerial + WHERE code = vSerial; + + IF vIsCEESerial THEN + + INSERT INTO invoiceInIntrastat ( + invoiceInFk, + intrastatFk, + amount, + stems, + countryFk, + net) + SELECT + vNewInvoiceInFk, + i.intrastatFk, + SUM(CAST((s.quantity * s.price * (100 - s.discount) / 100 ) AS DECIMAL(10, 2))), + SUM(CAST(IFNULL(i.stems, 1) * s.quantity AS DECIMAL(10, 2))), + su.countryFk, + CAST(SUM(IFNULL(i.stems, 1) + * s.quantity + * IF(ic.grams, ic.grams, IFNULL(i.weightByPiece, 0)) / 1000) AS DECIMAL(10, 2)) + FROM sale s + JOIN ticket t ON s.ticketFk = t.id + JOIN supplier su ON su.id = t.companyFk + JOIN item i ON i.id = s.itemFk + LEFT JOIN itemCost ic ON ic.itemFk = i.id AND ic.warehouseFk = t.warehouseFk + WHERE t.refFk = vNewRef + GROUP BY i.intrastatFk; + + END IF; + DROP TEMPORARY TABLE tmp.ticket; + DROP TEMPORARY TABLE tmp.ticketAmount; + DROP TEMPORARY TABLE tmp.ticketTax; + DROP TEMPORARY TABLE tmp.ticketServiceTax; + END IF; + END IF; + DROP TEMPORARY TABLE `tmp`.`ticketToInvoice`; +END$$ +DELIMITER ; diff --git a/db/changes/232001/00-wagon.sql b/db/changes/232001/00-wagon.sql new file mode 100644 index 000000000..bdb384db5 --- /dev/null +++ b/db/changes/232001/00-wagon.sql @@ -0,0 +1 @@ +ALTER TABLE `vn`.`wagon` ADD CONSTRAINT `wagon_type` FOREIGN KEY (`typeFk`) REFERENCES `wagonType` (`id`) ON UPDATE CASCADE; diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 42298e158..d08cecdd8 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -98,20 +98,20 @@ INSERT INTO `hedera`.`tpvConfig`(`id`, `currency`, `terminal`, `transactionType` VALUES (1, 978, 1, 0, 2000, 9, 0); -INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`, `image`) +INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `bcryptPassword`, `password`,`role`,`active`,`email`,`lang`, `image`) VALUES - (1101, 'BruceWayne', 'Bruce Wayne', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'), - (1102, 'PetterParker', 'Petter Parker', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), - (1103, 'ClarkKent', 'Clark Kent', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com', 'fr', 'e7723f0b24ff05b32ed09d95196f2f29'), - (1104, 'TonyStark', 'Tony Stark', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'), - (1105, 'MaxEisenhardt', 'Max Eisenhardt', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt', 'e7723f0b24ff05b32ed09d95196f2f29'), - (1106, 'DavidCharlesHaller', 'David Charles Haller', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'DavidCharlesHaller@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), - (1107, 'HankPym', 'Hank Pym', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), - (1108, 'CharlesXavier', 'Charles Xavier', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'CharlesXavier@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), - (1109, 'BruceBanner', 'Bruce Banner', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'BruceBanner@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), - (1110, 'JessicaJones', 'Jessica Jones', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'JessicaJones@mydomain.com', 'en', NULL), - (1111, 'Missing', 'Missing', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL), - (1112, 'Trash', 'Trash', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL); + (1101, 'BruceWayne', 'Bruce Wayne', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'), + (1102, 'PetterParker', 'Petter Parker', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), + (1103, 'ClarkKent', 'Clark Kent', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@mydomain.com', 'fr', 'e7723f0b24ff05b32ed09d95196f2f29'), + (1104, 'TonyStark', 'Tony Stark', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@mydomain.com', 'es', 'e7723f0b24ff05b32ed09d95196f2f29'), + (1105, 'MaxEisenhardt', 'Max Eisenhardt', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt', 'e7723f0b24ff05b32ed09d95196f2f29'), + (1106, 'DavidCharlesHaller', 'David Charles Haller', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'DavidCharlesHaller@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), + (1107, 'HankPym', 'Hank Pym', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), + (1108, 'CharlesXavier', 'Charles Xavier', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'CharlesXavier@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), + (1109, 'BruceBanner', 'Bruce Banner', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'BruceBanner@mydomain.com', 'en', 'e7723f0b24ff05b32ed09d95196f2f29'), + (1110, 'JessicaJones', 'Jessica Jones', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'JessicaJones@mydomain.com', 'en', NULL), + (1111, 'Missing', 'Missing', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL), + (1112, 'Trash', 'Trash', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'en', NULL); INSERT INTO `account`.`mailAlias`(`id`, `alias`, `description`, `isPublic`) VALUES @@ -546,7 +546,8 @@ INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif` VALUES (1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, util.VN_CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1, '400664487V'), (2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 0, util.VN_CURDATE(), 1, 'supplier address 2', 'GOTHAM', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals', 1, '400664487V'), - (442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, util.VN_CURDATE(), 1, 'supplier address 3', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V'); + (442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, util.VN_CURDATE(), 1, 'supplier address 3', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V'), + (1381, 'Ornamentales', 'Ornamentales', 7185000440, 1, '03815934E', 0, util.VN_CURDATE(), 1, 'supplier address 4', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V'); INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`) VALUES @@ -1408,16 +1409,16 @@ INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseO (7, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1), (8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2); -INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `isRaid`, `notes`, `evaNotes`) +INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `isRaid`, `evaNotes`) VALUES - (1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1, 442, 'IN2001', 'Movement 1', 0, 0, '', ''), - (2, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 442, 'IN2002', 'Movement 2', 0, 0, 'this is the note two', 'observation two'), - (3, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 0, 442, 'IN2003', 'Movement 3', 0, 0, 'this is the note three', 'observation three'), - (4, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 69, 'IN2004', 'Movement 4', 0, 0, 'this is the note four', 'observation four'), - (5, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 0, 442, 'IN2005', 'Movement 5', 0, 0, 'this is the note five', 'observation five'), - (6, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 6, 0, 442, 'IN2006', 'Movement 6', 0, 0, 'this is the note six', 'observation six'), - (7, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2007', 'Movement 7', 0, 0, 'this is the note seven', 'observation seven'), - (8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2008', 'Movement 8', 1, 1, '', ''); + (1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1, 442, 'IN2001', 'Movement 1', 0, 0, ''), + (2, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 442, 'IN2002', 'Movement 2', 0, 0, 'observation two'), + (3, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 0, 442, 'IN2003', 'Movement 3', 0, 0, 'observation three'), + (4, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 69, 'IN2004', 'Movement 4', 0, 0, 'observation four'), + (5, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 0, 442, 'IN2005', 'Movement 5', 0, 0, 'observation five'), + (6, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 6, 0, 442, 'IN2006', 'Movement 6', 0, 0, 'observation six'), + (7, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2007', 'Movement 7', 0, 0, 'observation seven'), + (8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2008', 'Movement 8', 1, 1, ''); INSERT INTO `bs`.`waste`(`buyer`, `year`, `week`, `family`, `itemFk`, `itemTypeFk`, `saleTotal`, `saleWaste`, `rate`) VALUES @@ -2769,10 +2770,23 @@ UPDATE `account`.`user` INSERT INTO `vn`.`ticketLog` (`originFk`, userFk, `action`, changedModel, oldInstance, newInstance, changedModelId, `description`) VALUES - (7, 18, 'update', 'Sale', '{"quantity":1}', '{"quantity":10}', 1, NULL), - (7, 18, 'update', 'Ticket', '{"quantity":1,"concept":"Chest ammo box"}', '{"quantity":10,"concept":"Chest ammo box"}', 1, NULL), - (7, 18, 'update', 'Sale', '{"price":3}', '{"price":5}', 1, NULL), - (7, 18, 'update', NULL, NULL, NULL, NULL, "Cambio cantidad Melee weapon heavy shield 1x0.5m de '5' a '10'"); + (7, 18, 'update', 'Sale', '{"quantity":1}', '{"quantity":10}', 1, NULL), + (7, 18, 'update', 'Ticket', '{"quantity":1,"concept":"Chest ammo box"}', '{"quantity":10,"concept":"Chest ammo box"}', 1, NULL), + (7, 18, 'update', 'Sale', '{"price":3}', '{"price":5}', 1, NULL), + (7, 18, 'update', NULL, NULL, NULL, NULL, "Cambio cantidad Melee weapon heavy shield 1x0.5m de '5' a '10'"); + +INSERT INTO `vn`.`ticketLog` (originFk, userFk, `action`, creationDate, changedModel, changedModelId, changedModelValue, oldInstance, newInstance, description) + VALUES + (1, NULL, 'delete', '2001-06-09 11:00:04', 'Ticket', 45, 'Spider Man' , NULL, NULL, NULL), + (1, 18, 'select', '2001-06-09 11:00:03', 'Ticket', 45, 'Spider Man' , NULL, NULL, NULL), + (1, NULL, 'update', '2001-05-09 10:00:02', 'Sale', 69854, 'Armor' , '{"isPicked": false}','{"isPicked": true}', NULL), + (1, 18, 'update', '2001-01-01 10:05:01', 'Sale', 69854, 'Armor' , NULL, NULL, 'Armor quantity changed from ''15'' to ''10'''), + (1, NULL, 'delete', '2001-01-01 10:00:10', 'Sale', 5689, 'Shield' , '{"quantity":10,"concept":"Shield"}', NULL, NULL), + (1, 18, 'insert', '2000-12-31 15:00:05', 'Sale', 69854, 'Armor' , NULL,'{"quantity":15,"concept":"Armor", "price": 345.99, "itemFk": 2}', NULL), + (1, 18, 'update', '2000-12-28 08:40:45', 'Ticket', 45, 'Spider Man' , '{"warehouseFk":60,"shipped":"2023-05-16T22:00:00.000Z","nickname":"Super Man","isSigned":true,"isLabeled":true,"isPrinted":true,"packages":0,"hour":0,"isBlocked":false,"hasPriority":false,"companyFk":442,"landed":"2023-05-17T22:00:00.000Z","isBoxed":true,"isDeleted":true,"zoneFk":713,"zonePrice":13,"zoneBonus":0}','{"warehouseFk":61,"shipped":"2023-05-17T22:00:00.000Z","nickname":"Spider Man","isSigned":false,"isLabeled":false,"isPrinted":false,"packages":1,"hour":0,"isBlocked":true,"hasPriority":true,"companyFk":443,"landed":"2023-05-18T22:00:00.000Z","isBoxed":false,"isDeleted":false,"zoneFk":713,"zonePrice":13,"zoneBonus":1}', NULL), + (1, 18, 'select', '2000-12-27 03:40:30', 'Ticket', 45, NULL , NULL, NULL, NULL), + (1, 18, 'insert', '2000-04-10 09:40:15', 'Sale', 5689, 'Shield' , NULL, '{"quantity":10,"concept":"Shield", "price": 10.5, "itemFk": 1}', NULL), + (1, 18, 'insert', '1999-05-09 10:00:00', 'Ticket', 45, 'Super Man' , NULL, '{"id":45,"clientFk":8608,"warehouseFk":60,"shipped":"2023-05-16T22:00:00.000Z","nickname":"Super Man","addressFk":48637,"isSigned":true,"isLabeled":true,"isPrinted":true,"packages":0,"hour":0,"created":"2023-05-16T11:42:56.000Z","isBlocked":false,"hasPriority":false,"companyFk":442,"agencyModeFk":639,"landed":"2023-05-17T22:00:00.000Z","isBoxed":true,"isDeleted":true,"zoneFk":713,"zonePrice":13,"zoneBonus":0}', NULL); INSERT INTO `vn`.`osTicketConfig` (`id`, `host`, `user`, `password`, `oldStatus`, `newStatusId`, `day`, `comment`, `hostDb`, `userDb`, `passwordDb`, `portDb`, `responseType`, `fromEmailId`, `replyTo`) VALUES @@ -2789,7 +2803,7 @@ INSERT INTO `vn`.`profileType` (`id`, `name`) INSERT INTO `salix`.`url` (`appName`, `environment`, `url`) VALUES - ('lilium', 'dev', 'http://localhost:8080/#/'), + ('lilium', 'dev', 'http://localhost:9000/#/'), ('salix', 'dev', 'http://localhost:5000/#!/'); INSERT INTO `vn`.`report` (`id`, `name`, `paperSizeFk`, `method`) @@ -2800,9 +2814,9 @@ INSERT INTO `vn`.`payDemDetail` (`id`, `detail`) VALUES (1, 1); -INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`) +INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`, `businessTypeFk`) VALUES - (1, NULL, 1); + (1, NULL, 1, 'worker'); INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`) VALUES diff --git a/db/dump/structure.sql b/db/dump/structure.sql index 089cb00ec..caac02d3d 100644 --- a/db/dump/structure.sql +++ b/db/dump/structure.sql @@ -42776,7 +42776,7 @@ CREATE DEFINER=`root`@`localhost` FUNCTION `hasAnyNegativeBase`() RETURNS tinyin BEGIN /* Calcula si existe alguna base imponible negativa -* Requiere la tabla temporal vn.ticketToInvoice(id) +* Requiere la tabla temporal tmp.ticketToInvoice(id) * * returns BOOLEAN */ @@ -42787,7 +42787,7 @@ BEGIN (KEY (ticketFk)) ENGINE = MEMORY SELECT id ticketFk - FROM ticketToInvoice; + FROM tmp.ticketToInvoice; CALL ticket_getTax(NULL); @@ -55223,7 +55223,7 @@ DELIMITER ;; CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceExpenceMake`(IN vInvoice INT) BEGIN /* Inserta las partidas de gasto correspondientes a la factura - * REQUIERE tabla ticketToInvoice + * REQUIERE tabla tmp.ticketToInvoice * @param vInvoice Numero de factura */ DELETE FROM invoiceOutExpence @@ -55233,7 +55233,7 @@ BEGIN SELECT vInvoice, expenceFk, SUM(ROUND(quantity * price * (100 - discount)/100,2)) amount - FROM ticketToInvoice t + FROM tmp.ticketToInvoice t JOIN sale s ON s.ticketFk = t.id JOIN item i ON i.id = s.itemFk GROUP BY i.expenceFk @@ -55243,7 +55243,7 @@ BEGIN SELECT vInvoice, tst.expenceFk, SUM(ROUND(ts.quantity * ts.price ,2)) amount - FROM ticketToInvoice t + FROM tmp.ticketToInvoice t JOIN ticketService ts ON ts.ticketFk = t.id JOIN ticketServiceType tst ON tst.id = ts.ticketServiceTypeFk HAVING amount != 0; @@ -55270,9 +55270,9 @@ BEGIN SET vMaxTicketDate = vn2008.DAYEND(vMaxTicketDate); - DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`; + DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`; - CREATE TEMPORARY TABLE `ticketToInvoice` + CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice` (PRIMARY KEY (`id`)) ENGINE = MEMORY SELECT Id_Ticket id FROM vn2008.Tickets WHERE (Fecha BETWEEN vMinDateTicket @@ -55305,8 +55305,8 @@ BEGIN SET vMinTicketDate = util.firstDayOfYear(vMaxTicketDate - INTERVAL 1 YEAR); SET vMaxTicketDate = util.dayend(vMaxTicketDate); - DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`; - CREATE TEMPORARY TABLE `ticketToInvoice` + DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`; + CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice` (PRIMARY KEY (`id`)) ENGINE = MEMORY SELECT id FROM ticket t @@ -55333,9 +55333,9 @@ DELIMITER ;; CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceFromTicket`(IN vTicket INT) BEGIN - DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`; + DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`; - CREATE TEMPORARY TABLE `ticketToInvoice` + CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice` (PRIMARY KEY (`id`)) ENGINE = MEMORY SELECT id FROM vn.ticket @@ -55931,9 +55931,9 @@ BEGIN JOIN invoiceOut io ON io.companyFk = s.id WHERE io.id = vInvoiceFk; - DROP TEMPORARY TABLE IF EXISTS ticketToInvoice; + DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice; - CREATE TEMPORARY TABLE ticketToInvoice + CREATE TEMPORARY TABLE tmp.ticketToInvoice SELECT id FROM ticket WHERE refFk = vInvoiceRef; @@ -56408,9 +56408,9 @@ BEGIN JOIN client c ON c.id = io.clientFk WHERE io.id = vInvoice; - DROP TEMPORARY TABLE IF EXISTS ticketToInvoice; + DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice; - CREATE TEMPORARY TABLE ticketToInvoice + CREATE TEMPORARY TABLE tmp.ticketToInvoice SELECT id FROM ticket WHERE refFk = vInvoiceRef; @@ -56456,7 +56456,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceOut_exportationFromClient`( vCompanyFk INT) BEGIN /** - * Genera tabla temporal ticketToInvoice necesaría para el proceso de facturación + * Genera tabla temporal tmp.ticketToInvoice necesaría para el proceso de facturación * Los abonos quedan excluidos en las exportaciones * * @param vMaxTicketDate Fecha hasta la cual cogerá tickets para facturar @@ -56467,8 +56467,8 @@ BEGIN SET vMinTicketDate = util.firstDayOfYear(vMaxTicketDate - INTERVAL 1 YEAR); SET vMaxTicketDate = util.dayend(vMaxTicketDate); - DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`; - CREATE TEMPORARY TABLE `ticketToInvoice` + DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`; + CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice` (PRIMARY KEY (`id`)) ENGINE = MEMORY SELECT t.id @@ -56503,7 +56503,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceOut_new`( BEGIN /** * Creación de facturas emitidas. - * requiere previamente tabla ticketToInvoice(id). + * requiere previamente tabla tmp.ticketToInvoice(id). * * @param vSerial serie a la cual se hace la factura * @param vInvoiceDate fecha de la factura @@ -56531,13 +56531,13 @@ BEGIN SELECT t.clientFk, t.companyFk INTO vClientFk, vCompanyFk - FROM ticketToInvoice tt + FROM tmp.ticketToInvoice tt JOIN ticket t ON t.id = tt.id LIMIT 1; - -- Eliminem de ticketToInvoice els tickets que no han de ser facturats + -- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats DELETE ti.* - FROM ticketToInvoice ti + FROM tmp.ticketToInvoice ti JOIN ticket t ON t.id = ti.id JOIN sale s ON s.ticketFk = t.id JOIN item i ON i.id = s.itemFk @@ -56552,7 +56552,7 @@ BEGIN SELECT SUM(s.quantity * s.price * (100 - s.discount)/100), ts.id INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice - FROM ticketToInvoice t + FROM tmp.ticketToInvoice t LEFT JOIN sale s ON s.ticketFk = t.id LEFT JOIN ticketService ts ON ts.ticketFk = t.id; @@ -56593,13 +56593,13 @@ BEGIN WHERE id = vNewInvoiceId; UPDATE ticket t - JOIN ticketToInvoice ti ON ti.id = t.id + JOIN tmp.ticketToInvoice ti ON ti.id = t.id SET t.refFk = vNewRef; DROP TEMPORARY TABLE IF EXISTS tmp.updateInter; CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador - FROM ticketToInvoice ti + FROM tmp.ticketToInvoice ti LEFT JOIN ticketState ts ON ti.id = ts.ticket JOIN state s WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id); @@ -56609,7 +56609,7 @@ BEGIN INSERT INTO ticketLog (action, userFk, originFk, description) SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef) - FROM ticketToInvoice ti; + FROM tmp.ticketToInvoice ti; CALL invoiceExpenceMake(vNewInvoiceId); CALL invoiceTaxMake(vNewInvoiceId,vTaxArea); @@ -56647,7 +56647,7 @@ BEGIN (KEY (ticketFk)) ENGINE = MEMORY SELECT id ticketFk - FROM ticketToInvoice; + FROM tmp.ticketToInvoice; CALL `ticket_getTax`('NATIONAL'); @@ -56725,7 +56725,7 @@ BEGIN DROP TEMPORARY TABLE tmp.ticketServiceTax; END IF; END IF; - DROP TEMPORARY TABLE `ticketToInvoice`; + DROP TEMPORARY TABLE `tmp`.`ticketToInvoice`; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -56876,7 +56876,7 @@ BEGIN (KEY (ticketFk)) ENGINE = MEMORY SELECT id ticketFk - FROM ticketToInvoice; + FROM tmp.ticketToInvoice; CALL ticket_getTax(vTaxArea); @@ -68751,7 +68751,7 @@ DELIMITER ; /*!50003 SET character_set_client = @saved_cs_client */ ; /*!50003 SET character_set_results = @saved_cs_results */ ; /*!50003 SET collation_connection = @saved_col_connection */ ; -/*!50003 DROP PROCEDURE IF EXISTS `ticketToInvoiceByAddress` */; +/*!50003 DROP PROCEDURE IF EXISTS `tmp`.`ticketToInvoiceByAddress` */; /*!50003 SET @saved_cs_client = @@character_set_client */ ; /*!50003 SET @saved_cs_results = @@character_set_results */ ; /*!50003 SET @saved_col_connection = @@collation_connection */ ; @@ -68771,9 +68771,9 @@ BEGIN SET vEnded = util.dayEnd(vEnded); - DROP TEMPORARY TABLE IF EXISTS vn.ticketToInvoice; + DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice; - CREATE TEMPORARY TABLE vn.ticketToInvoice + CREATE TEMPORARY TABLE tmp.ticketToInvoice SELECT id FROM vn.ticket WHERE addressFk = vAddress @@ -68807,9 +68807,9 @@ BEGIN SET vEnded = util.dayEnd(vEnded); - DROP TEMPORARY TABLE IF EXISTS vn.ticketToInvoice; + DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice; - CREATE TEMPORARY TABLE vn.ticketToInvoice + CREATE TEMPORARY TABLE tmp.ticketToInvoice SELECT id FROM vn.ticket WHERE clientFk = vClient @@ -68870,9 +68870,9 @@ BEGIN JOIN vn.client c ON c.id = io.clientFk WHERE io.id = vInvoice; - DROP TEMPORARY TABLE IF EXISTS vn.ticketToInvoice; + DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice; - CREATE TEMPORARY TABLE vn.ticketToInvoice + CREATE TEMPORARY TABLE tmp.ticketToInvoice SELECT id FROM vn.ticket WHERE refFk = vInvoiceRef; diff --git a/db/export-data.sh b/db/export-data.sh index bdf8049e0..11358e64c 100755 --- a/db/export-data.sh +++ b/db/export-data.sh @@ -68,6 +68,7 @@ TABLES=( time volumeConfig workCenter + companyI18n ) dump_tables ${TABLES[@]} diff --git a/e2e/helpers/extensions.js b/e2e/helpers/extensions.js index 7d80c69ee..fe3ef08bd 100644 --- a/e2e/helpers/extensions.js +++ b/e2e/helpers/extensions.js @@ -156,14 +156,14 @@ let actions = { await this.waitForSpinnerLoad(); }, - accessToSection: async function(state) { + accessToSection: async function(state, name = 'Others') { await this.waitForSelector('vn-left-menu'); let nested = await this.evaluate(state => { return document.querySelector(`vn-left-menu li li > a[ui-sref="${state}"]`) != null; }, state); if (nested) { - let selector = 'vn-left-menu vn-item-section > vn-icon[icon=keyboard_arrow_down]'; + let selector = `vn-left-menu li[name="${name}"]`; await this.evaluate(selector => { document.querySelector(selector).scrollIntoViewIfNeeded(); }, selector); @@ -414,7 +414,7 @@ let actions = { const selector = 'vn-snackbar .shape.shown'; await this.waitForSelector(selector); - let message = await this.evaluate(selector => { + const message = await this.evaluate(selector => { const shape = document.querySelector(selector); const message = { text: shape.querySelector('.text').innerText @@ -431,6 +431,8 @@ let actions = { return message; }, selector); + message.isSuccess = message.type == 'success'; + await this.hideSnackbar(); return message; }, @@ -466,28 +468,6 @@ let actions = { }, selector); }, - clearInput: async function(selector) { - await this.waitForSelector(selector); - - let field = await this.evaluate(selector => { - return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field; - }, selector); - - if ((field != null && field != '') || field == '0') { - let coords = await this.evaluate(selector => { - let rect = document.querySelector(selector).getBoundingClientRect(); - return {x: rect.x + (rect.width / 2), y: rect.y + (rect.height / 2), width: rect.width}; - }, selector); - await this.mouse.move(coords.x, coords.y); - await this.waitForSelector(`${selector} [icon="clear"]`, {visible: true}); - await this.waitToClick(`${selector} [icon="clear"]`); - } - - await this.evaluate(selector => { - return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field == ''; - }, selector); - }, - autocompleteSearch: async function(selector, searchValue) { let builtSelector = await this.selectorFormater(selector); @@ -519,17 +499,15 @@ let actions = { checkboxState: async function(selector) { await this.waitForSelector(selector); - return this.evaluate(selector => { - let checkbox = document.querySelector(selector); - switch (checkbox.$ctrl.field) { - case null: - return 'intermediate'; - case true: - return 'checked'; - default: - return 'unchecked'; - } - }, selector); + const value = await this.getInputValue(selector); + switch (value) { + case null: + return 'intermediate'; + case true: + return 'checked'; + default: + return 'unchecked'; + } }, isDisabled: async function(selector) { @@ -622,6 +600,138 @@ let actions = { waitForContentLoaded: async function() { await this.waitForSpinnerLoad(); + }, + + async getInputValue(selector) { + return this.evaluate(selector => { + const input = document.querySelector(selector); + return input.$ctrl.field; + }, selector); + }, + + async getValue(selector) { + return await this.waitToGetProperty(selector, 'value'); + }, + + async innerText(selector) { + const element = await this.$(selector); + const handle = await element.getProperty('innerText'); + return handle.jsonValue(); + }, + + async setInput(selector, value) { + const input = await this.$(selector); + const tagName = (await input.evaluate(e => e.tagName)).toLowerCase(); + + switch (tagName) { + case 'vn-textfield': + case 'vn-datalist': + case 'vn-input-number': + await this.clearInput(selector); + if (value) + await this.write(selector, value.toString()); + break; + case 'vn-autocomplete': + if (value) + await this.autocompleteSearch(selector, value.toString()); + else + await this.clearInput(selector); + break; + case 'vn-date-picker': + if (value) + await this.pickDate(selector, value); + else + await this.clearInput(selector); + break; + case 'vn-input-time': + if (value) + await this.pickTime(selector, value); + else + await this.clearInput(selector); + break; + case 'vn-check': + for (let i = 0; i < 3; i++) { + if (await this.getInput(selector) == value) break; + await this.click(selector); + } + break; + } + }, + + async getInput(selector) { + const input = await this.$(selector); + const tagName = (await input.evaluate(e => e.tagName)).toLowerCase(); + let el; + let value; + + switch (tagName) { + case 'vn-textfield': + case 'vn-autocomplete': + case 'vn-input-time': + case 'vn-datalist': + el = await input.$('input'); + value = await el.getProperty('value'); + return value.jsonValue(); + case 'vn-check': + case 'vn-input-number': + return await this.getInputValue(selector); + case 'vn-textarea': + el = await input.$('textarea'); + value = await el.getProperty('value'); + return value.jsonValue(); + case 'vn-date-picker': + el = await input.$('input'); + value = await el.getProperty('value'); + if (value) { + const date = new Date(await value.jsonValue()); + date.setUTCHours(0, 0, 0, 0); + return date; + } else + return null; + default: + value = await this.innerText(selector); + return value.jsonValue(); + } + }, + + async clearInput(selector) { + await this.waitForSelector(selector); + + let field = await this.evaluate(selector => { + return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field; + }, selector); + + if ((field != null && field != '') || field == '0') { + let coords = await this.evaluate(selector => { + let rect = document.querySelector(selector).getBoundingClientRect(); + return {x: rect.x + (rect.width / 2), y: rect.y + (rect.height / 2), width: rect.width}; + }, selector); + await this.mouse.move(coords.x, coords.y); + await this.waitForSelector(`${selector} [icon="clear"]`, {visible: true}); + await this.waitToClick(`${selector} [icon="clear"]`); + } + + await this.evaluate(selector => { + return document.querySelector(`${selector} input`).closest('.vn-field').$ctrl.field == ''; + }, selector); + }, + + async fetchForm(selector, inputNames) { + const values = {}; + for (const inputName of inputNames) + values[inputName] = await this.getInput(`${selector} [vn-name="${inputName}"]`); + return values; + }, + + async fillForm(selector, values) { + for (const inputName in values) + await this.setInput(`${selector} [vn-name="${inputName}"]`, values[inputName]); + }, + + async sendForm(selector, values) { + if (values) await this.fillForm(selector, values); + await this.click(`${selector} button[type=submit]`); + return await this.waitForSnackbar(); } }; @@ -629,12 +739,14 @@ export function extendPage(page) { for (let name in actions) { page[name] = async(...args) => { try { - return actions[name].apply(page, args); + return await actions[name].apply(page, args); } catch (err) { let stringArgs = args - .map(i => typeof i == 'function' ? 'Function' : i) + .map(i => typeof i == 'function' ? 'Function' : `'${i}'`) .join(', '); - throw new Error(`.${name}(${stringArgs}): ${err.message}`); + const myErr = new Error(`${err.message}\n at Page.${name}(${stringArgs})`); + myErr.stack = err.stack; + throw myErr; } }; } diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 84db638e3..b19db24d7 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -193,10 +193,6 @@ export default { saveNewPoscode: '#savePostcode', createButton: 'vn-client-create button[type=submit]' }, - clientDescriptor: { - moreMenu: 'vn-client-descriptor vn-icon-button[icon=more_vert]', - simpleTicketButton: '.vn-menu [name="simpleTicket"]' - }, clientBasicData: { name: 'vn-client-basic-data vn-textfield[ng-model="$ctrl.client.name"]', contact: 'vn-client-basic-data vn-textfield[ng-model="$ctrl.client.contact"]', @@ -231,23 +227,6 @@ export default { saveButton: 'button[type=submit]', watcher: 'vn-client-fiscal-data vn-watcher' }, - clientBillingData: { - payMethod: 'vn-client-billing-data vn-autocomplete[ng-model="$ctrl.client.payMethodFk"]', - IBAN: 'vn-client-billing-data vn-textfield[ng-model="$ctrl.client.iban"]', - dueDay: 'vn-client-billing-data vn-input-number[ng-model="$ctrl.client.dueDay"]', - receivedCoreLCRCheckbox: 'vn-client-billing-data vn-check[label="Received LCR"]', - receivedCoreVNLCheckbox: 'vn-client-billing-data vn-check[label="Received core VNL"]', - receivedB2BVNLCheckbox: 'vn-client-billing-data vn-check[label="Received B2B VNL"]', - swiftBic: 'vn-client-billing-data vn-autocomplete[ng-model="$ctrl.client.bankEntityFk"]', - newBankEntityButton: 'vn-client-billing-data vn-icon-button[vn-tooltip="New bank entity"] > button', - newBankEntityName: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.data.name"]', - newBankEntityBIC: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.data.bic"]', - newBankEntityCountry: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.data.countryFk"]', - newBankEntityCode: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.data.id"]', - acceptBankEntityButton: '.vn-dialog.shown button[response="accept"]', - saveButton: 'vn-client-billing-data button[type=submit]', - watcher: 'vn-client-billing-data vn-watcher' - }, clientAddresses: { addressesButton: 'vn-left-menu a[ui-sref="client.card.address.index"]', createAddress: 'vn-client-address-index vn-float-button', @@ -283,12 +262,6 @@ export default { cancelEditAddressButton: 'vn-client-address-edit > form > vn-button-bar > vn-button > button', watcher: 'vn-client-address-edit vn-watcher' }, - clientWebAccess: { - enableWebAccessCheckbox: 'vn-check[label="Enable web access"]', - userName: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.name"]', - email: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.email"]', - saveButton: 'button[type=submit]' - }, clientNotes: { addNoteFloatButton: 'vn-float-button', note: 'vn-textarea[ng-model="$ctrl.note.text"]', @@ -312,30 +285,6 @@ export default { clientMandate: { firstMandateText: 'vn-client-mandate vn-card vn-table vn-tbody > vn-tr' }, - clientLog: { - lastModificationPreviousValue: 'vn-client-log vn-tr table tr td.before', - lastModificationCurrentValue: 'vn-client-log vn-tr table tr td.after', - namePreviousValue: 'vn-client-log vn-tr table tr:nth-child(1) td.before', - nameCurrentValue: 'vn-client-log vn-tr table tr:nth-child(1) td.after', - activePreviousValue: 'vn-client-log vn-tr:nth-child(2) table tr:nth-child(2) td.before', - activeCurrentValue: 'vn-client-log vn-tr:nth-child(2) table tr:nth-child(2) td.after' - - }, - clientBalance: { - company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]', - newPaymentButton: `vn-float-button`, - newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.bankFk"]', - newPaymentAmount: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.amountPaid"]', - newDescription: 'vn-textfield[ng-model="$ctrl.receipt.description"]', - deliveredAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.deliveredAmount"]', - refundAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.amountToReturn"]', - saveButton: '.vn-dialog.shown [response="accept"]', - anyBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr', - firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)', - firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable', - firstLineReferenceInput: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable > div > field > vn-textfield', - compensationButton: 'vn-client-balance-index vn-icon-button[vn-dialog="send_compensation"]' - }, webPayment: { confirmFirstPaymentButton: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon-button[icon="done_all"]', firstPaymentConfirmed: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon[icon="check"]' @@ -414,7 +363,7 @@ export default { saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button' }, itemFixedPrice: { - add: 'vn-fixed-price vn-icon-button[icon="add_circle"]', + add: 'vn-fixed-price vn-icon-button[vn-tooltip="Add fixed price"]', firstItemID: 'vn-fixed-price tr:nth-child(2) vn-autocomplete[ng-model="price.itemFk"]', fourthFixedPrice: 'vn-fixed-price tr:nth-child(5)', fourthItemID: 'vn-fixed-price tr:nth-child(5) vn-autocomplete[ng-model="price.itemFk"]', @@ -427,7 +376,18 @@ export default { fourthEnded: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.ended"]', fourthDeleteIcon: 'vn-fixed-price tr:nth-child(5) > td:nth-child(9) > vn-icon-button[icon="delete"]', orderColumnId: 'vn-fixed-price th[field="itemFk"]', - removeWarehouseFilter: 'vn-searchbar > form > vn-textfield > div.container > div.prepend > prepend > div > span:nth-child(1) > vn-icon > i' + removeWarehouseFilter: 'vn-searchbar > form > vn-textfield > div.container > div.prepend > prepend > div > span:nth-child(1) > vn-icon > i', + generalSearchFilter: 'vn-fixed-price-search-panel vn-textfield[ng-model="$ctrl.filter.search"]', + reignFilter: 'vn-fixed-price-search-panel vn-horizontal.item-category vn-one', + typeFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.typeFk"]', + buyerFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.buyerFk"]', + warehouseFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.warehouseFk"]', + mineFilter: 'vn-fixed-price-search-panel vn-check[ng-model="$ctrl.filter.mine"]', + hasMinPriceFilter: 'vn-fixed-price-search-panel vn-check[ng-model="$ctrl.filter.hasMinPrice"]', + addTag: 'vn-fixed-price-search-panel vn-icon-button[icon="add_circle"]', + tagFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="itemTag.tagFk"]', + tagValueFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="itemTag.value"]', + chip: 'vn-fixed-price-search-panel vn-chip > vn-icon' }, itemCreateView: { temporalName: 'vn-item-create vn-textfield[ng-model="$ctrl.item.provisionalName"]', @@ -470,10 +430,6 @@ export default { packingOut: 'vn-input-number[ng-model="$ctrl.item.packingOut"]', isActiveCheckbox: 'vn-check[label="Active"]', priceInKgCheckbox: 'vn-check[label="Price in kg"]', - newIntrastatButton: 'vn-item-basic-data vn-icon-button[vn-tooltip="New intrastat"] > button', - newIntrastatId: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.newIntrastat.intrastatId"]', - newIntrastatDescription: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newIntrastat.description"]', - acceptIntrastatButton: '.vn-dialog.shown button[response="accept"]', submitBasicDataButton: `button[type=submit]` }, itemTags: { @@ -626,13 +582,6 @@ export default { saveButton: '.vn-dialog.shown [response="accept"]', expeditionRow: 'vn-ticket-expedition vn-table vn-tbody > vn-tr' }, - ticketPackages: { - firstPackage: 'vn-autocomplete[label="Package"]', - firstQuantity: 'vn-ticket-package vn-horizontal:nth-child(1) vn-input-number[ng-model="package.quantity"]', - firstRemovePackageButton: 'vn-icon-button[vn-tooltip="Remove package"]', - addPackageButton: 'vn-icon-button[vn-tooltip="Add package"]', - savePackagesButton: `button[type=submit]` - }, ticketSales: { setOk: 'vn-ticket-sale vn-tool-bar > vn-button[label="Ok"] > button', saleLine: 'vn-table div > vn-tbody > vn-tr vn-check', @@ -744,6 +693,7 @@ export default { anyDocument: 'vn-ticket-dms-index > vn-data-viewer vn-tbody vn-tr' }, ticketFuture: { + searchResult: 'vn-ticket-future tbody tr', openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]', originDated: 'vn-date-picker[label="Origin date"]', futureDated: 'vn-date-picker[label="Destination date"]', @@ -759,7 +709,6 @@ export default { problems: 'vn-check[label="With problems"]', tableButtonSearch: 'vn-button[vn-tooltip="Search"]', moveButton: 'vn-button[vn-tooltip="Future tickets"]', - acceptButton: '.vn-confirm.shown button[response="accept"]', firstCheck: 'tbody > tr:nth-child(1) > td > vn-check', multiCheck: 'vn-multi-check', tableId: 'vn-textfield[name="id"]', @@ -877,15 +826,6 @@ export default { landedDatePicker: 'vn-date-picker[label="Landed"]', createButton: 'button[type=submit]' }, - orderSummary: { - id: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(1) span', - alias: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(2) span', - consignee: 'vn-order-summary vn-one:nth-child(2) > vn-label-value:nth-child(6) span', - subtotal: 'vn-order-summary vn-one.taxes > p:nth-child(1)', - vat: 'vn-order-summary vn-one.taxes > p:nth-child(2)', - total: 'vn-order-summary vn-one.taxes > p:nth-child(3)', - sale: 'vn-order-summary vn-tbody > vn-tr', - }, orderCatalog: { plantRealmButton: 'vn-order-catalog > vn-side-menu vn-icon[icon="icon-plant"]', type: 'vn-order-catalog vn-autocomplete[data="$ctrl.itemTypes"]', @@ -903,14 +843,6 @@ export default { fifthFilterRemoveButton: 'vn-order-catalog > vn-side-menu .chips > vn-chip:nth-child(5) vn-icon[icon=cancel]', sixthFilterRemoveButton: 'vn-order-catalog > vn-side-menu .chips > vn-chip:nth-child(6) vn-icon[icon=cancel]', }, - orderBasicData: { - client: 'vn-autocomplete[label="Client"]', - address: 'vn-autocomplete[label="Address"]', - agency: 'vn-autocomplete[label="Agency"]', - observation: 'vn-textarea[label="Notes"]', - saveButton: `button[type=submit]`, - acceptButton: '.vn-confirm.shown button[response="accept"]' - }, orderLine: { orderSubtotal: 'vn-order-line .header :first-child', firstLineDeleteButton: 'vn-order-line vn-tbody > vn-tr:nth-child(1) vn-icon[icon="delete"]', @@ -950,16 +882,6 @@ export default { goToRouteSummaryButton: 'vn-route-summary > vn-card > h5 > a', }, - routeBasicData: { - worker: 'vn-route-basic-data vn-autocomplete[ng-model="$ctrl.route.workerFk"]', - vehicle: 'vn-route-basic-data vn-autocomplete[ng-model="$ctrl.route.vehicleFk"]', - kmStart: 'vn-route-basic-data vn-input-number[ng-model="$ctrl.route.kmStart"]', - kmEnd: 'vn-route-basic-data vn-input-number[ng-model="$ctrl.route.kmEnd"]', - createdDate: 'vn-route-basic-data vn-date-picker[ng-model="$ctrl.route.created"]', - startedHour: 'vn-route-basic-data vn-input-time[ng-model="$ctrl.route.started"]', - finishedHour: 'vn-route-basic-data vn-input-time[ng-model="$ctrl.route.finished"]', - saveButton: 'vn-route-basic-data button[type=submit]' - }, routeTickets: { firstTicketPriority: 'vn-route-tickets vn-tr:nth-child(1) vn-input-number[ng-model="ticket.priority"]', firstTicketCheckbox: 'vn-route-tickets vn-tr:nth-child(1) vn-check', @@ -989,9 +911,9 @@ export default { saveButton: 'vn-worker-basic-data button[type=submit]' }, workerNotes: { - addNoteFloatButton: 'vn-worker-note vn-float-button', - note: 'vn-textarea[ng-model="$ctrl.note.text"]', - saveButton: 'button[type=submit]', + addNoteFloatButton: 'vn-worker-note vn-icon[icon="add"]', + note: 'vn-note-worker-create vn-textarea[ng-model="$ctrl.note.text"]', + saveButton: 'vn-note-worker-create button[type=submit]', firstNoteText: 'vn-worker-note .text' }, workerPbx: { @@ -1244,22 +1166,6 @@ export default { confirmed: 'vn-entry-summary vn-check[label="Confirmed"]', anyBuyLine: 'vn-entry-summary tr.dark-row' }, - entryBasicData: { - reference: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.reference"]', - invoiceNumber: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.invoiceNumber"]', - notes: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.notes"]', - observations: 'vn-entry-basic-data vn-textarea[ng-model="$ctrl.entry.observation"]', - supplier: 'vn-entry-basic-data vn-autocomplete[ng-model="$ctrl.entry.supplierFk"]', - currency: 'vn-entry-basic-data vn-autocomplete[ng-model="$ctrl.entry.currencyFk"]', - commission: 'vn-entry-basic-data vn-input-number[ng-model="$ctrl.entry.commission"]', - company: 'vn-entry-basic-data vn-autocomplete[ng-model="$ctrl.entry.companyFk"]', - ordered: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isOrdered"]', - confirmed: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isConfirmed"]', - inventory: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isExcludedFromAvailable"]', - raid: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isRaid"]', - booked: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isBooked"]', - save: 'vn-entry-basic-data button[type=submit]', - }, entryDescriptor: { agency: 'vn-entry-descriptor div.body vn-label-value:nth-child(1) span', travelsQuicklink: 'vn-entry-descriptor vn-quick-link[icon="local_airport"] > a', @@ -1350,18 +1256,6 @@ export default { notes: 'vn-supplier-basic-data vn-textarea[ng-model="$ctrl.supplier.note"]', saveButton: 'vn-supplier-basic-data button[type="submit"]', }, - supplierFiscalData: { - socialName: 'vn-supplier-fiscal-data vn-textfield[ng-model="$ctrl.supplier.name"]', - taxNumber: 'vn-supplier-fiscal-data vn-textfield[ng-model="$ctrl.supplier.nif"]', - account: 'vn-supplier-fiscal-data vn-textfield[ng-model="$ctrl.supplier.account"]', - sageTaxType: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.sageTaxTypeFk"]', - sageWihholding: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.sageWithholdingFk"]', - postCode: 'vn-supplier-fiscal-data vn-datalist[ng-model="$ctrl.supplier.postCode"]', - city: 'vn-supplier-fiscal-data vn-datalist[ng-model="$ctrl.supplier.city"]', - province: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.provinceFk"]', - country: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.countryFk"]', - saveButton: 'vn-supplier-fiscal-data button[type="submit"]', - }, supplierBillingData: { payMethod: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payMethodFk"]', payDem: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payDemFk"]', diff --git a/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js b/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js index a3d747f1c..c4f091d1f 100644 --- a/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js +++ b/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js @@ -15,91 +15,55 @@ describe('SmartTable SearchBar integration', () => { await browser.close(); }); - describe('as filters in smart-table section', () => { - it('should search by type in searchBar', async() => { - await page.waitToClick(selectors.itemsIndex.openAdvancedSearchButton); - await page.autocompleteSearch(selectors.itemsIndex.advancedSearchItemType, 'Anthurium'); - await page.waitToClick(selectors.itemsIndex.advancedSearchButton); - await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 3); + it('should search by type in searchBar, reload page and have same results', async() => { + await page.waitToClick(selectors.itemsIndex.openAdvancedSearchButton); + await page.autocompleteSearch(selectors.itemsIndex.advancedSearchItemType, 'Anthurium'); + await page.waitToClick(selectors.itemsIndex.advancedSearchButton); + await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 3); + + await page.reload({ + waitUntil: 'networkidle2' }); - it('should reload page and have same results', async() => { - await page.reload({ - waitUntil: 'networkidle2' - }); + await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 3); - await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 3); + await page.waitToClick(selectors.itemsIndex.advancedSmartTableButton); + await page.write(selectors.itemsIndex.advancedSmartTableGrouping, '1'); + await page.keyboard.press('Enter'); + await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2); + + await page.reload({ + waitUntil: 'networkidle2' }); - it('should search by grouping in smartTable', async() => { - await page.waitToClick(selectors.itemsIndex.advancedSmartTableButton); - await page.write(selectors.itemsIndex.advancedSmartTableGrouping, '1'); - await page.keyboard.press('Enter'); - await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2); - }); - - it('should now reload page and have same results', async() => { - await page.reload({ - waitUntil: 'networkidle2' - }); - - await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2); - }); + await page.waitForNumberOfElements(selectors.itemsIndex.searchResult, 2); }); - describe('as filters in section without smart-table', () => { - it('go to zone section', async() => { - await page.loginAndModule('salesPerson', 'zone'); - await page.waitToClick(selectors.globalItems.searchButton); - }); + it('should filter in section without smart-table and search in searchBar go to zone section', async() => { + await page.loginAndModule('salesPerson', 'zone'); + await page.waitToClick(selectors.globalItems.searchButton); - it('should search in searchBar first time', async() => { - await page.doSearch('A'); - const count = await page.countElement(selectors.zoneIndex.searchResult); + await page.doSearch('A'); + const firstCount = await page.countElement(selectors.zoneIndex.searchResult); - expect(count).toEqual(7); - }); + await page.doSearch('A'); + const secondCount = await page.countElement(selectors.zoneIndex.searchResult); - it('should search in searchBar second time', async() => { - await page.doSearch('A'); - const count = await page.countElement(selectors.zoneIndex.searchResult); - - expect(count).toEqual(7); - }); - - it('should search in searchBar third time', async() => { - await page.doSearch('A'); - const count = await page.countElement(selectors.zoneIndex.searchResult); - - expect(count).toEqual(7); - }); + expect(firstCount).toEqual(7); + expect(secondCount).toEqual(7); }); - describe('as orders', () => { - it('should order by first id', async() => { - await page.loginAndModule('developer', 'item'); - await page.accessToSection('item.fixedPrice'); - await page.doSearch(); + it('should order orders by first id and order by last id, reload page and have same order', async() => { + await page.loginAndModule('developer', 'item'); + await page.accessToSection('item.fixedPrice'); + await page.keyboard.press('Enter'); - const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value'); + await page.waitForTextInField(selectors.itemFixedPrice.firstItemID, '1'); - expect(result).toEqual('1'); - }); - - it('should order by last id', async() => { - await page.waitToClick(selectors.itemFixedPrice.orderColumnId); - const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value'); - - expect(result).toEqual('3'); - }); - - it('should reload page and have same order', async() => { - await page.reload({ - waitUntil: 'networkidle2' - }); - const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value'); - - expect(result).toEqual('3'); + await page.waitToClick(selectors.itemFixedPrice.orderColumnId); + await page.reload({ + waitUntil: 'networkidle2' }); + await page.waitForTextInField(selectors.itemFixedPrice.firstItemID, '13'); }); }); diff --git a/e2e/paths/02-client/03_edit_fiscal_data.spec.js b/e2e/paths/02-client/03_edit_fiscal_data.spec.js index 2a56cb535..0babb5396 100644 --- a/e2e/paths/02-client/03_edit_fiscal_data.spec.js +++ b/e2e/paths/02-client/03_edit_fiscal_data.spec.js @@ -171,100 +171,40 @@ describe('Client Edit fiscalData path', () => { expect(result).toEqual('SMASH'); }); - it('should confirm the fiscal id have been edited', async() => { - const result = await page.waitToGetProperty(selectors.clientFiscalData.fiscalId, 'value'); + it('should confirm the fiscal data have been edited', async() => { + const fiscalId = await page.waitToGetProperty(selectors.clientFiscalData.fiscalId, 'value'); + const address = await page.waitToGetProperty(selectors.clientFiscalData.address, 'value'); + const postcode = await page.waitToGetProperty(selectors.clientFiscalData.postcode, 'value'); + const sageTax = await page.waitToGetProperty(selectors.clientFiscalData.sageTax, 'value'); + const sageTransaction = await page.waitToGetProperty(selectors.clientFiscalData.sageTransaction, 'value'); + const city = await page.waitToGetProperty(selectors.clientFiscalData.city, 'value'); + const province = await page.waitToGetProperty(selectors.clientFiscalData.province, 'value'); + const country = await page.waitToGetProperty(selectors.clientFiscalData.country, 'value'); + const active = await page.checkboxState(selectors.clientFiscalData.activeCheckbox); + const frozen = await page.checkboxState(selectors.clientFiscalData.frozenCheckbox); + const hasToInvoice = await page.checkboxState(selectors.clientFiscalData.hasToInvoiceCheckbox); + const vies = await page.checkboxState(selectors.clientFiscalData.viesCheckbox); + const notifyByMail = await page.checkboxState(selectors.clientFiscalData.notifyByMailCheckbox); + const invoiceByAddress = await page.checkboxState(selectors.clientFiscalData.invoiceByAddressCheckbox); + const equalizationTax = await page.checkboxState(selectors.clientFiscalData.equalizationTaxCheckbox); + const verifiedData = await page.checkboxState(selectors.clientFiscalData.verifiedDataCheckbox); - expect(result).toEqual('94980061C'); - }); - - it('should confirm the address have been edited', async() => { - const result = await page.waitToGetProperty(selectors.clientFiscalData.address, 'value'); - - expect(result).toEqual('Somewhere edited'); - }); - - it('should confirm the postcode have been edited', async() => { - const result = await page.waitToGetProperty(selectors.clientFiscalData.postcode, 'value'); - - expect(result).toContain('46000'); - }); - - it('should confirm the sageTax have been edited', async() => { - const result = await page.waitToGetProperty(selectors.clientFiscalData.sageTax, 'value'); - - expect(result).toEqual('Operaciones no sujetas'); - }); - - it('should confirm the sageTransaction have been edited', async() => { - const result = await page.waitToGetProperty(selectors.clientFiscalData.sageTransaction, 'value'); - - expect(result).toEqual('36: Regularización de inversiones'); - }); - - it('should confirm the city have been autocompleted', async() => { - const result = await page.waitToGetProperty(selectors.clientFiscalData.city, 'value'); - - expect(result).toEqual('Valencia'); - }); - - it(`should confirm the province have been autocompleted`, async() => { - const result = await page.waitToGetProperty(selectors.clientFiscalData.province, 'value'); - - expect(result).toContain('Province one'); - }); - - it('should confirm the country have been autocompleted', async() => { - const result = await page.waitToGetProperty(selectors.clientFiscalData.country, 'value'); - - expect(result).toEqual('España'); - }); - - it('should confirm active checkbox is unchecked', async() => { - const result = await page.checkboxState(selectors.clientFiscalData.activeCheckbox); - - expect(result).toBe('unchecked'); - }); - - it('should confirm frozen checkbox is checked', async() => { - const result = await page.checkboxState(selectors.clientFiscalData.frozenCheckbox); - - expect(result).toBe('checked'); - }); - - it('should confirm Has to invoice checkbox is unchecked', async() => { - const result = await page.checkboxState(selectors.clientFiscalData.hasToInvoiceCheckbox); - - expect(result).toBe('unchecked'); - }); - - it('should confirm Vies checkbox is checked', async() => { - const result = await page.checkboxState(selectors.clientFiscalData.viesCheckbox); - - expect(result).toBe('checked'); - }); - - it('should confirm Notify by email checkbox is unchecked', async() => { - const result = await page.checkboxState(selectors.clientFiscalData.notifyByMailCheckbox); - - expect(result).toBe('unchecked'); - }); - - it('should confirm invoice by address checkbox is checked', async() => { - const result = await page.checkboxState(selectors.clientFiscalData.invoiceByAddressCheckbox); - - expect(result).toBe('checked'); - }); - - it('should confirm Equalization tax checkbox is unchecked', async() => { - const result = await page.checkboxState(selectors.clientFiscalData.equalizationTaxCheckbox); - - expect(result).toBe('unchecked'); - }); - - it('should confirm Verified data checkbox is checked', async() => { - const result = await page.checkboxState(selectors.clientFiscalData.verifiedDataCheckbox); - - expect(result).toBe('checked'); + expect(fiscalId).toEqual('94980061C'); + expect(address).toEqual('Somewhere edited'); + expect(postcode).toContain('46000'); + expect(sageTax).toEqual('Operaciones no sujetas'); + expect(sageTransaction).toEqual('Regularización de inversiones'); + expect(city).toEqual('Valencia'); + expect(province).toContain('Province one'); + expect(country).toEqual('España'); + expect(active).toBe('unchecked'); + expect(frozen).toBe('checked'); + expect(hasToInvoice).toBe('unchecked'); + expect(vies).toBe('checked'); + expect(notifyByMail).toBe('unchecked'); + expect(invoiceByAddress).toBe('checked'); + expect(equalizationTax).toBe('unchecked'); + expect(verifiedData).toBe('checked'); }); // confirm invoice by address checkbox gets checked if the EQtax differs between addresses step 1 diff --git a/e2e/paths/02-client/04_edit_billing_data.spec.js b/e2e/paths/02-client/04_edit_billing_data.spec.js index de3270f93..10eb85406 100644 --- a/e2e/paths/02-client/04_edit_billing_data.spec.js +++ b/e2e/paths/02-client/04_edit_billing_data.spec.js @@ -1,6 +1,23 @@ -import selectors from '../../helpers/selectors'; import getBrowser from '../../helpers/puppeteer'; +const $ = { + payMethod: 'vn-client-billing-data vn-autocomplete[ng-model="$ctrl.client.payMethodFk"]', + IBAN: 'vn-client-billing-data vn-textfield[ng-model="$ctrl.client.iban"]', + dueDay: 'vn-client-billing-data vn-input-number[ng-model="$ctrl.client.dueDay"]', + receivedCoreLCRCheckbox: 'vn-client-billing-data vn-check[label="Received LCR"]', + receivedCoreVNLCheckbox: 'vn-client-billing-data vn-check[label="Received core VNL"]', + receivedB2BVNLCheckbox: 'vn-client-billing-data vn-check[label="Received B2B VNL"]', + swiftBic: 'vn-client-billing-data vn-autocomplete[ng-model="$ctrl.client.bankEntityFk"]', + newBankEntityButton: 'vn-client-billing-data vn-icon-button[vn-tooltip="New bank entity"] > button', + newBankEntityName: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.data.name"]', + newBankEntityBIC: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.data.bic"]', + newBankEntityCountry: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.data.countryFk"]', + newBankEntityCode: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.data.id"]', + acceptBankEntityButton: '.vn-dialog.shown button[response="accept"]', + saveButton: 'vn-client-billing-data button[type=submit]', + watcher: 'vn-client-billing-data vn-watcher' +}; + describe('Client Edit billing data path', () => { let browser; let page; @@ -17,93 +34,72 @@ describe('Client Edit billing data path', () => { }); it(`should attempt to edit the billing data without an IBAN but fail`, async() => { - await page.autocompleteSearch(selectors.clientBillingData.payMethod, 'PayMethod with IBAN'); - await page.autocompleteSearch(selectors.clientBillingData.swiftBic, 'BBKKESMMMMM'); - await page.clearInput(selectors.clientBillingData.dueDay); - await page.write(selectors.clientBillingData.dueDay, '60'); - await page.waitForTextInField(selectors.clientBillingData.dueDay, '60'); - await page.waitToClick(selectors.clientBillingData.receivedCoreLCRCheckbox); - await page.waitToClick(selectors.clientBillingData.receivedCoreVNLCheckbox); - await page.waitToClick(selectors.clientBillingData.receivedB2BVNLCheckbox); - await page.waitToClick(selectors.clientBillingData.saveButton); + await page.autocompleteSearch($.payMethod, 'PayMethod with IBAN'); + await page.autocompleteSearch($.swiftBic, 'BBKKESMMMMM'); + await page.clearInput($.dueDay); + await page.write($.dueDay, '60'); + await page.waitForTextInField($.dueDay, '60'); + await page.waitToClick($.receivedCoreLCRCheckbox); + await page.waitToClick($.receivedCoreVNLCheckbox); + await page.waitToClick($.receivedB2BVNLCheckbox); + await page.waitToClick($.saveButton); const message = await page.waitForSnackbar(); expect(message.text).toContain('That payment method requires an IBAN'); }); it(`should create a new BIC code`, async() => { - await page.waitToClick(selectors.clientBillingData.newBankEntityButton); - await page.write(selectors.clientBillingData.newBankEntityName, 'Gotham City Bank'); - await page.write(selectors.clientBillingData.newBankEntityBIC, 'GTHMCT'); - await page.autocompleteSearch(selectors.clientBillingData.newBankEntityCountry, 'España'); - await page.write(selectors.clientBillingData.newBankEntityCode, '9999'); - await page.waitToClick(selectors.clientBillingData.acceptBankEntityButton); + await page.waitToClick($.newBankEntityButton); + await page.write($.newBankEntityName, 'Gotham City Bank'); + await page.write($.newBankEntityBIC, 'GTHMCT'); + await page.autocompleteSearch($.newBankEntityCountry, 'España'); + await page.write($.newBankEntityCode, '9999'); + await page.waitToClick($.acceptBankEntityButton); const message = await page.waitForSnackbar(); - await page.waitForTextInField(selectors.clientBillingData.swiftBic, 'Gotham City Bank'); - const newcode = await page.waitToGetProperty(selectors.clientBillingData.swiftBic, 'value'); - - expect(newcode).toEqual('GTHMCT Gotham City Bank'); + await page.waitForTextInField($.swiftBic, 'GTHMCT'); + const newcode = await page.waitToGetProperty($.swiftBic, 'value'); + expect(newcode).toEqual('GTHMCT'); expect(message.text).toContain('Data saved!'); }); it(`should confirm the IBAN pay method was sucessfully saved`, async() => { - const payMethod = await page.waitToGetProperty(selectors.clientBillingData.payMethod, 'value'); + const payMethod = await page.waitToGetProperty($.payMethod, 'value'); expect(payMethod).toEqual('PayMethod with IBAN'); }); it(`should clear the BIC code field, update the IBAN to see how he BIC code autocompletes`, async() => { - await page.write(selectors.clientBillingData.IBAN, 'ES9121000418450200051332'); + await page.write($.IBAN, 'ES9121000418450200051332'); await page.keyboard.press('Tab'); await page.keyboard.press('Tab'); - await page.waitForTextInField(selectors.clientBillingData.swiftBic, 'caixesbb'); - let automaticCode = await page.waitToGetProperty(selectors.clientBillingData.swiftBic, 'value'); + await page.waitForTextInField($.swiftBic, 'caixesbb'); + let automaticCode = await page.waitToGetProperty($.swiftBic, 'value'); - expect(automaticCode).toEqual('CAIXESBB Caixa Bank'); + expect(automaticCode).toEqual('CAIXESBB'); }); it(`should save the form with all its new data`, async() => { - await page.waitForWatcherData(selectors.clientBillingData.watcher); - await page.waitToClick(selectors.clientBillingData.saveButton); + await page.waitForWatcherData($.watcher); + await page.waitToClick($.saveButton); const message = await page.waitForSnackbar(); expect(message.text).toContain('Notification sent!'); }); - it('should confirm the due day have been edited', async() => { - const dueDate = await page.waitToGetProperty(selectors.clientBillingData.dueDay, 'value'); + it('should confirm the billing data have been edited', async() => { + const dueDate = await page.waitToGetProperty($.dueDay, 'value'); + const IBAN = await page.waitToGetProperty($.IBAN, 'value'); + const swiftBic = await page.waitToGetProperty($.swiftBic, 'value'); + const receivedCoreLCR = await page.checkboxState($.receivedCoreLCRCheckbox); + const receivedCoreVNL = await page.checkboxState($.receivedCoreVNLCheckbox); + const receivedB2BVNL = await page.checkboxState($.receivedB2BVNLCheckbox); expect(dueDate).toEqual('60'); - }); - - it('should confirm the IBAN was saved', async() => { - const IBAN = await page.waitToGetProperty(selectors.clientBillingData.IBAN, 'value'); - expect(IBAN).toEqual('ES9121000418450200051332'); - }); - - it('should confirm the swift / BIC code was saved', async() => { - const code = await page.waitToGetProperty(selectors.clientBillingData.swiftBic, 'value'); - - expect(code).toEqual('CAIXESBB Caixa Bank'); - }); - - it('should confirm Received LCR checkbox is checked', async() => { - const result = await page.checkboxState(selectors.clientBillingData.receivedCoreLCRCheckbox); - - expect(result).toBe('checked'); - }); - - it('should confirm Received core VNL checkbox is unchecked', async() => { - const result = await page.checkboxState(selectors.clientBillingData.receivedCoreVNLCheckbox); - - expect(result).toBe('unchecked'); - }); - - it('should confirm Received B2B VNL checkbox is unchecked', async() => { - const result = await page.checkboxState(selectors.clientBillingData.receivedB2BVNLCheckbox); - - expect(result).toBe('unchecked'); + expect(swiftBic).toEqual('CAIXESBB'); + expect(receivedCoreLCR).toBe('checked'); + expect(receivedCoreVNL).toBe('unchecked'); + expect(receivedB2BVNL).toBe('unchecked'); }); }); diff --git a/e2e/paths/02-client/07_edit_web_access.spec.js b/e2e/paths/02-client/07_edit_web_access.spec.js index 29b39f788..5386d12bd 100644 --- a/e2e/paths/02-client/07_edit_web_access.spec.js +++ b/e2e/paths/02-client/07_edit_web_access.spec.js @@ -1,88 +1,56 @@ -/* eslint max-len: ["error", { "code": 150 }]*/ -import selectors from '../../helpers/selectors'; import getBrowser from '../../helpers/puppeteer'; -describe('Client Edit web access path', () => { +const $ = { + enableWebAccess: 'vn-client-web-access vn-check[label="Enable web access"]', + userName: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.name"]', + email: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.email"]', + saveButton: 'vn-client-web-access button[type=submit]', + nameValue: 'vn-client-log .change:nth-child(1) .basic-json:nth-child(2) vn-json-value', + activeValue: 'vn-client-log .change:nth-child(2) .basic-json:nth-child(1) vn-json-value' +}; + +describe('Client web access path', () => { let browser; let page; + beforeAll(async() => { browser = await getBrowser(); page = browser.page; await page.loginAndModule('salesPerson', 'client'); await page.accessToSearchResult('max'); - await page.accessToSection('client.card.webAccess'); }); afterAll(async() => { await browser.close(); }); - it('should uncheck the Enable web access checkbox', async() => { - await page.waitToClick(selectors.clientWebAccess.enableWebAccessCheckbox); - await page.waitToClick(selectors.clientWebAccess.saveButton); - const message = await page.waitForSnackbar(); + it('should modify and save web access attributes', async() => { + await page.accessToSection('client.card.webAccess'); + await page.click($.enableWebAccess); + await page.click($.saveButton); + const enableMessage = await page.waitForSnackbar(); + await page.overwrite($.userName, 'Legion'); + await page.overwrite($.email, 'legion@marvel.com'); + await page.click($.saveButton); + const modifyMessage = await page.waitForSnackbar(); - expect(message.text).toContain('Data saved!'); - }); - - it(`should update the name`, async() => { - await page.clearInput(selectors.clientWebAccess.userName); - await page.write(selectors.clientWebAccess.userName, 'Legion'); - await page.waitToClick(selectors.clientWebAccess.saveButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it(`should update the email`, async() => { - await page.clearInput(selectors.clientWebAccess.email); - await page.write(selectors.clientWebAccess.email, 'legion@marvel.com'); - await page.waitToClick(selectors.clientWebAccess.saveButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it('should reload the section and confirm web access is now unchecked', async() => { await page.reloadSection('client.card.webAccess'); - const result = await page.checkboxState(selectors.clientWebAccess.enableWebAccessCheckbox); + const hasAccess = await page.checkboxState($.enableWebAccess); + const userName = await page.getValue($.userName); + const email = await page.getValue($.email); - expect(result).toBe('unchecked'); - }); - - it('should confirm web access name have been updated', async() => { - const result = await page.waitToGetProperty(selectors.clientWebAccess.userName, 'value'); - - expect(result).toEqual('Legion'); - }); - - it('should confirm web access email have been updated', async() => { - const result = await page.waitToGetProperty(selectors.clientWebAccess.email, 'value'); - - expect(result).toEqual('legion@marvel.com'); - }); - - it(`should navigate to the log section`, async() => { await page.accessToSection('client.card.log'); - }); + const logName = await page.innerText($.nameValue); + const logActive = await page.innerText($.activeValue); - it(`should confirm the last log shows the updated client name and no modifications on active checkbox`, async() => { - let namePreviousValue = await page - .waitToGetProperty(selectors.clientLog.namePreviousValue, 'innerText'); - let nameCurrentValue = await page - .waitToGetProperty(selectors.clientLog.nameCurrentValue, 'innerText'); + expect(enableMessage.type).toBe('success'); + expect(modifyMessage.type).toBe('success'); - expect(namePreviousValue).toEqual('MaxEisenhardt'); - expect(nameCurrentValue).toEqual('Legion'); - }); + expect(hasAccess).toBe('unchecked'); + expect(userName).toEqual('Legion'); + expect(email).toEqual('legion@marvel.com'); - it(`should confirm the penultimate log shows the updated active and no modifications on client name`, async() => { - let activePreviousValue = await page - .waitToGetProperty(selectors.clientLog.activePreviousValue, 'innerText'); - let activeCurrentValue = await page - .waitToGetProperty(selectors.clientLog.activeCurrentValue, 'innerText'); - - expect(activePreviousValue).toEqual('✓'); - expect(activeCurrentValue).toEqual('✗'); + expect(logName).toEqual('Legion'); + expect(logActive).toEqual('✗'); }); }); diff --git a/e2e/paths/02-client/10_add_greuge.spec.js b/e2e/paths/02-client/10_add_greuge.spec.js index 6ea923a28..9141c499a 100644 --- a/e2e/paths/02-client/10_add_greuge.spec.js +++ b/e2e/paths/02-client/10_add_greuge.spec.js @@ -29,19 +29,16 @@ describe('Client Add greuge path', () => { expect(message.text).toContain('Some fields are invalid'); }); - it(`should create a new greuge with all its data`, async() => { + it(`should create a new greuge with all its data and confirm the greuge was added to the list`, async() => { await page.write(selectors.clientGreuge.amount, '999'); await page.waitForTextInField(selectors.clientGreuge.amount, '999'); await page.write(selectors.clientGreuge.description, 'new armor for Batman!'); await page.waitToClick(selectors.clientGreuge.saveButton); const message = await page.waitForSnackbar(); - expect(message.text).toContain('Data saved!'); - }); - - it('should confirm the greuge was added to the list', async() => { const result = await page.waitToGetProperty(selectors.clientGreuge.firstGreugeText, 'innerText'); + expect(message.text).toContain('Data saved!'); expect(result).toContain(999); expect(result).toContain('new armor for Batman!'); expect(result).toContain('Diff'); diff --git a/e2e/paths/02-client/13_log.spec.js b/e2e/paths/02-client/13_log.spec.js index 8f186d842..5292b1a65 100644 --- a/e2e/paths/02-client/13_log.spec.js +++ b/e2e/paths/02-client/13_log.spec.js @@ -28,22 +28,4 @@ describe('Client log path', () => { it('should navigate to the log section', async() => { await page.accessToSection('client.card.log'); }); - - it('should check the previous value of the last logged change', async() => { - let lastModificationPreviousValue = await page - .waitToGetProperty(selectors.clientLog.lastModificationPreviousValue, 'innerText'); - - expect(lastModificationPreviousValue).toContain('DavidCharlesHaller'); - }); - - it('should check the current value of the last logged change', async() => { - let lastModificationPreviousValue = await page - .waitToGetProperty(selectors.clientLog.lastModificationPreviousValue, 'innerText'); - - let lastModificationCurrentValue = await page. - waitToGetProperty(selectors.clientLog.lastModificationCurrentValue, 'innerText'); - - expect(lastModificationPreviousValue).toEqual('DavidCharlesHaller'); - expect(lastModificationCurrentValue).toEqual('this is a test'); - }); }); diff --git a/e2e/paths/02-client/14_balance.spec.js b/e2e/paths/02-client/14_balance.spec.js index d3de842e3..b1c0f7eea 100644 --- a/e2e/paths/02-client/14_balance.spec.js +++ b/e2e/paths/02-client/14_balance.spec.js @@ -1,6 +1,17 @@ import selectors from '../../helpers/selectors'; import getBrowser from '../../helpers/puppeteer'; +const $ = { + company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]', + newPaymentButton: `vn-float-button`, + newPayment: '.vn-dialog.shown', + refundAmount: '.vn-dialog.shown [vn-name="amountToReturn"]', + saveButton: '.vn-dialog.shown [response="accept"]', + firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)', + firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable', + firstLineReferenceInput: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable vn-textfield', +}; + describe('Client balance path', () => { let browser; let page; @@ -18,125 +29,100 @@ describe('Client balance path', () => { it('should now edit the local user config data', async() => { await page.waitToClick(selectors.globalItems.userMenuButton); await page.autocompleteSearch(selectors.globalItems.userLocalCompany, 'CCs'); - const message = await page.waitForSnackbar(); + const companyMessage = await page.waitForSnackbar(); - expect(message.text).toContain('Data saved!'); - }); - - it('should access to the balance section to check the data shown matches the local settings', async() => { await page.accessToSection('client.card.balance.index'); - let result = await page.waitToGetProperty(selectors.clientBalance.company, 'value'); + const company = await page.getValue($.company); - expect(result).toEqual('CCs'); - }); - - it('should now clear the user local settings', async() => { await page.waitToClick(selectors.globalItems.userMenuButton); await page.clearInput(selectors.globalItems.userConfigThirdAutocomplete); const message = await page.waitForSnackbar(); - expect(message.text).toContain('Data saved!'); - }); - - it('should reload the section', async() => { await page.closePopup(); await page.reloadSection('client.card.balance.index'); + + expect(companyMessage.isSuccess).toBeTrue(); + expect(company).toEqual('CCs'); + expect(message.isSuccess).toBeTrue(); }); it('should create a new payment that clears the debt', async() => { - await page.closePopup(); - await page.waitToClick(selectors.clientBalance.newPaymentButton); - await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Cash'); - await page.clearInput(selectors.clientBalance.newDescription); - await page.write(selectors.clientBalance.newDescription, 'Description'); - await page.waitToClick(selectors.clientBalance.saveButton); + await page.waitToClick($.newPaymentButton); + await page.fillForm($.newPayment, { + bank: 'Cash', + description: 'Description', + viewReceipt: false + }); + await page.respondToDialog('accept'); const message = await page.waitForSnackbar(); - expect(message.text).toContain('Data saved!'); + expect(message.isSuccess).toBeTrue(); }); - it('should edit the 1st line reference', async() => { - await page.waitToClick(selectors.clientBalance.firstLineReference); - await page.write(selectors.clientBalance.firstLineReferenceInput, 'Miscellaneous payment'); + it('should edit the 1st line reference and check data', async() => { + await page.waitToClick($.firstLineReference); + await page.write($.firstLineReferenceInput, 'Miscellaneous payment'); await page.keyboard.press('Enter'); const message = await page.waitForSnackbar(); - expect(message.text).toContain('Data saved!'); - }); - - it('should check balance is now 0, the reference was saved and the company is now VNL becouse the user local settings were removed', async() => { await page.waitForSpinnerLoad(); - let company = await page - .waitToGetProperty(selectors.clientBalance.company, 'value'); - - let reference = await page - .waitToGetProperty(selectors.clientBalance.firstLineReference, 'innerText'); - - let firstBalanceLine = await page - .waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText'); + let company = await page.getValue($.company); + let reference = await page.innerText($.firstLineReference); + let firstBalanceLine = await page.innerText($.firstLineBalance); + expect(message.isSuccess).toBeTrue(); expect(company).toEqual('VNL'); expect(reference).toEqual('Miscellaneous payment'); expect(firstBalanceLine).toContain('0.00'); }); - it('should create a new payment and check the cash comparison works correctly', async() => { - const amountPaid = '100'; - const cashHanded = '500'; - const expectedRefund = '400'; - - await page.waitToClick(selectors.clientBalance.newPaymentButton); - await page.write(selectors.clientBalance.newPaymentAmount, amountPaid); - await page.clearInput(selectors.clientBalance.newDescription); - await page.write(selectors.clientBalance.newDescription, 'Payment'); - await page.write(selectors.clientBalance.deliveredAmount, cashHanded); - const refund = await page.waitToGetProperty(selectors.clientBalance.refundAmount, 'value'); - await page.waitToClick(selectors.clientBalance.saveButton); + it('should create a new payment, check the cash comparison works correctly and balance value is -100', async() => { + await page.waitToClick($.newPaymentButton); + await page.fillForm($.newPayment, { + amountPaid: 100, + description: 'Payment', + deliveredAmount: 500, + viewReceipt: false + }); + const refund = await page.getValue($.refundAmount); + await page.respondToDialog('accept'); const message = await page.waitForSnackbar(); - expect(refund).toEqual(expectedRefund); - expect(message.text).toContain('Data saved!'); - }); - - it('should check the balance value is now -100', async() => { - let result = await page - .waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText'); + const result = await page.innerText($.firstLineBalance); + expect(refund).toEqual('400'); + expect(message.isSuccess).toBeTrue(); expect(result).toContain('-€100.00'); }); it('should create a new payment and check the cash exceeded the maximum', async() => { - const amountPaid = '1001'; - - await page.closePopup(); - await page.waitToClick(selectors.clientBalance.newPaymentButton); - await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Cash'); - await page.write(selectors.clientBalance.newPaymentAmount, amountPaid); - await page.clearInput(selectors.clientBalance.newDescription); - await page.write(selectors.clientBalance.newDescription, 'Payment'); - await page.waitToClick(selectors.clientBalance.saveButton); + await page.waitToClick($.newPaymentButton); + await page.fillForm($.newPayment, { + bank: 'Cash', + amountPaid: 1001, + description: 'Payment' + }); + await page.waitToClick($.saveButton); const message = await page.waitForSnackbar(); expect(message.text).toContain('Amount exceeded'); }); - it('should create a new payment that sets the balance back to the original negative value', async() => { + it('should create a new payment that sets the balance back to negative value and check it', async() => { await page.closePopup(); - await page.waitToClick(selectors.clientBalance.newPaymentButton); - await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Pay on receipt'); - await page.overwrite(selectors.clientBalance.newPaymentAmount, '-150'); - await page.clearInput(selectors.clientBalance.newDescription); - await page.write(selectors.clientBalance.newDescription, 'Description'); - await page.waitToClick(selectors.clientBalance.saveButton); + await page.waitToClick($.newPaymentButton); + + await page.fillForm($.newPayment, { + bank: 'Pay on receipt', + amountPaid: -150, + description: 'Description' + }); + await page.respondToDialog('accept'); const message = await page.waitForSnackbar(); - expect(message.text).toContain('Data saved!'); - }); - - it('should check balance is now 50', async() => { - let result = await page - .waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText'); + const result = await page.innerText($.firstLineBalance); + expect(message.isSuccess).toBeTrue(); expect(result).toEqual('€50.00'); }); @@ -149,12 +135,9 @@ describe('Client balance path', () => { await page.waitForState('client.index'); }); - it('should now search for the user Petter Parker', async() => { + it('should now search for the user Petter Parker not check the payment button is not present', async() => { await page.accessToSearchResult('Petter Parker'); await page.accessToSection('client.card.balance.index'); - }); - - it('should not be able to click the new payment button as it isnt present', async() => { - await page.waitForSelector(selectors.clientBalance.newPaymentButton, {hidden: true}); + await page.waitForSelector($.newPaymentButton, {hidden: true}); }); }); diff --git a/e2e/paths/02-client/21_defaulter.spec.js b/e2e/paths/02-client/21_defaulter.spec.js index 0eb16441f..97e62abef 100644 --- a/e2e/paths/02-client/21_defaulter.spec.js +++ b/e2e/paths/02-client/21_defaulter.spec.js @@ -50,7 +50,7 @@ describe('Client defaulter path', () => { expect(message.text).toContain(`The message can't be empty`); }); - it('shoul checked all defaulters', async() => { + it('should checked all defaulters', async() => { await page.loginAndModule('insurance', 'client'); await page.accessToSection('client.defaulter'); diff --git a/e2e/paths/02-client/23_send_compensation.spec.js b/e2e/paths/02-client/23_send_compensation.spec.js index 6ec8936a8..7ab2d0bac 100644 --- a/e2e/paths/02-client/23_send_compensation.spec.js +++ b/e2e/paths/02-client/23_send_compensation.spec.js @@ -1,6 +1,11 @@ -import selectors from '../../helpers/selectors'; import getBrowser from '../../helpers/puppeteer'; +const $ = { + company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]', + compensationButton: 'vn-client-balance-index vn-icon-button[vn-dialog="send_compensation"]', + saveButton: '.vn-dialog.shown [response="accept"]' +}; + describe('Client Send balance compensation', () => { let browser; let page; @@ -17,9 +22,9 @@ describe('Client Send balance compensation', () => { }); it(`should click on send compensation button`, async() => { - await page.autocompleteSearch(selectors.clientBalance.company, 'VNL'); - await page.waitToClick(selectors.clientBalance.compensationButton); - await page.waitToClick(selectors.clientBalance.saveButton); + await page.autocompleteSearch($.company, 'VNL'); + await page.waitToClick($.compensationButton); + await page.waitToClick($.saveButton); const message = await page.waitForSnackbar(); expect(message.text).toContain('Notification sent!'); diff --git a/e2e/paths/04-item/02_basic_data.spec.js b/e2e/paths/04-item/02_basic_data.spec.js index 3cf142816..bb8f3f134 100644 --- a/e2e/paths/04-item/02_basic_data.spec.js +++ b/e2e/paths/04-item/02_basic_data.spec.js @@ -1,14 +1,23 @@ -import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; +const $ = { + form: 'vn-item-basic-data form', + intrastatForm: '.vn-dialog.shown form', + newIntrastatButton: 'vn-item-basic-data vn-icon-button[vn-tooltip="New intrastat"] > button' +}; + describe('Item Edit basic data path', () => { let browser; let page; + beforeAll(async() => { browser = await getBrowser(); page = browser.page; await page.loginAndModule('buyer', 'item'); await page.accessToSearchResult('Melee weapon combat fist 15cm'); + }); + + beforeEach(async() => { await page.accessToSection('item.card.basicData'); }); @@ -16,124 +25,42 @@ describe('Item Edit basic data path', () => { await browser.close(); }); - it(`should check the descritor edit button is visible for buyer`, async() => { - await page.waitForSelector(selectors.itemDescriptor.editButton, {visible: true}); - }); + it(`should edit the item basic data and confirm the item data was edited`, async() => { + const values = { + name: 'Rose of Purity', + longName: 'RS Rose of Purity', + type: 'Anthurium', + intrastat: 'Coral y materiales similares', + origin: 'Spain', + relevancy: 1, + generic: 'Pallet', + isActive: false, + priceInKg: true, + isFragile: true, + packingOut: 5 + }; - it(`should edit the item basic data`, async() => { - await page.clearInput(selectors.itemBasicData.name); - await page.write(selectors.itemBasicData.name, 'Rose of Purity'); - await page.clearInput(selectors.itemBasicData.longName); - await page.write(selectors.itemBasicData.longName, 'RS Rose of Purity'); - await page.autocompleteSearch(selectors.itemBasicData.type, 'Anthurium'); - await page.autocompleteSearch(selectors.itemBasicData.intrastat, 'Coral y materiales similares'); - await page.autocompleteSearch(selectors.itemBasicData.origin, 'Spain'); - await page.clearInput(selectors.itemBasicData.relevancy); - await page.write(selectors.itemBasicData.relevancy, '1'); - await page.clearInput(selectors.itemBasicData.generic); - await page.autocompleteSearch(selectors.itemBasicData.generic, '16'); - await page.waitToClick(selectors.itemBasicData.isActiveCheckbox); - await page.waitToClick(selectors.itemBasicData.priceInKgCheckbox); - await page.waitToClick(selectors.itemBasicData.isFragile); - await page.write(selectors.itemBasicData.packingOut, '5'); - await page.waitToClick(selectors.itemBasicData.submitBasicDataButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it(`should create a new intrastat`, async() => { - await page.waitToClick(selectors.itemBasicData.newIntrastatButton); - await page.write(selectors.itemBasicData.newIntrastatId, '588420239'); - await page.write(selectors.itemBasicData.newIntrastatDescription, 'Tropical Flowers'); - await page.waitToClick(selectors.itemBasicData.acceptIntrastatButton); - await page.waitForTextInField(selectors.itemBasicData.intrastat, 'Tropical Flowers'); - let newcode = await page.waitToGetProperty(selectors.itemBasicData.intrastat, 'value'); - - expect(newcode).toEqual('588420239 Tropical Flowers'); - }); - - it('should save with the new intrastat', async() => { - await page.waitToClick(selectors.itemBasicData.submitBasicDataButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it(`should confirm the item name was edited`, async() => { + const message = await page.sendForm($.form, values); await page.reloadSection('item.card.basicData'); - const result = await page.waitToGetProperty(selectors.itemBasicData.name, 'value'); + const formValues = await page.fetchForm($.form, Object.keys(values)); - expect(result).toEqual('Rose of Purity'); + expect(message.isSuccess).toBeTrue(); + expect(formValues).toEqual(values); }); - it(`should confirm the item type was edited`, async() => { - const result = await page - .waitToGetProperty(selectors.itemBasicData.type, 'value'); + it(`should create a new intrastat and save it`, async() => { + await page.click($.newIntrastatButton); + await page.fillForm($.intrastatForm, { + id: '588420239', + description: 'Tropical Flowers' + }); + await page.respondToDialog('accept'); - expect(result).toEqual('Anthurium'); - }); + const message = await page.sendForm($.form); + await page.reloadSection('item.card.basicData'); + const formValues = await page.fetchForm($.form, ['intrastat']); - it(`should confirm the item intrastat was edited`, async() => { - const result = await page - .waitToGetProperty(selectors.itemBasicData.intrastat, 'value'); - - expect(result).toEqual('588420239 Tropical Flowers'); - }); - - it(`should confirm the item relevancy was edited`, async() => { - const result = await page - .waitToGetProperty(selectors.itemBasicData.relevancy, 'value'); - - expect(result).toEqual('1'); - }); - - it(`should confirm the item origin was edited`, async() => { - const result = await page - .waitToGetProperty(selectors.itemBasicData.origin, 'value'); - - expect(result).toEqual('Spain'); - }); - - it(`should confirm the item generic was edited`, async() => { - const result = await page - .waitToGetProperty(selectors.itemBasicData.generic, 'value'); - - expect(result).toEqual('16 - Pallet'); - }); - - it(`should confirm the item long name was edited`, async() => { - const result = await page - .waitToGetProperty(selectors.itemBasicData.longName, 'value'); - - expect(result).toEqual('RS Rose of Purity'); - }); - - it('should confirm isFragile checkbox is unchecked', async() => { - const result = await page - .checkboxState(selectors.itemBasicData.isFragile); - - expect(result).toBe('checked'); - }); - - it('should confirm isActive checkbox is unchecked', async() => { - const result = await page - .checkboxState(selectors.itemBasicData.isActiveCheckbox); - - expect(result).toBe('unchecked'); - }); - - it('should confirm the priceInKg checkbox is checked', async() => { - const result = await page - .checkboxState(selectors.itemBasicData.priceInKgCheckbox); - - expect(result).toBe('checked'); - }); - - it(`should confirm the item packingOut was edited`, async() => { - const result = await page - .waitToGetProperty(selectors.itemBasicData.packingOut, 'value'); - - expect(result).toEqual('5'); + expect(message.isSuccess).toBeTrue(); + expect(formValues).toEqual({intrastat: 'Tropical Flowers'}); }); }); diff --git a/e2e/paths/04-item/03_tax.spec.js b/e2e/paths/04-item/03_tax.spec.js index 8b3b0f8b1..83f4e6bee 100644 --- a/e2e/paths/04-item/03_tax.spec.js +++ b/e2e/paths/04-item/03_tax.spec.js @@ -53,12 +53,4 @@ describe('Item edit tax path', () => { expect(firstVatType).toEqual('Reduced VAT'); }); - - // # #2680 Undo changes button bugs - xit(`should now click the undo changes button and see the form is restored`, async() => { - await page.waitToClick(selectors.itemTax.undoChangesButton); - const firstVatType = await page.waitToGetProperty(selectors.itemTax.firstClass, 'value'); - - expect(firstVatType).toEqual('General VAT'); - }); }); diff --git a/e2e/paths/04-item/07_create.spec.js b/e2e/paths/04-item/07_create.spec.js index 33324cdba..c20be9ebc 100644 --- a/e2e/paths/04-item/07_create.spec.js +++ b/e2e/paths/04-item/07_create.spec.js @@ -1,6 +1,10 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; +const $ = { + form: 'vn-item-create form' +}; + describe('Item Create', () => { let browser; let page; @@ -14,13 +18,6 @@ describe('Item Create', () => { await browser.close(); }); - it(`should search for the item Infinity Gauntlet to confirm it isn't created yet`, async() => { - await page.doSearch('Infinity Gauntlet'); - const resultsCount = await page.countElement(selectors.itemsIndex.searchResult); - - expect(resultsCount).toEqual(0); - }); - it('should access to the create item view by clicking the create floating button', async() => { await page.waitToClick(selectors.itemsIndex.createItemButton); await page.waitForState('item.create'); @@ -37,44 +34,32 @@ describe('Item Create', () => { }); it('should throw an error when insert an invalid priority', async() => { - await page.write(selectors.itemCreateView.temporalName, 'Infinity Gauntlet'); - await page.autocompleteSearch(selectors.itemCreateView.type, 'Crisantemo'); - await page.autocompleteSearch(selectors.itemCreateView.intrastat, 'Coral y materiales similares'); - await page.autocompleteSearch(selectors.itemCreateView.origin, 'Holand'); - await page.clearInput(selectors.itemCreateView.priority); - await page.waitToClick(selectors.itemCreateView.createButton); - const message = await page.waitForSnackbar(); + const values = { + name: 'Infinity Gauntlet', + type: 'Crisantemo', + intrastat: 'Coral y materiales similares', + origin: 'Holand', + priority: null + }; + const message = await page.sendForm($.form, values); expect(message.text).toContain('Valid priorities'); }); it('should create the Infinity Gauntlet item', async() => { - await page.autocompleteSearch(selectors.itemCreateView.priority, '2'); - await page.waitToClick(selectors.itemCreateView.createButton); - const message = await page.waitForSnackbar(); + const values = { + name: 'Infinity Gauntlet', + type: 'Crisantemo', + intrastat: 'Coral y materiales similares', + origin: 'Holand', + priority: '2' + }; - expect(message.text).toContain('Data saved!'); - }); + await page.fillForm($.form, values); + const formValues = await page.fetchForm($.form, Object.keys(values)); + const message = await page.sendForm($.form); - it('should confirm Infinity Gauntlet item was created', async() => { - let result = await page - .waitToGetProperty(selectors.itemBasicData.name, 'value'); - - expect(result).toEqual('Infinity Gauntlet'); - - result = await page - .waitToGetProperty(selectors.itemBasicData.type, 'value'); - - expect(result).toEqual('Crisantemo'); - - result = await page - .waitToGetProperty(selectors.itemBasicData.intrastat, 'value'); - - expect(result).toEqual('5080000 Coral y materiales similares'); - - result = await page - .waitToGetProperty(selectors.itemBasicData.origin, 'value'); - - expect(result).toEqual('Holand'); + expect(message.isSuccess).toBeTrue(); + expect(formValues).toEqual(values); }); }); diff --git a/e2e/paths/04-item/10_item_log.spec.js b/e2e/paths/04-item/10_item_log.spec.js index 6a7bd7ae2..dc467044d 100644 --- a/e2e/paths/04-item/10_item_log.spec.js +++ b/e2e/paths/04-item/10_item_log.spec.js @@ -42,23 +42,4 @@ describe('Item log path', () => { await page.waitForSelector(selectors.itemsIndex.createItemButton); await page.waitForState('item.index'); }); - - it(`should search for the created item and navigate to it's log section`, async() => { - await page.accessToSearchResult('Knowledge artifact'); - await page.accessToSection('item.card.log'); - }); - - it(`should confirm the log is showing 4 entries`, async() => { - await page.waitForSelector(selectors.itemLog.anyLineCreated); - const anyLineCreatedCount = await page.countElement(selectors.itemLog.anyLineCreated); - - expect(anyLineCreatedCount).toEqual(4); - }); - - xit(`should confirm the log is showing the intrastat for the created item`, async() => { - const fifthLineCreatedProperty = await page - .waitToGetProperty(selectors.itemLog.fifthLineCreatedProperty, 'innerText'); - - expect(fifthLineCreatedProperty).toEqual('05080000'); - }); }); diff --git a/e2e/paths/04-item/13_fixedPrice.spec.js b/e2e/paths/04-item/13_fixedPrice.spec.js index ec8238b87..37c4401b0 100644 --- a/e2e/paths/04-item/13_fixedPrice.spec.js +++ b/e2e/paths/04-item/13_fixedPrice.spec.js @@ -1,47 +1,95 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; +const $ = selectors.itemFixedPrice; + describe('Item fixed prices path', () => { let browser; let page; + let httpRequest; + beforeAll(async() => { browser = await getBrowser(); page = browser.page; await page.loginAndModule('buyer', 'item'); await page.accessToSection('item.fixedPrice'); + page.on('request', req => { + if (req.url().includes(`FixedPrices/filter`)) + httpRequest = req.url(); + }); }); afterAll(async() => { await browser.close(); }); + it('should filter using all the fields', async() => { + await page.write($.generalSearchFilter, 'item'); + await page.keyboard.press('Enter'); + + expect(httpRequest).toContain('search=item'); + + await page.click($.chip); + await page.click($.reignFilter); + + expect(httpRequest).toContain('categoryFk'); + + await page.autocompleteSearch($.typeFilter, 'Alstroemeria'); + + expect(httpRequest).toContain('typeFk'); + + await page.click($.chip); + await page.autocompleteSearch($.buyerFilter, 'buyerNick'); + + expect(httpRequest).toContain('buyerFk'); + + await page.click($.chip); + await page.autocompleteSearch($.warehouseFilter, 'Algemesi'); + + expect(httpRequest).toContain('warehouseFk'); + + await page.click($.chip); + await page.click($.mineFilter); + + expect(httpRequest).toContain('mine=true'); + + await page.click($.chip); + await page.click($.hasMinPriceFilter); + + expect(httpRequest).toContain('hasMinPrice=true'); + + await page.click($.chip); + await page.click($.addTag); + await page.autocompleteSearch($.tagFilter, 'Color'); + await page.autocompleteSearch($.tagValueFilter, 'Brown'); + + expect(httpRequest).toContain('tags'); + + await page.click($.chip); + }); + it('should click on the add new fixed price button', async() => { - await page.waitToClick(selectors.itemFixedPrice.removeWarehouseFilter); - await page.waitForSpinnerLoad(); - await page.waitToClick(selectors.itemFixedPrice.add); - await page.waitForSelector(selectors.itemFixedPrice.fourthFixedPrice); + await page.waitToClick($.add); + await page.waitForSelector($.fourthFixedPrice); }); it('should fill the fixed price data', async() => { const now = Date.vnNew(); - await page.autocompleteSearch(selectors.itemFixedPrice.fourthWarehouse, 'Warehouse one'); - await page.writeOnEditableTD(selectors.itemFixedPrice.fourthGroupingPrice, '1'); - await page.writeOnEditableTD(selectors.itemFixedPrice.fourthPackingPrice, '1'); - await page.write(selectors.itemFixedPrice.fourthMinPrice, '1'); - await page.pickDate(selectors.itemFixedPrice.fourthStarted, now); - await page.pickDate(selectors.itemFixedPrice.fourthEnded, now); + await page.autocompleteSearch($.fourthWarehouse, 'Warehouse one'); + await page.writeOnEditableTD($.fourthGroupingPrice, '1'); + await page.writeOnEditableTD($.fourthPackingPrice, '1'); + await page.write($.fourthMinPrice, '1'); + await page.pickDate($.fourthStarted, now); + await page.pickDate($.fourthEnded, now); const message = await page.waitForSnackbar(); expect(message.text).toContain('Data saved!'); }); it('should reload the section and check the created price has the expected ID', async() => { - await page.accessToSection('item.index'); - await page.accessToSection('item.fixedPrice'); - await page.waitToClick(selectors.itemFixedPrice.removeWarehouseFilter); - await page.waitForSpinnerLoad(); + await page.goto(`http://localhost:5000/#!/item/fixed-price`); - const result = await page.waitToGetProperty(selectors.itemFixedPrice.fourthItemID, 'value'); + const result = await page.waitToGetProperty($.fourthItemID, 'value'); expect(result).toContain('13'); }); diff --git a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js index f9b520981..2c9646708 100644 --- a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js +++ b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js @@ -246,9 +246,11 @@ describe('Ticket Edit sale path', () => { it('should select the third sale and create a claim of it', async() => { await page.accessToSearchResult('16'); await page.accessToSection('ticket.card.sale'); + await page.waitToClick(selectors.ticketSales.firstSaleCheckbox); await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox); await page.waitToClick(selectors.ticketSales.moreMenu); await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim); + await page.waitToClick(selectors.globalItems.acceptButton); await page.waitForState('claim.card.basicData'); }); @@ -314,7 +316,7 @@ describe('Ticket Edit sale path', () => { it('should confirm the transfered quantity is the correct one', async() => { const result = await page.waitToGetProperty(selectors.ticketSales.secondSaleQuantityCell, 'innerText'); - expect(result).toContain('20'); + expect(result).toContain('10'); }); it('should go back to the original ticket sales section', async() => { @@ -423,20 +425,6 @@ describe('Ticket Edit sale path', () => { expect(result).toBeFalsy(); }); - // tickets no longer update their totals instantly, a task performed ever 5-10 mins does it. disabled this test until it changes. - xit('should update all sales discount', async() => { - await page.closePopup(); - await page.waitToClick(selectors.ticketSales.moreMenu); - await page.waitToClick(selectors.ticketSales.moreMenuUpdateDiscount); - await page.waitForSelector(selectors.ticketSales.moreMenuUpdateDiscountInput); - await page.type(selectors.ticketSales.moreMenuUpdateDiscountInput, '100'); - await page.keyboard.press('Enter'); - await page.waitForTextInElement(selectors.ticketSales.totalImport, '0.00'); - const result = await page.waitToGetProperty(selectors.ticketSales.totalImport, 'innerText'); - - expect(result).toContain('0.00'); - }); - it('should log in as Production role and go to a target ticket summary', async() => { await page.loginAndModule('production', 'ticket'); await page.accessToSearchResult('13'); diff --git a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js index ae5e2fb0c..edccd5561 100644 --- a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js +++ b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js @@ -29,20 +29,4 @@ describe('Ticket expeditions and log path', () => { expect(result).toEqual(3); }); - - it(`should confirm the expedition deleted is shown now in the ticket log`, async() => { - await page.accessToSection('ticket.card.log'); - const user = await page - .waitToGetProperty(selectors.ticketLog.user, 'innerText'); - - const action = await page - .waitToGetProperty(selectors.ticketLog.action, 'innerText'); - - const id = await page - .waitToGetProperty(selectors.ticketLog.id, 'innerText'); - - expect(user).toContain('production'); - expect(action).toContain('Deletes'); - expect(id).toEqual('2'); - }); }); diff --git a/e2e/paths/05-ticket/04_packages.spec.js b/e2e/paths/05-ticket/04_packages.spec.js index f874307a8..2b79e9cb6 100644 --- a/e2e/paths/05-ticket/04_packages.spec.js +++ b/e2e/paths/05-ticket/04_packages.spec.js @@ -1,6 +1,13 @@ -import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; +const $ = { + firstPackage: 'vn-autocomplete[label="Package"]', + firstQuantity: 'vn-ticket-package vn-horizontal:nth-child(1) vn-input-number[ng-model="package.quantity"]', + firstRemovePackageButton: 'vn-icon-button[vn-tooltip="Remove package"]', + addPackageButton: 'vn-icon-button[vn-tooltip="Add package"]', + savePackagesButton: `button[type=submit]` +}; + describe('Ticket Create packages path', () => { let browser; let page; @@ -18,19 +25,19 @@ describe('Ticket Create packages path', () => { }); it(`should attempt create a new package but receive an error if package is blank`, async() => { - await page.waitToClick(selectors.ticketPackages.firstRemovePackageButton); - await page.waitToClick(selectors.ticketPackages.addPackageButton); - await page.write(selectors.ticketPackages.firstQuantity, '99'); - await page.waitToClick(selectors.ticketPackages.savePackagesButton); + await page.waitToClick($.firstRemovePackageButton); + await page.waitToClick($.addPackageButton); + await page.write($.firstQuantity, '99'); + await page.waitToClick($.savePackagesButton); const message = await page.waitForSnackbar(); expect(message.text).toContain('Package cannot be blank'); }); it(`should delete the first package and receive and error to save a new one with blank quantity`, async() => { - await page.clearInput(selectors.ticketPackages.firstQuantity); - await page.autocompleteSearch(selectors.ticketPackages.firstPackage, 'Container medical box 1m'); - await page.waitToClick(selectors.ticketPackages.savePackagesButton); + await page.clearInput($.firstQuantity); + await page.autocompleteSearch($.firstPackage, 'Container medical box 1m'); + await page.waitToClick($.savePackagesButton); const message = await page.waitForSnackbar(); expect(message.text).toContain('Some fields are invalid'); @@ -40,15 +47,15 @@ describe('Ticket Create packages path', () => { const result = await page .evaluate(selector => { return document.querySelector(`${selector} input`).checkValidity(); - }, selectors.ticketPackages.firstQuantity); + }, $.firstQuantity); expect(result).toBeTruthy(); }); it(`should create a new package with correct data`, async() => { - await page.clearInput(selectors.ticketPackages.firstQuantity); - await page.write(selectors.ticketPackages.firstQuantity, '-99'); - await page.waitToClick(selectors.ticketPackages.savePackagesButton); + await page.clearInput($.firstQuantity); + await page.write($.firstQuantity, '-99'); + await page.waitToClick($.savePackagesButton); const message = await page.waitForSnackbar(); expect(message.text).toContain('Data saved!'); @@ -56,15 +63,15 @@ describe('Ticket Create packages path', () => { it(`should confirm the first select is the expected one`, async() => { await page.reloadSection('ticket.card.package'); - await page.waitForTextInField(selectors.ticketPackages.firstPackage, 'Container medical box 1m'); - const result = await page.waitToGetProperty(selectors.ticketPackages.firstPackage, 'value'); + await page.waitForTextInField($.firstPackage, 'Container medical box 1m'); + const result = await page.waitToGetProperty($.firstPackage, 'value'); - expect(result).toEqual('7 : Container medical box 1m'); + expect(result).toEqual('Container medical box 1m'); }); it(`should confirm quantity is just a number and the string part was ignored by the imput number`, async() => { - await page.waitForTextInField(selectors.ticketPackages.firstQuantity, '-99'); - const result = await page.waitToGetProperty(selectors.ticketPackages.firstQuantity, 'value'); + await page.waitForTextInField($.firstQuantity, '-99'); + const result = await page.waitToGetProperty($.firstQuantity, 'value'); expect(result).toEqual('-99'); }); diff --git a/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js b/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js index a68ce894e..51ead6461 100644 --- a/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js +++ b/e2e/paths/05-ticket/15_create_ticket_from_client.spec.js @@ -1,6 +1,11 @@ -import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; +const $ = { + form: 'vn-ticket-create-card', + moreMenu: 'vn-client-descriptor vn-icon-button[icon=more_vert]', + simpleTicketButton: '.vn-menu [name="simpleTicket"]' +}; + describe('Ticket create from client path', () => { let browser; let page; @@ -16,20 +21,17 @@ describe('Ticket create from client path', () => { await browser.close(); }); - it('should click the create simple ticket on the descriptor menu', async() => { - await page.waitToClick(selectors.clientDescriptor.moreMenu); - await page.waitToClick(selectors.clientDescriptor.simpleTicketButton); + it('should create simple ticket and check if the client details are the expected ones', async() => { + await page.waitToClick($.moreMenu); + await page.waitToClick($.simpleTicketButton); await page.waitForState('ticket.create'); - }); - it('should check if the client details are the expected ones', async() => { - const client = await page - .waitToGetProperty(selectors.createTicketView.client, 'value'); + const values = { + client: 'Petter Parker', + address: 'Petter Parker' + }; + const formValues = await page.fetchForm($.form, Object.keys(values)); - const address = await page - .waitToGetProperty(selectors.createTicketView.address, 'value'); - - expect(client).toContain('Petter Parker'); - expect(address).toContain('20 Ingram Street'); + expect(formValues).toEqual(values); }); }); diff --git a/e2e/paths/05-ticket/17_log.spec.js b/e2e/paths/05-ticket/17_log.spec.js index 32829ee74..e1da2df44 100644 --- a/e2e/paths/05-ticket/17_log.spec.js +++ b/e2e/paths/05-ticket/17_log.spec.js @@ -31,30 +31,4 @@ describe('Ticket log path', () => { expect(message.text).toContain('Data saved!'); }); - - it('should navigate to the log section', async() => { - await page.accessToSection('ticket.card.log'); - }); - - it('should set the viewport width to 1920 to see the table full width', async() => { - await page.setViewport({ - width: 1920, - height: 0, - }); - - const result = await page.waitToGetProperty(selectors.ticketLog.firstTD, 'innerText'); - - expect(result.length).not.toBeGreaterThan('20'); - }); - - it('should set the viewport width to 800 to see the table shrink and move data to the 1st column', async() => { - await page.setViewport({ - width: 800, - height: 0, - }); - - const result = await page.waitToGetProperty(selectors.ticketLog.firstTD, 'innerText'); - - expect(result.length).toBeGreaterThan('15'); - }); }); diff --git a/e2e/paths/05-ticket/18_index_payout.spec.js b/e2e/paths/05-ticket/18_index_payout.spec.js index 220dacf61..7e5201d11 100644 --- a/e2e/paths/05-ticket/18_index_payout.spec.js +++ b/e2e/paths/05-ticket/18_index_payout.spec.js @@ -1,5 +1,10 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; +const $ = { + newPayment: '.vn-dialog.shown', + anyBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr', + firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable' +}; describe('Ticket index payout path', () => { let browser; @@ -8,17 +13,14 @@ describe('Ticket index payout path', () => { beforeAll(async() => { browser = await getBrowser(); page = browser.page; + await page.loginAndModule('administrative', 'ticket'); + await page.waitForState('ticket.index'); }); afterAll(async() => { await browser.close(); }); - it('should navigate to the ticket index', async() => { - await page.loginAndModule('administrative', 'ticket'); - await page.waitForState('ticket.index'); - }); - it('should check the second ticket from a client and 1 of another', async() => { await page.waitToClick(selectors.globalItems.searchButton); await page.waitToClick(selectors.ticketsIndex.thirdTicketCheckbox); @@ -42,27 +44,27 @@ describe('Ticket index payout path', () => { await page.waitForSelector(selectors.ticketsIndex.payoutCompany); }); - it('should fill the company and bank to perform a payout', async() => { - await page.autocompleteSearch(selectors.ticketsIndex.payoutCompany, 'VNL'); - await page.autocompleteSearch(selectors.ticketsIndex.payoutBank, 'cash'); - await page.write(selectors.clientBalance.newPaymentAmount, '100'); - await page.write(selectors.ticketsIndex.payoutDescription, 'Payment'); - await page.waitToClick(selectors.ticketsIndex.submitPayout); + it('should fill the company and bank to perform a payout and check a new balance line was entered', async() => { + await page.fillForm($.newPayment, { + company: 'VNL', + bank: 'cash', + amountPaid: 100, + description: 'Payment', + viewReceipt: false + }); + await page.respondToDialog('accept'); const message = await page.waitForSnackbar(); - expect(message.text).toContain('Data saved!'); - }); - - it('should navigate to the client balance section and check a new balance line was entered', async() => { await page.waitToClick(selectors.globalItems.homeButton); await page.selectModule('client'); await page.accessToSearchResult('1101'); await page.accessToSection('client.card.balance.index'); - await page.waitForSelector(selectors.clientBalance.anyBalanceLine); - const count = await page.countElement(selectors.clientBalance.anyBalanceLine); - const reference = await page.waitToGetProperty(selectors.clientBalance.firstLineReference, 'innerText'); + await page.waitForSelector($.anyBalanceLine); + const count = await page.countElement($.anyBalanceLine); + const reference = await page.innerText($.firstLineReference); + expect(message.isSuccess).toBeTrue(); expect(count).toEqual(4); - expect(reference).toContain('Cash, Albaran: 7, 8Payment'); + expect(reference).toContain('Payment'); }); }); diff --git a/e2e/paths/05-ticket/21_future.spec.js b/e2e/paths/05-ticket/21_future.spec.js index 3c52048c7..82525c1db 100644 --- a/e2e/paths/05-ticket/21_future.spec.js +++ b/e2e/paths/05-ticket/21_future.spec.js @@ -1,6 +1,7 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; -// https://redmine.verdnatura.es/issues/5616 + +// 'https:// redmine.verdnatura.es/issues/5642' xdescribe('Ticket Future path', () => { let browser; let page; @@ -44,94 +45,67 @@ xdescribe('Ticket Future path', () => { expect(message.text).toContain('originDated is a required argument'); }); - it('should search with the required data', async() => { - await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); - await page.waitToClick(selectors.ticketFuture.submit); + // it('should search with the required data', async() => { + // await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); + // await page.waitToClick(selectors.ticketFuture.submit); - expect(httpRequest).toBeDefined(); - }); + // expect(httpRequest).toBeDefined(); + // }); - it('should search with the origin IPT', async() => { - await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); + // it('should search with the origin IPT', async() => { + // await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); - await page.autocompleteSearch(selectors.ticketFuture.ipt, 'H'); - await page.waitToClick(selectors.ticketFuture.submit); + // await page.autocompleteSearch(selectors.ticketFuture.ipt, 'H'); + // await page.waitToClick(selectors.ticketFuture.submit); - expect(httpRequest).toContain('ipt=H'); - }); + // expect(httpRequest).toContain('ipt=H'); + // }); - it('should search with the destination IPT', async() => { - await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); + // it('should search with the destination IPT', async() => { + // await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); - await page.clearInput(selectors.ticketFuture.ipt); + // await page.clearInput(selectors.ticketFuture.ipt); - await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'H'); - await page.waitToClick(selectors.ticketFuture.submit); + // await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'H'); + // await page.waitToClick(selectors.ticketFuture.submit); - expect(httpRequest).toContain('futureIpt=H'); - }); + // expect(httpRequest).toContain('futureIpt=H'); + // }); - it('should search with the origin grouped state', async() => { - await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); + // it('should search with the origin grouped state', async() => { + // await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); - await page.clearInput(selectors.ticketFuture.futureIpt); + // await page.clearInput(selectors.ticketFuture.futureIpt); - await page.autocompleteSearch(selectors.ticketFuture.state, 'Free'); - await page.waitToClick(selectors.ticketFuture.submit); + // await page.autocompleteSearch(selectors.ticketFuture.state, 'Free'); + // await page.waitToClick(selectors.ticketFuture.submit); - expect(httpRequest).toContain('state=FREE'); - }); + // expect(httpRequest).toContain('state=FREE'); + // }); - it('should search with the destination grouped state', async() => { - await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); + // it('should search with the destination grouped state', async() => { + // await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); - await page.clearInput(selectors.ticketFuture.state); + // await page.clearInput(selectors.ticketFuture.state); - await page.autocompleteSearch(selectors.ticketFuture.futureState, 'Free'); - await page.waitToClick(selectors.ticketFuture.submit); + // await page.autocompleteSearch(selectors.ticketFuture.futureState, 'Free'); + // await page.waitToClick(selectors.ticketFuture.submit); - expect(httpRequest).toContain('futureState=FREE'); + // expect(httpRequest).toContain('futureState=FREE'); - await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); - await page.clearInput(selectors.ticketFuture.futureState); - await page.waitToClick(selectors.ticketFuture.submit); - }); + // await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); + // await page.clearInput(selectors.ticketFuture.futureState); + // await page.waitToClick(selectors.ticketFuture.submit); + // }); - it('should search in smart-table with an ID Origin', async() => { - await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - await page.write(selectors.ticketFuture.tableId, '1'); - await page.keyboard.press('Enter'); + // it('should check the three last tickets and move to the future', async() => { + // await page.waitForNumberOfElements(selectors.ticketFuture.searchResult, 4); + // await page.waitToClick(selectors.ticketFuture.multiCheck); + // await page.waitToClick(selectors.ticketFuture.firstCheck); + // await page.waitToClick(selectors.ticketFuture.moveButton); + // await page.waitToClick(selectors.globalItems.acceptButton); + // const message = await page.waitForSnackbar(); - expect(httpRequest).toContain('id'); - await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - }); - - it('should search in smart-table with an IPT Destination', async() => { - await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - await page.autocompleteSearch(selectors.ticketFuture.tableFutureIpt, 'H'); - - expect(httpRequest).toContain('futureIpt'); - await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - }); - - it('should search in smart-table with an ID Destination', async() => { - await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - await page.write(selectors.ticketFuture.tableFutureId, '1'); - await page.keyboard.press('Enter'); - - expect(httpRequest).toContain('futureId'); - await page.waitToClick(selectors.ticketFuture.tableButtonSearch); - await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton); - await page.waitToClick(selectors.ticketFuture.submit); - }); - - it('should check the three last tickets and move to the future', async() => { - await page.waitToClick(selectors.ticketFuture.multiCheck); - await page.waitToClick(selectors.ticketFuture.firstCheck); - await page.waitToClick(selectors.ticketFuture.moveButton); - await page.waitToClick(selectors.ticketFuture.acceptButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Tickets moved successfully!'); - }); + // expect(message.text).toContain('Tickets moved successfully!'); + // }); }); diff --git a/e2e/paths/05-ticket/22_advance.spec.js b/e2e/paths/05-ticket/22_advance.spec.js index f8626d56d..f27120b3b 100644 --- a/e2e/paths/05-ticket/22_advance.spec.js +++ b/e2e/paths/05-ticket/22_advance.spec.js @@ -1,6 +1,7 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; -// https://redmine.verdnatura.es/issues/5616 + +// 'https:// redmine.verdnatura.es/issues/5642' xdescribe('Ticket Advance path', () => { let browser; let page; @@ -45,65 +46,43 @@ xdescribe('Ticket Advance path', () => { expect(message.text).toContain('dateFuture is a required argument'); }); - it('should search with the required data', async() => { - await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); - await page.waitToClick(selectors.ticketAdvance.submit); + // it('should search with the required data', async() => { + // await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); + // await page.waitToClick(selectors.ticketAdvance.submit); - expect(httpRequest).toBeDefined(); - }); + // expect(httpRequest).toBeDefined(); + // }); - it('should search with the origin IPT', async() => { - await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); - await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'H'); - await page.waitToClick(selectors.ticketAdvance.submit); + // it('should search with the origin IPT', async() => { + // await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); + // await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'H'); + // await page.waitToClick(selectors.ticketAdvance.submit); - expect(httpRequest).toContain('futureIpt=H'); + // expect(httpRequest).toContain('futureIpt=H'); - await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); - await page.clearInput(selectors.ticketAdvance.futureIpt); - await page.waitToClick(selectors.ticketAdvance.submit); - }); + // await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); + // await page.clearInput(selectors.ticketAdvance.futureIpt); + // await page.waitToClick(selectors.ticketAdvance.submit); + // }); - it('should search with the destination IPT', async() => { - await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); - await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'H'); - await page.waitToClick(selectors.ticketAdvance.submit); + // it('should search with the destination IPT', async() => { + // await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); + // await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'H'); + // await page.waitToClick(selectors.ticketAdvance.submit); - expect(httpRequest).toContain('ipt=H'); + // expect(httpRequest).toContain('ipt=H'); - await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); - await page.clearInput(selectors.ticketAdvance.ipt); - await page.waitToClick(selectors.ticketAdvance.submit); - }); + // await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); + // await page.clearInput(selectors.ticketAdvance.ipt); + // await page.waitToClick(selectors.ticketAdvance.submit); + // }); - it('should search in smart-table with an IPT Origin', async() => { - await page.waitToClick(selectors.ticketAdvance.tableButtonSearch); - await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'V'); + // it('should check the first ticket and move to the present', async() => { + // await page.waitToClick(selectors.ticketAdvance.firstCheck); + // await page.waitToClick(selectors.ticketAdvance.moveButton); + // await page.waitToClick(selectors.ticketAdvance.acceptButton); + // const message = await page.waitForSnackbar(); - expect(httpRequest).toContain('futureIpt'); - - await page.waitToClick(selectors.ticketAdvance.tableButtonSearch); - await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); - await page.waitToClick(selectors.ticketAdvance.submit); - }); - - it('should search in smart-table with an IPT Destination', async() => { - await page.waitToClick(selectors.ticketAdvance.tableButtonSearch); - await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'V'); - - expect(httpRequest).toContain('ipt'); - - await page.waitToClick(selectors.ticketAdvance.tableButtonSearch); - await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton); - await page.waitToClick(selectors.ticketAdvance.submit); - }); - - it('should check the first ticket and move to the present', async() => { - await page.waitToClick(selectors.ticketAdvance.firstCheck); - await page.waitToClick(selectors.ticketAdvance.moveButton); - await page.waitToClick(selectors.ticketAdvance.acceptButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Tickets moved successfully!'); - }); + // expect(message.text).toContain('Tickets moved successfully!'); + // }); }); diff --git a/e2e/paths/07-order/01_summary.spec.js b/e2e/paths/07-order/01_summary.spec.js index 922d5eeee..9df481ef6 100644 --- a/e2e/paths/07-order/01_summary.spec.js +++ b/e2e/paths/07-order/01_summary.spec.js @@ -1,6 +1,15 @@ -import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; +const $ = { + id: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(1) span', + alias: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(2) span', + consignee: 'vn-order-summary vn-one:nth-child(2) > vn-label-value:nth-child(6) span', + subtotal: 'vn-order-summary vn-one.taxes > p:nth-child(1)', + vat: 'vn-order-summary vn-one.taxes > p:nth-child(2)', + total: 'vn-order-summary vn-one.taxes > p:nth-child(3)', + sale: 'vn-order-summary vn-tbody > vn-tr', +}; + describe('Order summary path', () => { let browser; let page; @@ -15,49 +24,23 @@ describe('Order summary path', () => { await browser.close(); }); - it('should reach the order summary section', async() => { + it('should reach the order summary section and check data', async() => { await page.waitForState('order.card.summary'); - }); - it('should check the summary contains the order id', async() => { - const result = await page.waitToGetProperty(selectors.orderSummary.id, 'innerText'); + const id = await page.innerText($.id); + const alias = await page.innerText($.alias); + const consignee = await page.innerText($.consignee); + const subtotal = await page.innerText($.subtotal); + const vat = await page.innerText($.vat); + const total = await page.innerText($.total); + const sale = await page.countElement($.sale); - expect(result).toEqual('16'); - }); - - it('should check the summary contains the order alias', async() => { - const result = await page.waitToGetProperty(selectors.orderSummary.alias, 'innerText'); - - expect(result).toEqual('Many places'); - }); - - it('should check the summary contains the order consignee', async() => { - const result = await page.waitToGetProperty(selectors.orderSummary.consignee, 'innerText'); - - expect(result).toEqual('address 26 - Gotham (Province one)'); - }); - - it('should check the summary contains the order subtotal', async() => { - const result = await page.waitToGetProperty(selectors.orderSummary.subtotal, 'innerText'); - - expect(result.length).toBeGreaterThan(1); - }); - - it('should check the summary contains the order vat', async() => { - const result = await page.waitToGetProperty(selectors.orderSummary.vat, 'innerText'); - - expect(result.length).toBeGreaterThan(1); - }); - - it('should check the summary contains the order total', async() => { - const result = await page.waitToGetProperty(selectors.orderSummary.total, 'innerText'); - - expect(result.length).toBeGreaterThan(1); - }); - - it('should check the summary contains the order sales', async() => { - const result = await page.countElement(selectors.orderSummary.sale); - - expect(result).toBeGreaterThan(0); + expect(id).toEqual('16'); + expect(alias).toEqual('Many places'); + expect(consignee).toEqual('address 26 - Gotham (Province one)'); + expect(subtotal.length).toBeGreaterThan(1); + expect(vat.length).toBeGreaterThan(1); + expect(total.length).toBeGreaterThan(1); + expect(sale).toBeGreaterThan(0); }); }); diff --git a/e2e/paths/07-order/02_basic_data.spec.js b/e2e/paths/07-order/02_basic_data.spec.js index 90eaf269e..b2c21b071 100644 --- a/e2e/paths/07-order/02_basic_data.spec.js +++ b/e2e/paths/07-order/02_basic_data.spec.js @@ -1,6 +1,13 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; +const $ = { + form: 'vn-order-basic-data form', + observation: 'vn-order-basic-data form [vn-name="note"]', + saveButton: `vn-order-basic-data form button[type=submit]`, + acceptButton: '.vn-confirm.shown button[response="accept"]' +}; + describe('Order edit basic data path', () => { let browser; let page; @@ -20,90 +27,43 @@ describe('Order edit basic data path', () => { describe('when confirmed order', () => { it('should not be able to change the client', async() => { - await page.autocompleteSearch(selectors.orderBasicData.client, 'Tony Stark'); - await page.autocompleteSearch(selectors.orderBasicData.address, 'Tony Stark'); - await page.waitToClick(selectors.orderBasicData.saveButton); - const message = await page.waitForSnackbar(); + const message = await page.sendForm($.form, { + client: 'Tony Stark', + address: 'Tony Stark', + }); - expect(message.text).toContain(`You can't make changes on the basic data of an confirmed order or with rows`); - }); - }); - - describe('when order with rows', () => { - it('should now navigate to order index', async() => { - const orderId = '16'; - - await page.waitToClick(selectors.orderDescriptor.returnToModuleIndexButton); - await page.waitToClick(selectors.globalItems.acceptButton); - await page.waitForContentLoaded(); - await page.accessToSearchResult(orderId); - await page.accessToSection('order.card.basicData'); - await page.waitForSelector(selectors.orderBasicData.observation, {visible: true}); - await page.waitForState('order.card.basicData'); - }); - - it('should not be able to change anything', async() => { - await page.write(selectors.orderBasicData.observation, 'observation'); - await page.waitToClick(selectors.orderBasicData.saveButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain(`You can't make changes on the basic data of an confirmed order or with rows`); + expect(message.text).toContain(`You can't make changes on the basic data`); }); }); describe('when new order', () => { - it('should navigate to the order index and click the new order button', async() => { + it('should create an order and edit its basic data', async() => { await page.waitToClick(selectors.globalItems.returnToModuleIndexButton); - await page.waitToClick(selectors.orderBasicData.acceptButton); + await page.waitToClick($.acceptButton); await page.waitForContentLoaded(); await page.waitToClick(selectors.ordersIndex.createOrderButton); await page.waitForState('order.create'); - }); - it('should now create a new one', async() => { await page.autocompleteSearch(selectors.createOrderView.client, 'Jessica Jones'); await page.pickDate(selectors.createOrderView.landedDatePicker); await page.autocompleteSearch(selectors.createOrderView.agency, 'Other agency'); await page.waitToClick(selectors.createOrderView.createButton); await page.waitForState('order.card.catalog'); - }); - it('should navigate to the basic data section of the new order', async() => { await page.accessToSection('order.card.basicData'); - await page.waitForState('order.card.basicData'); - }); - it('should be able to modify all the properties', async() => { - await page.autocompleteSearch(selectors.orderBasicData.client, 'Tony Stark'); - await page.autocompleteSearch(selectors.orderBasicData.address, 'Tony Stark'); - await page.autocompleteSearch(selectors.orderBasicData.agency, 'Other agency'); - await page.write(selectors.orderBasicData.observation, 'my observation'); - await page.waitToClick(selectors.orderBasicData.saveButton); - const message = await page.waitForSnackbar(); + const values = { + client: 'Tony Stark', + address: 'Tony Stark', + agencyMode: 'Other agency' + }; - expect(message.text).toContain('Data saved!'); - }); - - it('should now confirm the client have been edited', async() => { + const message = await page.sendForm($.form, values); await page.reloadSection('order.card.basicData'); - const result = await page - .waitToGetProperty(selectors.orderBasicData.client, 'value'); + const formValues = await page.fetchForm($.form, Object.keys(values)); - expect(result).toEqual('1104: Tony Stark'); - }); - - it('should now confirm the agency have been edited', async() => { - const result = await page - .waitToGetProperty(selectors.orderBasicData.agency, 'value'); - - expect(result).toEqual('Other agency'); - }); - - it('should now confirm the observations have been edited', async() => { - const result = await page - .waitToGetProperty(selectors.orderBasicData.observation, 'value'); - - expect(result).toEqual('my observation'); + expect(message.isSuccess).toBeTrue(); + expect(formValues).toEqual(values); }); }); }); diff --git a/e2e/paths/08-route/02_basic_data.spec.js b/e2e/paths/08-route/02_basic_data.spec.js index ff8361499..7ab7dda42 100644 --- a/e2e/paths/08-route/02_basic_data.spec.js +++ b/e2e/paths/08-route/02_basic_data.spec.js @@ -1,4 +1,3 @@ -import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; describe('Route basic Data path', () => { @@ -17,47 +16,27 @@ describe('Route basic Data path', () => { await browser.close(); }); - it('should edit the route basic data', async() => { + it('should edit the route basic data and confirm the route was edited', async() => { const nextMonth = Date.vnNew(); nextMonth.setMonth(nextMonth.getMonth() + 1); + nextMonth.setUTCHours(0, 0, 0, 0); - await page.autocompleteSearch(selectors.routeBasicData.worker, 'adminBossNick'); - await page.autocompleteSearch(selectors.routeBasicData.vehicle, '1111-IMK'); - await page.pickDate(selectors.routeBasicData.createdDate, nextMonth); - await page.clearInput(selectors.routeBasicData.kmStart); - await page.write(selectors.routeBasicData.kmStart, '1'); - await page.clearInput(selectors.routeBasicData.kmEnd); - await page.write(selectors.routeBasicData.kmEnd, '2'); - await page.type(`${selectors.routeBasicData.startedHour} input`, '0800'); - await page.type(`${selectors.routeBasicData.finishedHour} input`, '1230'); - await page.waitToClick(selectors.routeBasicData.saveButton); - const message = await page.waitForSnackbar(); + const form = 'vn-route-basic-data form'; + const values = { + worker: 'adminBossNick', + vehicle: '1111-IMK', + created: nextMonth, + kmStart: 1, + kmEnd: 2, + started: '08:00', + finished: '12:30', + }; - expect(message.text).toContain('Data saved!'); - }); - - it('should confirm the worker was edited', async() => { + const message = await page.sendForm(form, values); await page.reloadSection('route.card.basicData'); - const worker = await page.waitToGetProperty(selectors.routeBasicData.worker, 'value'); + const formValues = await page.fetchForm(form, Object.keys(values)); - expect(worker).toEqual('adminBoss - adminBossNick'); - }); - - it('should confirm the vehicle was edited', async() => { - const vehicle = await page.waitToGetProperty(selectors.routeBasicData.vehicle, 'value'); - - expect(vehicle).toEqual('1111-IMK'); - }); - - it('should confirm the km start was edited', async() => { - const kmStart = await page.waitToGetProperty(selectors.routeBasicData.kmStart, 'value'); - - expect(kmStart).toEqual('1'); - }); - - it('should confirm the km end was edited', async() => { - const kmEnd = await page.waitToGetProperty(selectors.routeBasicData.kmEnd, 'value'); - - expect(kmEnd).toEqual('2'); + expect(message.isSuccess).toBeTrue(); + expect(formValues).toEqual(values); }); }); diff --git a/e2e/paths/08-route/04_tickets.spec.js b/e2e/paths/08-route/04_tickets.spec.js index 950e11d3e..ccd5562c2 100644 --- a/e2e/paths/08-route/04_tickets.spec.js +++ b/e2e/paths/08-route/04_tickets.spec.js @@ -57,11 +57,4 @@ describe('Route tickets path', () => { it('should now count how many tickets are in route to find one less', async() => { await page.waitForNumberOfElements(selectors.routeTickets.anyTicket, 0); }); - - // #2862 updateVolume() route descriptor no actualiza volumen - xit('should confirm the route volume on the descriptor has been updated by the changes made', async() => { - const result = await page.waitToGetProperty(selectors.routeDescriptor.volume, 'innerText'); - - expect(result).toEqual('0 / 50 m³'); - }); }); diff --git a/e2e/paths/09-invoice-in/04_tax.spec.js b/e2e/paths/09-invoice-in/04_tax.spec.js index b1dbe2008..d51c39048 100644 --- a/e2e/paths/09-invoice-in/04_tax.spec.js +++ b/e2e/paths/09-invoice-in/04_tax.spec.js @@ -17,55 +17,36 @@ describe('InvoiceIn tax path', () => { await browser.close(); }); - it('should add a new tax', async() => { + it('should add a new tax and check it', async() => { await page.waitToClick(selectors.invoiceInTax.addTaxButton); await page.autocompleteSearch(selectors.invoiceInTax.thirdExpense, '6210000567'); await page.write(selectors.invoiceInTax.thirdTaxableBase, '100'); - await page.autocompleteSearch(selectors.invoiceInTax.thirdTaxType, '6'); + await page.autocompleteSearch(selectors.invoiceInTax.thirdTaxType, 'H.P. IVA'); await page.autocompleteSearch(selectors.invoiceInTax.thirdTransactionType, 'Operaciones exentas'); await page.waitToClick(selectors.invoiceInTax.saveButton); const message = await page.waitForSnackbar(); - expect(message.text).toContain('Data saved!'); - }); - - it('should navigate to the summary and check the taxable base sum is correct', async() => { await page.waitToClick(selectors.invoiceInDescriptor.summaryIcon); await page.waitForState('invoiceIn.card.summary'); - const result = await page.waitToGetProperty(selectors.invoiceInSummary.totalTaxableBase, 'innerText'); + const total = await page.waitToGetProperty(selectors.invoiceInSummary.totalTaxableBase, 'innerText'); - expect(result).toEqual('Taxable base €1,323.16'); - }); - - it('should navigate back to tax section, check the reciently added line contains the expected expense', async() => { await page.accessToSection('invoiceIn.card.tax'); - const result = await page.waitToGetProperty(selectors.invoiceInTax.thirdExpense, 'value'); - expect(result).toEqual('6210000567: Alquiler VNH'); - }); + const thirdExpense = await page.waitToGetProperty(selectors.invoiceInTax.thirdExpense, 'value'); + const thirdTaxableBase = await page.waitToGetProperty(selectors.invoiceInTax.thirdTaxableBase, 'value'); + const thirdTaxType = await page.waitToGetProperty(selectors.invoiceInTax.thirdTaxType, 'value'); + const thirdTransactionType = await page.waitToGetProperty(selectors.invoiceInTax.thirdTransactionType, 'value'); + const thirdRate = await page.waitToGetProperty(selectors.invoiceInTax.thirdRate, 'value'); - it('should check the reciently added line contains the expected taxable base', async() => { - const result = await page.waitToGetProperty(selectors.invoiceInTax.thirdTaxableBase, 'value'); + expect(message.text).toContain('Data saved!'); - expect(result).toEqual('100'); - }); + expect(total).toEqual('Taxable base €1,323.16'); - it('should check the reciently added line contains the expected tax type', async() => { - const result = await page.waitToGetProperty(selectors.invoiceInTax.thirdTaxType, 'value'); - - expect(result).toEqual('6: H.P. IVA 4% CEE'); - }); - - it('should check the reciently added line contains the expected transaction type', async() => { - const result = await page.waitToGetProperty(selectors.invoiceInTax.thirdTransactionType, 'value'); - - expect(result).toEqual('37: Operaciones exentas'); - }); - - it('should check the reciently added line contains the expected rate', async() => { - const result = await page.waitToGetProperty(selectors.invoiceInTax.thirdRate, 'value'); - - expect(result).toEqual('€4.00'); + expect(thirdExpense).toEqual('6210000567'); + expect(thirdTaxableBase).toEqual('100'); + expect(thirdTaxType).toEqual('H.P. IVA 4% CEE'); + expect(thirdTransactionType).toEqual('Operaciones exentas'); + expect(thirdRate).toEqual('€4.00'); }); it('should delete the added line', async() => { diff --git a/e2e/paths/09-invoice-in/05_serial.spec.js b/e2e/paths/09-invoice-in/05_serial.spec.js index 3aa94f48c..8be5660da 100644 --- a/e2e/paths/09-invoice-in/05_serial.spec.js +++ b/e2e/paths/09-invoice-in/05_serial.spec.js @@ -35,7 +35,7 @@ describe('InvoiceIn serial path', () => { }); it('should go to index and check if the search-panel has the correct params', async() => { - await page.click(selectors.invoiceInSerial.goToIndex); + await page.waitToClick(selectors.invoiceInSerial.goToIndex); const params = await page.$$(selectors.invoiceInIndex.topbarSearchParams); const serial = await params[0].getProperty('title'); const isBooked = await params[1].getProperty('title'); diff --git a/e2e/paths/09-invoice-out/03_manualInvoice.spec.js b/e2e/paths/09-invoice-out/03_manualInvoice.spec.js index abb9ca7e7..dfaa55ef9 100644 --- a/e2e/paths/09-invoice-out/03_manualInvoice.spec.js +++ b/e2e/paths/09-invoice-out/03_manualInvoice.spec.js @@ -15,49 +15,39 @@ describe('InvoiceOut manual invoice path', () => { await browser.close(); }); - it('should open the manual invoice form', async() => { + it('should create an invoice from a ticket', async() => { await page.waitToClick(selectors.invoiceOutIndex.createInvoice); await page.waitForSelector(selectors.invoiceOutIndex.manualInvoiceForm); - }); - it('should create an invoice from a ticket', async() => { await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceTicket, '15'); await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceSerial, 'Global nacional'); await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceTaxArea, 'national'); await page.waitToClick(selectors.invoiceOutIndex.saveInvoice); const message = await page.waitForSnackbar(); + await page.waitForState('invoiceOut.card.summary'); + expect(message.text).toContain('Data saved!'); }); - it(`should have been redirected to the created invoice summary`, async() => { - await page.waitForState('invoiceOut.card.summary'); - }); - - it(`should navigate back to the invoiceOut index`, async() => { + it(`should create another invoice from a client`, async() => { await page.waitToClick(selectors.globalItems.applicationsMenuButton); await page.waitForSelector(selectors.globalItems.applicationsMenuVisible); await page.waitToClick(selectors.globalItems.invoiceOutButton); await page.waitForSelector(selectors.invoiceOutIndex.topbarSearch); await page.waitForState('invoiceOut.index'); - }); - it('should now open the manual invoice form', async() => { await page.waitToClick(selectors.invoiceOutIndex.createInvoice); await page.waitForSelector(selectors.invoiceOutIndex.manualInvoiceForm); - }); - it('should create an invoice from a client', async() => { await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceClient, 'Max Eisenhardt'); await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceSerial, 'Global nacional'); await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceTaxArea, 'national'); await page.waitToClick(selectors.invoiceOutIndex.saveInvoice); const message = await page.waitForSnackbar(); + await page.waitForState('invoiceOut.card.summary'); + expect(message.text).toContain('Data saved!'); }); - - it(`should have been redirected to the created invoice summary`, async() => { - await page.waitForState('invoiceOut.card.summary'); - }); }); diff --git a/e2e/paths/09-invoice-out/04_globalInvoice.spec.js b/e2e/paths/09-invoice-out/04_globalInvoice.spec.js index 23aa3593c..64cddfa25 100644 --- a/e2e/paths/09-invoice-out/04_globalInvoice.spec.js +++ b/e2e/paths/09-invoice-out/04_globalInvoice.spec.js @@ -18,7 +18,6 @@ describe('InvoiceOut global invoice path', () => { }); let invoicesBeforeOneClient; - let invoicesBeforeAllClients; let now = Date.vnNew(); it('should count the amount of invoices listed before globla invoces are made', async() => { @@ -27,13 +26,10 @@ describe('InvoiceOut global invoice path', () => { expect(invoicesBeforeOneClient).toBeGreaterThanOrEqual(4); }); - it('should open the global invoice form', async() => { - await page.accessToSection('invoiceOut.global-invoicing'); - }); - it('should create a global invoice for charles xavier today', async() => { + await page.accessToSection('invoiceOut.global-invoicing'); await page.waitToClick(selectors.invoiceOutGlobalInvoicing.oneClient); - await page.autocompleteSearch(selectors.invoiceOutGlobalInvoicing.clientId, '1108'); + await page.autocompleteSearch(selectors.invoiceOutGlobalInvoicing.clientId, 'Charles Xavier'); await page.pickDate(selectors.invoiceOutGlobalInvoicing.invoiceDate, now); await page.pickDate(selectors.invoiceOutGlobalInvoicing.maxShipped, now); await page.autocompleteSearch(selectors.invoiceOutGlobalInvoicing.printer, '1'); diff --git a/e2e/paths/10-travel/01_create.spec.js b/e2e/paths/10-travel/01_create.spec.js index 15da42d5d..98ade4852 100644 --- a/e2e/paths/10-travel/01_create.spec.js +++ b/e2e/paths/10-travel/01_create.spec.js @@ -4,9 +4,6 @@ import getBrowser from '../../helpers/puppeteer'; describe('Travel create path', () => { let browser; let page; - const date = Date.vnNew(); - const day = 15; - date.setDate(day); beforeAll(async() => { browser = await getBrowser(); @@ -18,60 +15,28 @@ describe('Travel create path', () => { await browser.close(); }); - it('should open the create travel form by clicking on the "new" button', async() => { + it('should create a new travel and check it was created with the correct data', async() => { + const date = Date.vnNew(); + date.setDate(15); + date.setUTCHours(0, 0, 0, 0); + await page.waitToClick(selectors.travelIndex.newTravelButton); await page.waitForState('travel.create'); - }); - it('should fill the reference, agency and ship date then save the form', async() => { - await page.write(selectors.travelIndex.reference, 'Testing reference'); - await page.autocompleteSearch(selectors.travelIndex.agency, 'inhouse pickup'); - await page.pickDate(selectors.travelIndex.shipDate, date); // this line autocompletes another 3 fields - await page.waitForTimeout(1000); - await page.waitToClick(selectors.travelIndex.save); + const values = { + reference: 'Testing reference', + agencyMode: 'inhouse pickup', + shipped: date, + landed: date, + warehouseOut: 'Warehouse One', + warehouseIn: 'Warehouse Five' + }; - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it('should check the user was redirected to the travel basic data upon creation', async() => { + const message = await page.sendForm('vn-travel-create form', values); await page.waitForState('travel.card.basicData'); - }); + const formValues = await page.fetchForm('vn-travel-basic-data form', Object.keys(values)); - it('should check the travel was created with the correct reference', async() => { - const reference = await page.waitToGetProperty(selectors.travelBasicData.reference, 'value'); - - expect(reference).toContain('Testing reference'); - }); - - it('should check the travel was created with the correct agency', async() => { - const agency = await page.waitToGetProperty(selectors.travelBasicData.agency, 'value'); - - expect(agency).toContain('inhouse pickup'); - }); - - it('should check the travel was created with the correct shiping date', async() => { - const shipDate = await page.waitToGetProperty(selectors.travelBasicData.shippedDate, 'value'); - - expect(shipDate).toContain(day); - }); - - it('should check the travel was created with the correct landing date', async() => { - const landingDate = await page.waitToGetProperty(selectors.travelBasicData.deliveryDate, 'value'); - - expect(landingDate).toContain(day); - }); - - it('should check the travel was created with the correct warehouseOut', async() => { - const warehouseOut = await page.waitToGetProperty(selectors.travelBasicData.outputWarehouse, 'value'); - - expect(warehouseOut).toContain('Warehouse One'); - }); - - it('should check the travel was created with the correct warehouseIn', async() => { - const warehouseIn = await page.waitToGetProperty(selectors.travelBasicData.inputWarehouse, 'value'); - - expect(warehouseIn).toContain('Warehouse Five'); + expect(message.isSuccess).toBeTrue(); + expect(formValues).toEqual(values); }); }); diff --git a/e2e/paths/11-zone/02_descriptor.spec.js b/e2e/paths/11-zone/02_descriptor.spec.js index 12a1c8f68..f3c0e7740 100644 --- a/e2e/paths/11-zone/02_descriptor.spec.js +++ b/e2e/paths/11-zone/02_descriptor.spec.js @@ -29,14 +29,4 @@ describe('Zone descriptor path', () => { expect(count).toEqual(0); }); - - it('should check the ticket whom lost the zone and see evidence on the logs', async() => { - await page.waitToClick(selectors.globalItems.homeButton); - await page.selectModule('ticket'); - await page.accessToSearchResult('20'); - await page.accessToSection('ticket.card.log'); - const lastChanges = await page.waitToGetProperty(selectors.ticketLog.changes, 'innerText'); - - expect(lastChanges).toContain('1'); - }); }); diff --git a/e2e/paths/12-entry/03_latestBuys.spec.js b/e2e/paths/12-entry/03_latestBuys.spec.js index a73e12659..9ec072912 100644 --- a/e2e/paths/12-entry/03_latestBuys.spec.js +++ b/e2e/paths/12-entry/03_latestBuys.spec.js @@ -42,20 +42,6 @@ describe('Entry lastest buys path', () => { expect(httpRequests.find(req => req.includes(('typeFk')))).toBeDefined(); }); - it('should filter by from date', async() => { - await page.pickDate(selectors.entryLatestBuys.fromInput, new Date()); - await page.waitToClick(selectors.entryLatestBuys.chip); - - expect(httpRequests.find(req => req.includes(('from')))).toBeDefined(); - }); - - it('should filter by to date', async() => { - await page.pickDate(selectors.entryLatestBuys.toInput, new Date()); - await page.waitToClick(selectors.entryLatestBuys.chip); - - expect(httpRequests.find(req => req.includes(('to')))).toBeDefined(); - }); - it('should filter by sales person', async() => { await page.autocompleteSearch(selectors.entryLatestBuys.salesPersonInput, 'buyerNick'); await page.waitToClick(selectors.entryLatestBuys.chip); diff --git a/e2e/paths/12-entry/04_create.spec.js b/e2e/paths/12-entry/04_create.spec.js index 20fa6b23d..537637671 100644 --- a/e2e/paths/12-entry/04_create.spec.js +++ b/e2e/paths/12-entry/04_create.spec.js @@ -21,8 +21,8 @@ describe('Entry create path', () => { }); it('should fill the form to create a valid entry then redirect to basic Data', async() => { - await page.autocompleteSearch(selectors.entryIndex.newEntrySupplier, '2'); - await page.autocompleteSearch(selectors.entryIndex.newEntryTravel, 'Warehouse Three'); + await page.autocompleteSearch(selectors.entryIndex.newEntrySupplier, 'The farmer'); + await page.autocompleteSearch(selectors.entryIndex.newEntryTravel, 'Warehouse'); await page.autocompleteSearch(selectors.entryIndex.newEntryCompany, 'ORN'); await page.waitToClick(selectors.entryIndex.saveNewEntry); diff --git a/e2e/paths/12-entry/05_basicData.spec.js b/e2e/paths/12-entry/05_basicData.spec.js index 3b5f40c35..15282820e 100644 --- a/e2e/paths/12-entry/05_basicData.spec.js +++ b/e2e/paths/12-entry/05_basicData.spec.js @@ -1,6 +1,22 @@ -import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; +const $ = { + reference: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.reference"]', + invoiceNumber: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.invoiceNumber"]', + notes: 'vn-entry-basic-data vn-textfield[ng-model="$ctrl.entry.notes"]', + observations: 'vn-entry-basic-data vn-textarea[ng-model="$ctrl.entry.observation"]', + supplier: 'vn-entry-basic-data vn-autocomplete[ng-model="$ctrl.entry.supplierFk"]', + currency: 'vn-entry-basic-data vn-autocomplete[ng-model="$ctrl.entry.currencyFk"]', + commission: 'vn-entry-basic-data vn-input-number[ng-model="$ctrl.entry.commission"]', + company: 'vn-entry-basic-data vn-autocomplete[ng-model="$ctrl.entry.companyFk"]', + ordered: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isOrdered"]', + confirmed: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isConfirmed"]', + inventory: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isExcludedFromAvailable"]', + raid: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isRaid"]', + booked: 'vn-entry-basic-data vn-check[ng-model="$ctrl.entry.isBooked"]', + save: 'vn-entry-basic-data button[type=submit]', +}; + describe('Entry basic data path', () => { let browser; let page; @@ -17,105 +33,49 @@ describe('Entry basic data path', () => { await browser.close(); }); - it('should edit the basic data', async() => { - await page.write(selectors.entryBasicData.reference, 'new movement 8'); - await page.write(selectors.entryBasicData.invoiceNumber, 'new movement 8'); - await page.write(selectors.entryBasicData.notes, 'new notes'); - await page.write(selectors.entryBasicData.observations, ' edited'); - await page.autocompleteSearch(selectors.entryBasicData.supplier, 'Plants nick'); - await page.autocompleteSearch(selectors.entryBasicData.currency, 'eur'); - await page.clearInput(selectors.entryBasicData.commission); - await page.write(selectors.entryBasicData.commission, '100'); - await page.autocompleteSearch(selectors.entryBasicData.company, 'CCs'); - await page.waitToClick(selectors.entryBasicData.ordered); - await page.waitToClick(selectors.entryBasicData.confirmed); - await page.waitToClick(selectors.entryBasicData.inventory); - await page.waitToClick(selectors.entryBasicData.raid); - await page.waitToClick(selectors.entryBasicData.booked); - await page.waitToClick(selectors.entryBasicData.save); - + it('should edit the basic data and confirm the reference was edited', async() => { + await page.write($.reference, 'new movement 8'); + await page.write($.invoiceNumber, 'new movement 8'); + await page.write($.observations, ' edited'); + await page.autocompleteSearch($.supplier, 'Plants nick'); + await page.autocompleteSearch($.currency, 'eur'); + await page.clearInput($.commission); + await page.write($.commission, '100'); + await page.autocompleteSearch($.company, 'CCs'); + await page.waitToClick($.ordered); + await page.waitToClick($.confirmed); + await page.waitToClick($.inventory); + await page.waitToClick($.raid); + await page.waitToClick($.booked); + await page.waitToClick($.save); const message = await page.waitForSnackbar(); + await page.reloadSection('entry.card.basicData'); + const reference = await page.waitToGetProperty($.reference, 'value'); + const supplier = await page.waitToGetProperty($.supplier, 'value'); + const invoiceNumber = await page.waitToGetProperty($.invoiceNumber, 'value'); + const observations = await page.waitToGetProperty($.observations, 'value'); + const currency = await page.waitToGetProperty($.currency, 'value'); + const commission = await page.waitToGetProperty($.commission, 'value'); + const company = await page.waitToGetProperty($.company, 'value'); + const ordered = await page.checkboxState($.ordered); + const confirmed = await page.checkboxState($.confirmed); + const inventory = await page.checkboxState($.inventory); + const raid = await page.checkboxState($.raid); + const booked = await page.checkboxState($.booked); + expect(message.text).toContain('Data saved!'); - }); - - it('should confirm the reference was edited', async() => { - await page.reloadSection('entry.card.basicData'); - const result = await page.waitToGetProperty(selectors.entryBasicData.reference, 'value'); - - expect(result).toEqual('new movement 8'); - }); - - it('should confirm the invoiceNumber was edited', async() => { - await page.reloadSection('entry.card.basicData'); - const result = await page.waitToGetProperty(selectors.entryBasicData.invoiceNumber, 'value'); - - expect(result).toEqual('new movement 8'); - }); - - it('should confirm the note was edited', async() => { - const result = await page.waitToGetProperty(selectors.entryBasicData.notes, 'value'); - - expect(result).toEqual('new notes'); - }); - - it('should confirm the observation was edited', async() => { - const result = await page.waitToGetProperty(selectors.entryBasicData.observations, 'value'); - - expect(result).toEqual('observation two edited'); - }); - - it('should confirm the supplier was edited', async() => { - const result = await page.waitToGetProperty(selectors.entryBasicData.supplier, 'value'); - - expect(result).toEqual('1 - Plants nick'); - }); - - it('should confirm the currency was edited', async() => { - const result = await page.waitToGetProperty(selectors.entryBasicData.currency, 'value'); - - expect(result).toEqual('EUR'); - }); - - it('should confirm the commission was edited', async() => { - const result = await page.waitToGetProperty(selectors.entryBasicData.commission, 'value'); - - expect(result).toEqual('100'); - }); - - it('should confirm the company was edited', async() => { - const result = await page.waitToGetProperty(selectors.entryBasicData.company, 'value'); - - expect(result).toEqual('CCs'); - }); - - it('should confirm ordered was edited', async() => { - const result = await page.checkboxState(selectors.entryBasicData.ordered); - - expect(result).toBe('checked'); - }); - - it('should confirm confirmed was edited', async() => { - const result = await page.checkboxState(selectors.entryBasicData.confirmed); - - expect(result).toBe('checked'); - }); - - it('should confirm inventory was edited', async() => { - const result = await page.checkboxState(selectors.entryBasicData.inventory); - - expect(result).toBe('checked'); - }); - - it('should confirm raid was edited', async() => { - const result = await page.checkboxState(selectors.entryBasicData.raid); - - expect(result).toBe('checked'); - }); - - it('should confirm booked was edited', async() => { - const result = await page.checkboxState(selectors.entryBasicData.booked); - - expect(result).toBe('checked'); + expect(reference).toEqual('new movement 8'); + expect(supplier).toEqual('Plants nick'); + expect(invoiceNumber).toEqual('new movement 8'); + expect(observations).toEqual('observation two edited'); + expect(currency).toEqual('EUR'); + expect(commission).toEqual('100'); + expect(company).toEqual('CCs'); + expect(ordered).toBe('checked'); + expect(confirmed).toBe('checked'); + expect(inventory).toBe('checked'); + expect(raid).toBe('checked'); + expect(booked).toBe('checked'); }); }); diff --git a/e2e/paths/12-entry/07_buys.spec.js b/e2e/paths/12-entry/07_buys.spec.js index 4487394df..e501452bc 100644 --- a/e2e/paths/12-entry/07_buys.spec.js +++ b/e2e/paths/12-entry/07_buys.spec.js @@ -86,40 +86,47 @@ describe('Entry import, create and edit buys path', () => { await page.waitForNumberOfElements(selectors.entryBuys.anyBuyLine, 2); }); - it('should edit the newest buy', async() => { + it('should edit the newest buy and check data', async() => { await page.clearInput(selectors.entryBuys.secondBuyPackingPrice); await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyPackingPrice, '100'); + await page.keyboard.press('Enter'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyGroupingPrice); await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyGroupingPrice, '200'); + await page.keyboard.press('Enter'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyPrice); await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyPrice, '300'); + await page.keyboard.press('Enter'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyGrouping); await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyGrouping, '400'); + await page.keyboard.press('Enter'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyPacking); await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyPacking, '500'); + await page.keyboard.press('Enter'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyWeight); await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyWeight, '600'); + await page.keyboard.press('Enter'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyStickers); await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyStickers, '700'); + await page.keyboard.press('Enter'); await page.waitForSnackbar(); await page.autocompleteSearch(selectors.entryBuys.secondBuyPackage, '94'); @@ -128,60 +135,28 @@ describe('Entry import, create and edit buys path', () => { await page.clearInput(selectors.entryBuys.secondBuyQuantity); await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyQuantity, '800'); - }); + await page.keyboard.press('Enter'); - it('should reload the section and check the packing price is as expected', async() => { await page.reloadSection('entry.card.buy.index'); - const result = await page.waitToGetProperty(selectors.entryBuys.secondBuyPackingPrice, 'value'); - expect(result).toEqual('100'); - }); + const secondBuyPackingPrice = await page.getValue(selectors.entryBuys.secondBuyPackingPrice); + const secondBuyGroupingPrice = await page.getValue(selectors.entryBuys.secondBuyGroupingPrice); + const secondBuyPrice = await page.getValue(selectors.entryBuys.secondBuyPrice); + const secondBuyGrouping = await page.getValue(selectors.entryBuys.secondBuyGrouping); + const secondBuyPacking = await page.getValue(selectors.entryBuys.secondBuyPacking); + const secondBuyWeight = await page.getValue(selectors.entryBuys.secondBuyWeight); + const secondBuyStickers = await page.getValue(selectors.entryBuys.secondBuyStickers); + const secondBuyPackage = await page.getValue(selectors.entryBuys.secondBuyPackage); + const secondBuyQuantity = await page.getValue(selectors.entryBuys.secondBuyQuantity); - it('should reload the section and check the grouping price is as expected', async() => { - const result = await page.waitToGetProperty(selectors.entryBuys.secondBuyGroupingPrice, 'value'); - - expect(result).toEqual('200'); - }); - - it('should reload the section and check the price is as expected', async() => { - const result = await page.waitToGetProperty(selectors.entryBuys.secondBuyPrice, 'value'); - - expect(result).toEqual('300'); - }); - - it('should reload the section and check the grouping is as expected', async() => { - const result = await page.waitToGetProperty(selectors.entryBuys.secondBuyGrouping, 'value'); - - expect(result).toEqual('400'); - }); - - it('should reload the section and check the packing is as expected', async() => { - const result = await page.waitToGetProperty(selectors.entryBuys.secondBuyPacking, 'value'); - - expect(result).toEqual('500'); - }); - - it('should reload the section and check the weight is as expected', async() => { - const result = await page.waitToGetProperty(selectors.entryBuys.secondBuyWeight, 'value'); - - expect(result).toEqual('600'); - }); - - it('should reload the section and check the stickers are as expected', async() => { - const result = await page.waitToGetProperty(selectors.entryBuys.secondBuyStickers, 'value'); - - expect(result).toEqual('700'); - }); - - it('should reload the section and check the package is as expected', async() => { - const result = await page.waitToGetProperty(selectors.entryBuys.secondBuyPackage, 'value'); - - expect(result).toEqual('94'); - }); - - it('should reload the section and check the quantity is as expected', async() => { - const result = await page.waitToGetProperty(selectors.entryBuys.secondBuyQuantity, 'value'); - - expect(result).toEqual('800'); + expect(secondBuyPackingPrice).toEqual('100'); + expect(secondBuyGroupingPrice).toEqual('200'); + expect(secondBuyPrice).toEqual('300'); + expect(secondBuyGrouping).toEqual('400'); + expect(secondBuyPacking).toEqual('500'); + expect(secondBuyWeight).toEqual('600'); + expect(secondBuyStickers).toEqual('700'); + expect(secondBuyPackage).toEqual('94'); + expect(secondBuyQuantity).toEqual('800'); }); }); diff --git a/e2e/paths/13-supplier/02_basic_data.spec.js b/e2e/paths/13-supplier/02_basic_data.spec.js index 9d86e11d4..72ea6d890 100644 --- a/e2e/paths/13-supplier/02_basic_data.spec.js +++ b/e2e/paths/13-supplier/02_basic_data.spec.js @@ -64,14 +64,4 @@ describe('Supplier basic data path', () => { expect(result).toEqual('Some notes'); }); - - it('should navigate to the log section', async() => { - await page.accessToSection('supplier.card.log'); - }); - - it('should check the changes have been recorded', async() => { - const result = await page.waitToGetProperty('vn-tr table tr:nth-child(3) td.after', 'innerText'); - - expect(result).toEqual('Some notes'); - }); }); diff --git a/e2e/paths/13-supplier/03_fiscal_data.spec.js b/e2e/paths/13-supplier/03_fiscal_data.spec.js index 4f9581e32..80c6c79b2 100644 --- a/e2e/paths/13-supplier/03_fiscal_data.spec.js +++ b/e2e/paths/13-supplier/03_fiscal_data.spec.js @@ -1,4 +1,3 @@ -import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; describe('Supplier fiscal data path', () => { @@ -10,102 +9,48 @@ describe('Supplier fiscal data path', () => { page = browser.page; await page.loginAndModule('administrative', 'supplier'); await page.accessToSearchResult('2'); - await page.accessToSection('supplier.card.fiscalData'); }); afterAll(async() => { await browser.close(); }); - it('should attempt to edit the fiscal data but fail as the tax number is invalid', async() => { - await page.clearInput(selectors.supplierFiscalData.city); - await page.clearInput(selectors.supplierFiscalData.province); - await page.clearInput(selectors.supplierFiscalData.country); - await page.clearInput(selectors.supplierFiscalData.postCode); - await page.write(selectors.supplierFiscalData.city, 'Valencia'); - await page.waitForTimeout(1000); // must repeat this action twice or fails. also #2699 may be a cool solution to this. - await page.clearInput(selectors.supplierFiscalData.city); - await page.write(selectors.supplierFiscalData.city, 'Valencia'); - await page.clearInput(selectors.supplierFiscalData.socialName); - await page.write(selectors.supplierFiscalData.socialName, 'Farmer King SL'); - await page.clearInput(selectors.supplierFiscalData.taxNumber); - await page.write(selectors.supplierFiscalData.taxNumber, 'Wrong tax number'); - await page.clearInput(selectors.supplierFiscalData.account); - await page.write(selectors.supplierFiscalData.account, '0123456789'); - await page.autocompleteSearch(selectors.supplierFiscalData.sageWihholding, 'retencion estimacion objetiva'); - await page.autocompleteSearch(selectors.supplierFiscalData.sageTaxType, 'operaciones no sujetas'); + it('should attempt to edit the fiscal data and check data is saved', async() => { + await page.accessToSection('supplier.card.fiscalData'); - await page.waitToClick(selectors.supplierFiscalData.saveButton); - const message = await page.waitForSnackbar(); + const form = 'vn-supplier-fiscal-data form'; + const values = { + province: null, + country: null, + postcode: null, + city: 'Valencia', + socialName: 'Farmer King SL', + taxNumber: 'Wrong tax number', + account: '0123456789', + sageWithholding: 'retencion estimacion objetiva', + sageTaxType: 'operaciones no sujetas' + }; - expect(message.text).toContain('Invalid Tax number'); - }); + const errorMessage = await page.sendForm(form, values); + const message = await page.sendForm(form, { + taxNumber: '12345678Z' + }); - it('should save the changes as the tax number is valid this time', async() => { - await page.clearInput(selectors.supplierFiscalData.taxNumber); - await page.write(selectors.supplierFiscalData.taxNumber, '12345678Z'); - - await page.waitToClick(selectors.supplierFiscalData.saveButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it('should reload the section', async() => { await page.reloadSection('supplier.card.fiscalData'); - }); + const formValues = await page.fetchForm(form, Object.keys(values)); - it('should check the socialName was edited', async() => { - const result = await page.waitToGetProperty(selectors.supplierFiscalData.socialName, 'value'); - - expect(result).toEqual('Farmer King SL'); - }); - - it('should check the taxNumber was edited', async() => { - const result = await page.waitToGetProperty(selectors.supplierFiscalData.taxNumber, 'value'); - - expect(result).toEqual('12345678Z'); - }); - - it('should check the account was edited', async() => { - const result = await page.waitToGetProperty(selectors.supplierFiscalData.account, 'value'); - - expect(result).toEqual('0123456789'); - }); - - it('should check the sageWihholding was edited', async() => { - const result = await page.waitToGetProperty(selectors.supplierFiscalData.sageWihholding, 'value'); - - expect(result).toEqual('RETENCION ESTIMACION OBJETIVA'); - }); - - it('should check the sageTaxType was edited', async() => { - const result = await page.waitToGetProperty(selectors.supplierFiscalData.sageTaxType, 'value'); - - expect(result).toEqual('Operaciones no sujetas'); - }); - - it('should check the postCode was edited', async() => { - const result = await page.waitToGetProperty(selectors.supplierFiscalData.postCode, 'value'); - - expect(result).toEqual('46000'); - }); - - it('should check the city was edited', async() => { - const result = await page.waitToGetProperty(selectors.supplierFiscalData.city, 'value'); - - expect(result).toEqual('Valencia'); - }); - - it('should check the province was edited', async() => { - const result = await page.waitToGetProperty(selectors.supplierFiscalData.province, 'value'); - - expect(result).toEqual('Province one (España)'); - }); - - it('should check the country was edited', async() => { - const result = await page.waitToGetProperty(selectors.supplierFiscalData.country, 'value'); - - expect(result).toEqual('España'); + expect(errorMessage.text).toContain('Invalid Tax number'); + expect(message.isSuccess).toBeTrue(); + expect(formValues).toEqual({ + province: 'Province one', + country: 'España', + postcode: '46000', + city: 'Valencia', + socialName: 'Farmer King SL', + taxNumber: '12345678Z', + account: '0123456789', + sageWithholding: 'RETENCION ESTIMACION OBJETIVA', + sageTaxType: 'Operaciones no sujetas' + }); }); }); diff --git a/e2e/paths/14-account/04_acl.spec.js b/e2e/paths/14-account/04_acl.spec.js index c400dbfb2..ce2a63b14 100644 --- a/e2e/paths/14-account/04_acl.spec.js +++ b/e2e/paths/14-account/04_acl.spec.js @@ -23,7 +23,7 @@ describe('Account ACL path', () => { it('should create new acl', async() => { await page.autocompleteSearch(selectors.accountAcl.role, 'sysadmin'); - await page.autocompleteSearch(selectors.accountAcl.model, 'UserAccount'); + await page.autocompleteSearch(selectors.accountAcl.model, 'Account'); await page.autocompleteSearch(selectors.accountAcl.accessType, '*'); await page.autocompleteSearch(selectors.accountAcl.permission, 'ALLOW'); await page.waitToClick(selectors.accountAcl.save); diff --git a/front/core/components/autocomplete/index.js b/front/core/components/autocomplete/index.js index 52491f7e0..2539c4ef4 100755 --- a/front/core/components/autocomplete/index.js +++ b/front/core/components/autocomplete/index.js @@ -174,7 +174,6 @@ export default class Autocomplete extends Field { refreshDisplayed() { let display = ''; - let hasTemplate = this.$transclude && this.$transclude.isSlotFilled('tplItem'); if (this._selection && this.showField) { if (this.multiple && Array.isArray(this._selection)) { @@ -182,19 +181,8 @@ export default class Autocomplete extends Field { if (display.length > 0) display += ', '; display += item[this.showField]; } - } else { + } else display = this._selection[this.showField]; - if (hasTemplate) { - let template = this.$transclude(() => {}, null, 'tplItem'); - const element = template[0]; - const description = element.querySelector('.text-secondary'); - if (description) description.remove(); - - const displayElement = angular.element(element); - const displayText = displayElement.text(); - display = this.$interpolate(displayText)(this._selection); - } - } } this.input.value = display; diff --git a/front/core/components/avatar/index.html b/front/core/components/avatar/index.html new file mode 100644 index 000000000..2819e1d50 --- /dev/null +++ b/front/core/components/avatar/index.html @@ -0,0 +1,5 @@ +
Field | -Before | -After | -
---|---|---|
{{prop.name}} | -{{prop.old}} | -{{prop.new}} | -