From ccf5c95b56f5db5def20e419de08f4026de48838 Mon Sep 17 00:00:00 2001 From: Carlos Jimenez Ruiz Date: Wed, 20 Feb 2019 12:49:39 +0100 Subject: [PATCH 01/10] #860 E2E client/client/src/web-payment/index.js --- e2e/helpers/selectors.js | 4 ++ .../client-module/16_web_payment.spec.js | 40 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 e2e/paths/client-module/16_web_payment.spec.js diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index d4a5fea0e..8b4b0e184 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -163,6 +163,10 @@ export default { firstRiskLineBalance: 'vn-client-risk-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)' }, + 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"]' + }, itemsIndex: { goBackToModuleIndexButton: `vn-ticket-descriptor a[href="#!/ticket/index"]`, createItemButton: `${components.vnFloatButton}`, diff --git a/e2e/paths/client-module/16_web_payment.spec.js b/e2e/paths/client-module/16_web_payment.spec.js new file mode 100644 index 000000000..d7f8e88f3 --- /dev/null +++ b/e2e/paths/client-module/16_web_payment.spec.js @@ -0,0 +1,40 @@ +import selectors from '../../helpers/selectors.js'; +import createNightmare from '../../helpers/nightmare'; + +// #860 E2E client/client/src/web-payment/index.js missing fixtures for another client +xdescribe('Client web Payment', () => { + const nightmare = createNightmare(); + + describe('as employee', () => { + beforeAll(() => { + nightmare + .loginAndModule('employee', 'client') + .accessToSearchResult('Bruce Wayne') + .accessToSection('client.card.webPayment'); + }); + + it('should not be able to confirm payments', async() => { + let exists = await nightmare + .exists(selectors.webPayment.confirmFirstPaymentButton); + + expect(exists).toBeFalsy(); + }); + }); + + describe('as administrative', () => { + beforeAll(() => { + nightmare + .loginAndModule('administrative', 'client') + .accessToSearchResult('Bruce Wayne') + .accessToSection('client.card.webPayment'); + }); + + it('should be able to confirm payments', async() => { + let exists = await nightmare + .waitToClick(selectors.webPayment.confirmFirstPaymentButton) + .exists(selectors.webPayment.firstPaymentConfirmed); + + expect(exists).toBeTruthy(); + }); + }); +}); From 79cf4afb3e9981f1b1d816a6925193da27524a4a Mon Sep 17 00:00:00 2001 From: Gerard Date: Wed, 20 Feb 2019 16:30:46 +0100 Subject: [PATCH 02/10] #1116 loggable now works with transaction and log enabled on ticket module --- loopback/common/models/loggable.js | 42 +++++++++---------- .../back/methods/ticket/specs/deleted.spec.js | 10 ++--- modules/ticket/back/models/ticket.json | 5 ++- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/loopback/common/models/loggable.js b/loopback/common/models/loggable.js index 6cc7298c6..8df5762fc 100644 --- a/loopback/common/models/loggable.js +++ b/loopback/common/models/loggable.js @@ -22,12 +22,12 @@ module.exports = function(Self) { oldInstance = await fkToValue(oldInstanceFk, ctx); if (ctx.where && !ctx.currentInstance) { let fields = Object.keys(ctx.data); - ctx.oldInstances = await Self.modelBuilder.models[ctx.Model.definition.name].find({where: ctx.where, fields: fields}); + ctx.oldInstances = await ctx.Model.app.models[ctx.Model.definition.name].find({where: ctx.where, fields: fields}); } } - if (ctx.isNewInstance) { + if (ctx.isNewInstance) newInstance = await fkToValue(ctx.instance.__data, ctx); - } + ctx.hookState.oldInstance = oldInstance; ctx.hookState.newInstance = newInstance; }); @@ -36,7 +36,7 @@ module.exports = function(Self) { if (ctx.where) { let affectedModel = ctx.Model.definition.name; let definition = ctx.Model.definition; - let deletedInstances = await Self.modelBuilder.models[affectedModel].find({where: ctx.where}); + let deletedInstances = await ctx.Model.app.models[affectedModel].find({where: ctx.where}); let relation = definition.settings.log.relation; if (relation) { @@ -81,12 +81,11 @@ module.exports = function(Self) { }; let transaction = {}; - if (ctx.options && ctx.options.transaction) { + if (ctx.options && ctx.options.transaction) transaction = ctx.options.transaction; - } let logModel = definition.settings.log.model; - await Self.modelBuilder.models[logModel].create(logRecord, transaction); + await ctx.Model.app.models[logModel].create(logRecord, transaction); }); } @@ -147,25 +146,23 @@ module.exports = function(Self) { if (changedModelValue && (!ctx.instance || !ctx.instance[changedModelValue])) { var where = []; changedModelId = []; - let changedInstances = await Self.modelBuilder.models[definition.name].find({where: ctx.where, fields: ['id', changedModelValue]}); + let changedInstances = await ctx.Model.app.models[definition.name].find({where: ctx.where, fields: ['id', changedModelValue]}); changedInstances.forEach(element => { where.push(element[changedModelValue]); changedModelId.push(element.id); }); - } else if (ctx.hookState.oldInstance) { + } else if (ctx.hookState.oldInstance) where = ctx.instance[changedModelValue]; - } + // Set oldInstance, newInstance, userFk and action let oldInstance = {}; - if (ctx.hookState.oldInstance) { + if (ctx.hookState.oldInstance) Object.assign(oldInstance, ctx.hookState.oldInstance); - } let newInstance = {}; - if (ctx.hookState.newInstance) { + if (ctx.hookState.newInstance) Object.assign(newInstance, ctx.hookState.newInstance); - } let userFk; if (loopBackContext) @@ -189,17 +186,16 @@ module.exports = function(Self) { let logModel = definition.settings.log.model; let transaction = {}; - if (ctx.options && ctx.options.transaction) { + if (ctx.options && ctx.options.transaction) transaction = ctx.options.transaction; - } - await Self.modelBuilder.models[logModel].create(logsToSave, transaction); + await ctx.Model.app.models[logModel].create(logsToSave, transaction); } // this function retuns all the instances changed in case this is an updateAll function setLogsToSave(changedInstances, changedInstancesIds, logRecord, ctx) { let promises = []; - if (changedInstances && typeof changedInstances == "object") { + if (changedInstances && typeof changedInstances == 'object') { for (let i = 0; i < changedInstances.length; i++) { logRecord.changedModelId = changedInstancesIds[i]; logRecord.changedModelValue = changedInstances[i]; @@ -207,9 +203,9 @@ module.exports = function(Self) { logRecord.oldInstance = ctx.oldInstances[i]; promises.push(JSON.parse(JSON.stringify(logRecord))); } - } else { + } else return logRecord; - } + return promises; } @@ -217,11 +213,11 @@ module.exports = function(Self) { let oldInstance = ctx.hookState.oldInstance; let newInstance = ctx.hookState.newInstance; - if (oldInstance && newInstance) { + if (oldInstance && newInstance) return 'update'; - } else if (!oldInstance && newInstance) { + else if (!oldInstance && newInstance) return 'insert'; - } + return 'delete'; } }; diff --git a/modules/ticket/back/methods/ticket/specs/deleted.spec.js b/modules/ticket/back/methods/ticket/specs/deleted.spec.js index 84cf5d57d..e5a0906a2 100644 --- a/modules/ticket/back/methods/ticket/specs/deleted.spec.js +++ b/modules/ticket/back/methods/ticket/specs/deleted.spec.js @@ -3,21 +3,21 @@ const app = require('vn-loopback/server/server'); describe('ticket deleted()', () => { let ticket; - beforeAll(async () => { + beforeAll(async() => { let originalTicket = await app.models.Ticket.findOne({where: {id: 16}}); originalTicket.id = null; ticket = await app.models.Ticket.create(originalTicket); }); - afterAll(async () => { + afterAll(async() => { await app.models.Ticket.destroyById(ticket.id); }); - it('should make sure the ticket is not deleted yet', async () => { + it('should make sure the ticket is not deleted yet', async() => { expect(ticket.isDeleted).toEqual(false); }); - it('should set a ticket to deleted and log the change on TicketState table', async () => { + it('should set a ticket to deleted and log the change on TicketState table', async() => { let ctx = {req: {accessToken: {userId: 9}}}; let params = {id: ticket.id}; await app.models.Ticket.deleted(ctx, params); @@ -29,7 +29,7 @@ describe('ticket deleted()', () => { expect(changedState.stateFk).toEqual(17); }); - it('should throw an error if the given ticket has a claim', async () => { + it('should throw an error if the given ticket has a claim', async() => { let ctx = {req: {accessToken: {userId: 9}}}; let params = {id: 16}; let error; diff --git a/modules/ticket/back/models/ticket.json b/modules/ticket/back/models/ticket.json index bd8917f8d..95073fec7 100644 --- a/modules/ticket/back/models/ticket.json +++ b/modules/ticket/back/models/ticket.json @@ -1,6 +1,9 @@ { "name": "Ticket", - "base": "VnModel", + "base": "Loggable", + "log": { + "model":"TicketLog" + }, "options": { "mysql": { "table": "ticket" From c95b2d71d4bff0df168710dffa0d1472bf7a0403 Mon Sep 17 00:00:00 2001 From: Gerard Date: Wed, 20 Feb 2019 16:43:01 +0100 Subject: [PATCH 03/10] tag not closed correctly fixed --- modules/item/front/index/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/item/front/index/index.html b/modules/item/front/index/index.html index e314628c6..3b1cc6d22 100644 --- a/modules/item/front/index/index.html +++ b/modules/item/front/index/index.html @@ -97,7 +97,7 @@ - + From 0cca3bb9ce9d51ff7ccd3780f5f685513d5ab052 Mon Sep 17 00:00:00 2001 From: Gerard Date: Wed, 20 Feb 2019 17:52:36 +0100 Subject: [PATCH 04/10] #1137 ticket.summary, ticket.sale --- e2e/helpers/selectors.js | 14 +++--- e2e/paths/ticket-module/07_edit_sale.spec.js | 8 ++-- modules/ticket/front/sale/index.html | 46 ++++++++++---------- modules/ticket/front/summary/index.html | 8 ++-- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 0df20f191..4506cc7bd 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -269,7 +269,7 @@ export default { sale: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr', firstSaleItemId: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span', popoverDiaryButton: 'vn-ticket-summary vn-item-descriptor-popover vn-item-descriptor vn-icon[icon="icon-transaction"]', - firstSaleQuantity: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(4)', + firstSaleQuantity: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3)', firstSaleDiscount: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(6)' }, ticketsIndex: { @@ -337,18 +337,18 @@ export default { firstSaleQuantity: `vn-textfield[model="sale.quantity"]:nth-child(1) input`, firstSaleQuantityClearInput: `vn-textfield[model="sale.quantity"] div.suffix > i`, firstSaleID: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(4) > span', - firstSalePrice: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(7)', + firstSalePrice: 'vn-ticket-sale:nth-child(1) vn-tr:nth-child(1) > vn-td:nth-child(7) > span', firstSalePriceInput: 'vn-ticket-sale:nth-child(1) > vn-vertical > vn-popover.edit.dialog-summary.ng-isolate-scope.vn-popover.shown > div > div.content > div > vn-textfield', - firstSaleDiscount: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(8)', + firstSaleDiscount: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(8) > span', firstSaleDiscountInput: 'vn-ticket-sale:nth-child(1) vn-ticket-sale-edit-discount > div > vn-textfield > div > div > div.infix > input.ng-not-empty', firstSaleImport: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(9)', firstSaleReservedIcon: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td:nth-child(2) > vn-icon:nth-child(3)', - firstSaleColour: `vn-ticket-sale vn-tr:nth-child(1) vn-td:nth-child(5) section:nth-child(1)`, - firstSaleLength: `vn-ticket-sale vn-tr:nth-child(1) vn-td:nth-child(5) section:nth-child(3)`, + firstSaleColour: `vn-ticket-sale vn-tr:nth-child(1) vn-td:nth-child(6) section:nth-child(1)`, + firstSaleLength: `vn-ticket-sale vn-tr:nth-child(1) vn-td:nth-child(6) section:nth-child(3)`, firstSaleCheckbox: `vn-ticket-sale vn-tr:nth-child(1) vn-check[field="sale.checked"] md-checkbox`, secondSaleClaimIcon: 'vn-ticket-sale > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(2) > a > vn-icon', - secondSaleColour: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(5) section:nth-child(5)`, - secondSalePrice: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(7)`, + secondSaleColour: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(6) section:nth-child(5)`, + secondSalePrice: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(7) > span`, secondSaleDiscount: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(8)`, secondSaleImport: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(9)`, secondSaleText: `vn-table div > vn-tbody > vn-tr:nth-child(2)`, diff --git a/e2e/paths/ticket-module/07_edit_sale.spec.js b/e2e/paths/ticket-module/07_edit_sale.spec.js index 655f25cb3..9a0a3f35d 100644 --- a/e2e/paths/ticket-module/07_edit_sale.spec.js +++ b/e2e/paths/ticket-module/07_edit_sale.spec.js @@ -538,16 +538,16 @@ xdescribe('Ticket Edit sale path', () => { describe('when state is preparation and loged as Production', () => { it(`should not be able to edit the sale price`, async() => { const result = await nightmare - .waitToClick(selectors.ticketSales.firstSalePrice) - .exists(selectors.ticketSales.firstSalePriceInput); + .wait(selectors.ticketSales.firstSaleID) + .exists(selectors.ticketSales.firstSalePrice); expect(result).toBeFalsy(); }); it(`should not be able to edit the sale discount`, async() => { const result = await nightmare - .waitToClick(selectors.ticketSales.firstSaleDiscount) - .exists(selectors.ticketSales.firstSaleDiscountInput); + .waitToClick(selectors.ticketSales.firstSaleID) + .exists(selectors.ticketSales.firstSaleDiscount); expect(result).toBeFalsy(); }); diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html index 82e6bff8c..8e4585a2a 100644 --- a/modules/ticket/front/sale/index.html +++ b/modules/ticket/front/sale/index.html @@ -62,8 +62,8 @@ Id + Quantity Item - Quantity Price Disc Amount @@ -94,7 +94,7 @@ icon="icon-reserve" vn-tooltip="{{::$ctrl.$translate.instant('Reserved')}}"> - + - - - - {{sale.quantity}} - - {{sale.price | currency: 'EUR':2}} + + + + + + + {{sale.price | currency: 'EUR':2}} + {{sale.price | currency: 'EUR':2}} - - {{sale.discount}} % + + + {{sale.discount}} % + @@ -158,7 +158,7 @@
MANÁ: {{$ctrl.mana | currency: 'EUR':0}}
@@ -185,7 +185,7 @@ Item - Description Quantity + Description Price Discount Amount @@ -89,8 +89,8 @@ {{sale.itemFk | zeroFill:6}}
- {{::sale.quantity}} + {{::sale.price | currency: 'EUR':2}} {{::sale.discount}} % {{::sale.quantity * sale.price | currency: 'EUR':2}} @@ -123,8 +123,8 @@ Id - Description Quantity + Description Price Tax class @@ -132,8 +132,8 @@ {{::service.id}} - {{::service.description}} {{::service.quantity}} + {{::service.description}} {{::service.price}} {{::service.taxClass.description}} From 4b54b82a9d3d8f78b683504d7d081cb38ca90cf6 Mon Sep 17 00:00:00 2001 From: Gerard Date: Wed, 20 Feb 2019 18:46:30 +0100 Subject: [PATCH 05/10] #1150 descriptor popover intentar abrir con id movimiento --- modules/ticket/back/methods/ticket/summary.js | 5 +++-- modules/ticket/front/request/index/index.html | 2 +- modules/ticket/front/request/index/index.js | 6 +++--- modules/ticket/front/summary/index.html | 6 +++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/modules/ticket/back/methods/ticket/summary.js b/modules/ticket/back/methods/ticket/summary.js index 36a5b961e..56e17062c 100644 --- a/modules/ticket/back/methods/ticket/summary.js +++ b/modules/ticket/back/methods/ticket/summary.js @@ -135,14 +135,15 @@ module.exports = Self => { relation: 'user' } } - }, - { + }, { relation: 'atender', scope: { include: { relation: 'user' } } + }, { + relation: 'sale' } ] }; diff --git a/modules/ticket/front/request/index/index.html b/modules/ticket/front/request/index/index.html index e868486af..2a1937052 100644 --- a/modules/ticket/front/request/index/index.html +++ b/modules/ticket/front/request/index/index.html @@ -54,7 +54,7 @@ {{request.saleFk | zeroFill:6}} diff --git a/modules/ticket/front/request/index/index.js b/modules/ticket/front/request/index/index.js index 2ade30013..d60204e6d 100644 --- a/modules/ticket/front/request/index/index.js +++ b/modules/ticket/front/request/index/index.js @@ -44,18 +44,18 @@ class Controller { }); } - showItemDescriptor(event, sale) { + showItemDescriptor(event, itemFk) { this.quicklinks = { btnThree: { icon: 'icon-transaction', state: `item.card.diary({ - id: ${sale.itemFk}, + id: ${itemFk}, ticketFk: ${this.$stateParams.id} })`, tooltip: 'Item diary' } }; - this.$.itemDescriptor.itemFk = sale.itemFk; + this.$.itemDescriptor.itemFk = itemFk; this.$.itemDescriptor.parent = event.target; this.$.itemDescriptor.show(); } diff --git a/modules/ticket/front/summary/index.html b/modules/ticket/front/summary/index.html index 364d371b6..6071b1370 100644 --- a/modules/ticket/front/summary/index.html +++ b/modules/ticket/front/summary/index.html @@ -151,7 +151,7 @@ Atender Quantity Price - Sale id + Item Ok @@ -166,9 +166,9 @@ - {{request.saleFk | zeroFill:6}} + {{request.sale.itemFk | zeroFill:6}} From c3679b56421561224f2de227fe9d0a39aabf8839 Mon Sep 17 00:00:00 2001 From: Carlos Jimenez Ruiz Date: Thu, 21 Feb 2019 07:40:22 +0100 Subject: [PATCH 06/10] =?UTF-8?q?#1077=20e2e=20espec=C3=ADfico=20para=20lo?= =?UTF-8?q?gin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- e2e/paths/login/01_login.spec.js | 61 ++++++++++++++++++++++++++++++++ loopback/locale/es.json | 3 +- 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 e2e/paths/login/01_login.spec.js diff --git a/e2e/paths/login/01_login.spec.js b/e2e/paths/login/01_login.spec.js new file mode 100644 index 000000000..a33be0c25 --- /dev/null +++ b/e2e/paths/login/01_login.spec.js @@ -0,0 +1,61 @@ +import createNightmare from '../../helpers/nightmare'; +import config from '../../helpers/config.js'; + + +describe('Login path', () => { + const nightmare = createNightmare(); + + it('should receive an error when the username is incorrect', async() => { + const username = 'nobody'; + const password = 'nightmare'; + + const result = await nightmare + .goto(`${config.url}/#!/login`) + .wait(`vn-login input[name=user]`) + .write(`vn-login input[name=user]`, username) + .write(`vn-login input[name=password]`, password) + .click(`vn-login input[type=submit]`) + .waitForLastSnackbar(); + + expect(result.length).toBeGreaterThan(0); + }); + + it('should receive an error when the username is blank', async() => { + const password = 'nightmare'; + + const result = await nightmare + .clearInput(`vn-login input[name=user]`) + .write(`vn-login input[name=password]`, password) + .click(`vn-login input[type=submit]`) + .waitForLastSnackbar(); + + expect(result.length).toBeGreaterThan(0); + }); + + it('should receive an error when the password is incorrect', async() => { + const username = 'employee'; + const password = 'badpassword'; + + const result = await nightmare + .write(`vn-login input[name=user]`, username) + .write(`vn-login input[name=password]`, password) + .click(`vn-login input[type=submit]`) + .waitForLastSnackbar(); + + expect(result.length).toBeGreaterThan(0); + }); + + it('should log in', async() => { + const username = 'employee'; + const password = 'nightmare'; + + const url = await nightmare + .write(`vn-login input[name=user]`, username) + .write(`vn-login input[name=password]`, password) + .click(`vn-login input[type=submit]`) + .wait('#logout') + .parsedUrl(); + + expect(url.hash).toEqual('#!/'); + }); +}); diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 7ef74e67f..e1a06c078 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -67,5 +67,6 @@ "You can't create a ticket for a inactive client": "No puedes crear un ticket para un cliente inactivo", "Tag value cannot be blank": "El valor del tag no puede quedar en blanco", "ORDER_EMPTY": "Cesta vacía", - "You don't have enough privileges to do that": "No tienes permisos para cambiar esto" + "You don't have enough privileges to do that": "No tienes permisos para cambiar esto", + "You can't create a ticket for a client that has a debt": "No puedes crear un ticket para un client con deuda" } \ No newline at end of file From 444d531162399f5e4574339031c8e480a3dcf264 Mon Sep 17 00:00:00 2001 From: Gerard Date: Thu, 21 Feb 2019 07:46:27 +0100 Subject: [PATCH 07/10] summary action now shows ticket id --- modules/claim/front/summary/index.html | 18 ++++++++++++++---- modules/claim/front/summary/index.js | 8 ++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/modules/claim/front/summary/index.html b/modules/claim/front/summary/index.html index dd50d4933..ec650c86e 100644 --- a/modules/claim/front/summary/index.html +++ b/modules/claim/front/summary/index.html @@ -40,7 +40,7 @@ - Id + Item Landed Quantity Claimed @@ -107,7 +107,8 @@ - Id + Item + Ticket Destination Landed Quantity @@ -126,7 +127,13 @@ {{action.sale.itemFk | zeroFill:6}} - {{action.sale.id}} + + + {{action.sale.ticket.id | zeroFill:6}} + + {{action.claimBeggining.description}} {{action.sale.ticket.landed | dateTime: 'dd/MM/yyyy'}} {{action.sale.quantity}} @@ -150,4 +157,7 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/modules/claim/front/summary/index.js b/modules/claim/front/summary/index.js index 67af420fe..b8fedca7a 100644 --- a/modules/claim/front/summary/index.js +++ b/modules/claim/front/summary/index.js @@ -33,12 +33,16 @@ class Controller { } showWorkerDescriptor(event, userId) { - event.preventDefault(); - event.stopImmediatePropagation(); this.selectedWorker = userId; this.$.workerDescriptor.parent = event.target; this.$.workerDescriptor.show(); } + + showTicketDescriptor(event, ticketId) { + this.$.ticketDescriptor.ticketFk = ticketId; + this.$.ticketDescriptor.parent = event.target; + this.$.ticketDescriptor.show(); + } } Controller.$inject = ['$scope', '$http']; From 06be5351156d240fc5026ca3ff3e92922717c7b1 Mon Sep 17 00:00:00 2001 From: Joan Sanchez Date: Thu, 21 Feb 2019 08:43:04 +0100 Subject: [PATCH 08/10] ticket subtotal should check service prices #1151 --- .../back/methods/client/specs/getCard.spec.js | 4 +- .../back/methods/client/specs/summary.spec.js | 2 +- .../methods/ticket/specs/getTaxes.spec.js | 2 +- .../methods/ticket/specs/getTotal.spec.js | 2 +- .../back/methods/ticket/specs/getVAT.spec.js | 2 +- .../methods/ticket/specs/subtotal.spec.js | 15 +++ .../back/methods/ticket/specs/summary.spec.js | 8 +- .../ticket/back/methods/ticket/subtotal.js | 40 ++++++++ modules/ticket/back/methods/ticket/summary.js | 6 +- modules/ticket/back/models/ticket.js | 1 + modules/ticket/front/sale/index.html | 2 +- modules/ticket/front/sale/index.js | 9 +- modules/ticket/front/sale/index.spec.js | 5 +- modules/ticket/front/summary/index.html | 4 +- .../changes/1.2-CHECK/04-ticketGetTax.sql | 99 +++++++++++++++++++ .../changes/1.2-CHECK/05-ticketGetTaxAdd.sql | 34 +++++++ 16 files changed, 213 insertions(+), 22 deletions(-) create mode 100644 modules/ticket/back/methods/ticket/specs/subtotal.spec.js create mode 100644 modules/ticket/back/methods/ticket/subtotal.js create mode 100644 services/db/install/changes/1.2-CHECK/04-ticketGetTax.sql create mode 100644 services/db/install/changes/1.2-CHECK/05-ticketGetTaxAdd.sql diff --git a/modules/client/back/methods/client/specs/getCard.spec.js b/modules/client/back/methods/client/specs/getCard.spec.js index 896585096..1619280f8 100644 --- a/modules/client/back/methods/client/specs/getCard.spec.js +++ b/modules/client/back/methods/client/specs/getCard.spec.js @@ -1,12 +1,12 @@ const app = require('vn-loopback/server/server'); -describe('Client card', () => { +describe('Client get', () => { it('should call the card() method to receive a formated card of Bruce Wayne', async() => { let id = 101; let result = await app.models.Client.getCard(id); expect(result.id).toEqual(101); expect(result.name).toEqual('Bruce Wayne'); - expect(result.debt).toEqual(579.1); + expect(result.debt).toEqual(595.81); }); }); diff --git a/modules/client/back/methods/client/specs/summary.spec.js b/modules/client/back/methods/client/specs/summary.spec.js index 16527227f..aeae819ee 100644 --- a/modules/client/back/methods/client/specs/summary.spec.js +++ b/modules/client/back/methods/client/specs/summary.spec.js @@ -17,7 +17,7 @@ describe('client summary()', () => { it('should return a summary object containing debt', async() => { let result = await app.models.Client.summary(101); - expect(result.debt.debt).toEqual(579.1); + expect(result.debt.debt).toEqual(595.81); }); it('should return a summary object containing averageInvoiced', async() => { diff --git a/modules/ticket/back/methods/ticket/specs/getTaxes.spec.js b/modules/ticket/back/methods/ticket/specs/getTaxes.spec.js index fe0c91e92..2d8488cd3 100644 --- a/modules/ticket/back/methods/ticket/specs/getTaxes.spec.js +++ b/modules/ticket/back/methods/ticket/specs/getTaxes.spec.js @@ -4,6 +4,6 @@ describe('ticket getTaxes()', () => { it('should return the tax of a given ticket', async() => { let result = await app.models.Ticket.getTaxes(1); - expect(result[0].tax).toEqual(7.44); + expect(result[0].tax).toEqual(7.64); }); }); diff --git a/modules/ticket/back/methods/ticket/specs/getTotal.spec.js b/modules/ticket/back/methods/ticket/specs/getTotal.spec.js index 4bf10539e..bcdcd4889 100644 --- a/modules/ticket/back/methods/ticket/specs/getTotal.spec.js +++ b/modules/ticket/back/methods/ticket/specs/getTotal.spec.js @@ -4,7 +4,7 @@ describe('ticket getTotal()', () => { it('should return the total of a ticket', async() => { let result = await app.models.Ticket.getTotal(1); - expect(result).toEqual(155.89); + expect(result).toEqual(158.09); }); it(`should return zero if the ticket doesn't have lines`, async() => { diff --git a/modules/ticket/back/methods/ticket/specs/getVAT.spec.js b/modules/ticket/back/methods/ticket/specs/getVAT.spec.js index 8f80d9512..70fa0fa39 100644 --- a/modules/ticket/back/methods/ticket/specs/getVAT.spec.js +++ b/modules/ticket/back/methods/ticket/specs/getVAT.spec.js @@ -4,7 +4,7 @@ describe('ticket getVAT()', () => { it('should call the getVAT method and return the response', async() => { await app.models.Ticket.getVAT(1) .then(response => { - expect(response).toEqual(20.29); + expect(response).toEqual(20.49); }); }); diff --git a/modules/ticket/back/methods/ticket/specs/subtotal.spec.js b/modules/ticket/back/methods/ticket/specs/subtotal.spec.js new file mode 100644 index 000000000..c204f806a --- /dev/null +++ b/modules/ticket/back/methods/ticket/specs/subtotal.spec.js @@ -0,0 +1,15 @@ +const app = require('vn-loopback/server/server'); + +describe('ticket subtotal()', () => { + it('should return the subtotal of a ticket', async() => { + let result = await app.models.Ticket.subtotal(1); + + expect(result).toEqual(137.60); + }); + + it(`should return zero if the ticket doesn't have lines`, async() => { + let result = await app.models.Ticket.subtotal(13); + + expect(result).toEqual(0.00); + }); +}); diff --git a/modules/ticket/back/methods/ticket/specs/summary.spec.js b/modules/ticket/back/methods/ticket/specs/summary.spec.js index 34e6affba..2041555ba 100644 --- a/modules/ticket/back/methods/ticket/specs/summary.spec.js +++ b/modules/ticket/back/methods/ticket/specs/summary.spec.js @@ -14,21 +14,21 @@ describe('ticket summary()', () => { expect(result.sales.length).toEqual(4); }); - it('should return a summary object containing subTotal for 1 ticket', async() => { + it('should return a summary object containing subtotal for 1 ticket', async() => { let result = await app.models.Ticket.summary(1); - expect(Math.round(result.subTotal * 100) / 100).toEqual(135.60); + expect(Math.round(result.subtotal * 100) / 100).toEqual(137.60); }); it('should return a summary object containing VAT for 1 ticket', async() => { let result = await app.models.Ticket.summary(1); - expect(Math.round(result.VAT * 100) / 100).toEqual(20.29); + expect(Math.round(result.vat * 100) / 100).toEqual(20.49); }); it('should return a summary object containing total for 1 ticket', async() => { let result = await app.models.Ticket.summary(1); - let total = result.subTotal + result.VAT; + let total = result.subtotal + result.vat; let expectedTotal = Math.round(total * 100) / 100; expect(result.total).toEqual(expectedTotal); diff --git a/modules/ticket/back/methods/ticket/subtotal.js b/modules/ticket/back/methods/ticket/subtotal.js new file mode 100644 index 000000000..f1595e77b --- /dev/null +++ b/modules/ticket/back/methods/ticket/subtotal.js @@ -0,0 +1,40 @@ +module.exports = Self => { + Self.remoteMethod('subtotal', { + description: 'Returns the total of a ticket', + accessType: 'READ', + accepts: [{ + arg: 'id', + type: 'number', + required: true, + description: 'ticket id', + http: {source: 'path'} + }], + returns: { + type: 'number', + root: true + }, + http: { + path: `/:id/subtotal`, + verb: 'GET' + } + }); + + Self.subtotal = async ticketFk => { + const sale = Self.app.models.Sale; + const ticketSales = await sale.find({where: {ticketFk}}); + const ticketService = Self.app.models.TicketService; + const ticketServices = await ticketService.find({where: {ticketFk}}); + + let subtotal = 0.00; + ticketSales.forEach(sale => { + subtotal += sale.price * sale.quantity * ((100 - sale.discount) / 100); + }); + + ticketServices.forEach(service => { + subtotal += service.price * service.quantity; + }); + + + return Math.round(subtotal * 100) / 100; + }; +}; diff --git a/modules/ticket/back/methods/ticket/summary.js b/modules/ticket/back/methods/ticket/summary.js index 56e17062c..8af76b981 100644 --- a/modules/ticket/back/methods/ticket/summary.js +++ b/modules/ticket/back/methods/ticket/summary.js @@ -23,9 +23,9 @@ module.exports = Self => { let models = Self.app.models; let summaryObj = await getTicketData(Self, ticketFk); summaryObj.sales = await getSales(models.Sale, ticketFk); - summaryObj.subTotal = getSubTotal(summaryObj.sales); - summaryObj.VAT = await models.Ticket.getVAT(ticketFk); - summaryObj.total = await models.Ticket.getTotal(ticketFk); + summaryObj.subtotal = await models.Ticket.subtotal(ticketFk); + summaryObj.vat = await models.Ticket.getVAT(ticketFk); + summaryObj.total = summaryObj.subtotal + summaryObj.vat; summaryObj.packagings = await models.TicketPackaging.find({ where: {ticketFk: ticketFk}, include: [{relation: 'packaging', diff --git a/modules/ticket/back/models/ticket.js b/modules/ticket/back/models/ticket.js index 52144ca4c..c7486a26a 100644 --- a/modules/ticket/back/models/ticket.js +++ b/modules/ticket/back/models/ticket.js @@ -5,6 +5,7 @@ module.exports = Self => { require('../methods/ticket/summary')(Self); require('../methods/ticket/getTotal')(Self); require('../methods/ticket/getTaxes')(Self); + require('../methods/ticket/subtotal')(Self); require('../methods/ticket/componentUpdate')(Self); require('../methods/ticket/new')(Self); require('../methods/ticket/isEditable')(Self); diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html index 8e4585a2a..1a93c08c1 100644 --- a/modules/ticket/front/sale/index.html +++ b/modules/ticket/front/sale/index.html @@ -46,7 +46,7 @@ -

Subtotal {{$ctrl.subTotal | currency: 'EUR':2}}

+

Subtotal {{$ctrl.subtotal | currency: 'EUR':2}}

VAT {{$ctrl.VAT | currency: 'EUR':2}}

Total {{$ctrl.total | currency: 'EUR':2}}

diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js index 6cc012b4e..129a00198 100644 --- a/modules/ticket/front/sale/index.js +++ b/modules/ticket/front/sale/index.js @@ -36,9 +36,10 @@ class Controller { } loadSubTotal() { - this.subTotal = 0.0; - if (!this.sales) return; - this.subTotal = this.sales.reduce((sum, sale) => sum + this.getSaleTotal(sale), 0.0); + if (!this.$stateParams.id || !this.sales) return; + this.$http.get(`/ticket/api/Tickets/${this.$stateParams.id}/subtotal`).then(res => { + this.subtotal = res.data || 0.0; + }); } getSaleTotal(sale) { @@ -54,7 +55,7 @@ class Controller { } get total() { - return this.subTotal + this.VAT; + return this.subtotal + this.VAT; } onMoreOpen() { diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js index ceaddab90..fea921a14 100644 --- a/modules/ticket/front/sale/index.spec.js +++ b/modules/ticket/front/sale/index.spec.js @@ -41,6 +41,7 @@ describe('Ticket', () => { $httpBackend = _$httpBackend_; $httpBackend.whenGET(/api\/Tickets\/1\/getSales.*/).respond(sales); $httpBackend.whenGET(`/ticket/api/Tickets/1/getVAT`).respond(200, 10.5); + $httpBackend.whenGET(`/ticket/api/Tickets/1/subtotal`).respond(200, 227.5); $element = $compile('')($scope); controller = $element.controller('vnTicketSale'); @@ -67,9 +68,9 @@ describe('Ticket', () => { }); }); - describe('total/VAT/subTotal properties', () => { + describe('total/VAT/subtotal properties', () => { it('should fill total, VAT and subTotal', () => { - expect(controller.subTotal).toEqual(227.5); + expect(controller.subtotal).toEqual(227.5); expect(controller.VAT).toEqual(10.5); expect(controller.total).toEqual(238); }); diff --git a/modules/ticket/front/summary/index.html b/modules/ticket/front/summary/index.html index 6071b1370..95711e3b3 100644 --- a/modules/ticket/front/summary/index.html +++ b/modules/ticket/front/summary/index.html @@ -46,8 +46,8 @@ -

Subtotal {{$ctrl.summary.subTotal | currency: 'EUR':2}}

-

VAT {{$ctrl.summary.VAT | currency: 'EUR':2}}

+

Subtotal {{$ctrl.summary.subtotal | currency: 'EUR':2}}

+

VAT {{$ctrl.summary.vat | currency: 'EUR':2}}

Total {{$ctrl.summary.total | currency: 'EUR':2}}

diff --git a/services/db/install/changes/1.2-CHECK/04-ticketGetTax.sql b/services/db/install/changes/1.2-CHECK/04-ticketGetTax.sql new file mode 100644 index 000000000..6e2423faa --- /dev/null +++ b/services/db/install/changes/1.2-CHECK/04-ticketGetTax.sql @@ -0,0 +1,99 @@ + USE `vn`; +DROP procedure IF EXISTS `ticketGetTax`; + +DELIMITER $$ +USE `vn`$$ +CREATE DEFINER=`root`@`%` PROCEDURE `ticketGetTax`() + READS SQL DATA +BEGIN +/** + * Calcula la base imponible, el IVA y el recargo de equivalencia para + * un conjunto de tickets. + * + * @table tmp.ticket(ticketFk) Identificadores de los tickets a calcular + * @return tmp.ticketAmount + * @return tmp.ticketTax Impuesto desglosado para cada ticket. + + */ + DROP TEMPORARY TABLE IF EXISTS tmp.addressCompany; + CREATE TEMPORARY TABLE tmp.addressCompany + (INDEX (addressFk, companyFk)) + ENGINE = MEMORY + SELECT DISTINCT t.addressFk, t.companyFk + FROM tmp.ticket tmpTicket + JOIN ticket t ON t.id = tmpTicket.ticketFk; + + CALL addressTaxArea (); + + + /** Solo se calcula la base imponible (taxableBase) y el impuesto se calculará posteriormente + * No se debería cambiar el sistema por problemas con los decimales + */ + + DROP TEMPORARY TABLE IF EXISTS tmp.ticketTax; + CREATE TEMPORARY TABLE tmp.ticketTax + (INDEX (ticketFk)) + ENGINE = MEMORY + SELECT tmpTicket.ticketFk, + bp.pgcFk, + SUM(s.quantity * s.price * (100 - s.discount)/100 ) AS taxableBase, + pgc.rate, + tc.code + FROM tmp.ticket tmpTicket + JOIN sale s ON s.ticketFk = tmpTicket.ticketFk + JOIN item i ON i.id = s.itemFk + JOIN ticket t ON t.id = tmpTicket.ticketFk + JOIN supplier su ON su.id = t.companyFk + JOIN tmp.addressTaxArea ata + ON ata.addressFk = t.addressFk AND ata.companyFk = t.companyFk + JOIN itemTaxCountry itc + ON itc.itemFk = i.id AND itc.countryFk = su.countryFk + JOIN bookingPlanner bp + ON bp.countryFk = su.countryFk + AND bp.taxAreaFk = ata.areaFk + AND bp.taxClassFk = itc.taxClassFk + JOIN pgc ON pgc.code = bp.pgcFk + JOIN taxClass tc ON tc.id = bp.taxClassFk + GROUP BY tmpTicket.ticketFk, pgc.code,pgc.rate + HAVING taxableBase != 0; + + DROP TEMPORARY TABLE IF EXISTS tmp.ticketServiceTax; + CREATE TEMPORARY TABLE tmp.ticketServiceTax + (INDEX (ticketFk)) + ENGINE = MEMORY + SELECT tt.ticketFk, + SUM(ts.quantity * ts.price) AS taxableBase, + pgc.rate, + tc.code + FROM tmp.ticketTax tt + JOIN ticketService ts ON ts.ticketFk = tt.ticketFk + JOIN ticket t ON t.id = tt.ticketFk + JOIN supplier su ON su.id = t.companyFk + JOIN tmp.addressTaxArea ata + ON ata.addressFk = t.addressFk AND ata.companyFk = t.companyFk + JOIN bookingPlanner bp + ON bp.countryFk = su.countryFk + AND bp.taxAreaFk = ata.areaFk + AND bp.taxClassFk = ts.taxClassFk + JOIN pgc ON pgc.code = bp.pgcFk AND pgc.rate = tt.rate + JOIN taxClass tc ON tc.id = bp.taxClassFk + GROUP BY tt.ticketFk, tt.code,tt.rate + HAVING taxableBase != 0; + + UPDATE tmp.ticketTax tt + JOIN tmp.ticketServiceTax ts ON tt.ticketFk = ts.ticketFk AND tt.code = ts.code AND tt.rate = ts.rate + SET tt.taxableBase = tt.taxableBase + ts.taxableBase; + + DROP TEMPORARY TABLE IF EXISTS tmp.ticketAmount; + CREATE TEMPORARY TABLE tmp.ticketAmount + (INDEX (ticketFk)) + ENGINE = MEMORY + SELECT ticketFk, taxableBase, SUM(CAST(taxableBase * rate / 100 AS DECIMAL(10, 2))) tax,code + FROM tmp.ticketTax + GROUP BY ticketFk, code; + + DROP TEMPORARY TABLE IF EXISTS tmp.addressCompany; + DROP TEMPORARY TABLE IF EXISTS tmp.addressTaxArea; +END$$ + +DELIMITER ; \ No newline at end of file diff --git a/services/db/install/changes/1.2-CHECK/05-ticketGetTaxAdd.sql b/services/db/install/changes/1.2-CHECK/05-ticketGetTaxAdd.sql new file mode 100644 index 000000000..3631a77e5 --- /dev/null +++ b/services/db/install/changes/1.2-CHECK/05-ticketGetTaxAdd.sql @@ -0,0 +1,34 @@ +DROP PROCEDURE IF EXISTS vn.ticketGetTaxAdd; + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticketGetTaxAdd`(vTicketFk INT) +BEGIN +/** + * Añade un ticket a la tabla tmp.ticket para calcular + * el IVA y el recargo de equivalencia y devuelve el resultado. + */ + DROP TEMPORARY TABLE IF EXISTS tmp.ticket; + CREATE TEMPORARY TABLE tmp.ticket + ENGINE = MEMORY + SELECT vTicketFk ticketFk; + + CALL vn.ticketGetTax(); + + SELECT + tt.ticketFk, + CAST(tt.taxableBase AS DECIMAL(10, 2)) AS taxableBase, + CAST(tt.rate * tt.taxableBase / 100 AS DECIMAL(10, 2)) AS tax, + pgc.*, + CAST(IF(pe.equFk IS NULL, taxableBase, 0) AS DECIMAL(10, 2)) AS Base, + pgc.rate / 100 as vatPercent + FROM tmp.ticketTax tt + JOIN vn.pgc ON pgc.code = tt.pgcFk + LEFT JOIN vn.pgcEqu pe ON pe.equFk = pgc.code; + + DROP TEMPORARY TABLE tmp.ticket; + DROP TEMPORARY TABLE tmp.ticketTax; + DROP TEMPORARY TABLE tmp.ticketAmount; + +END$$ +DELIMITER ; From c9746521dc4ee1555a0180cee0dce7109e7c6ace Mon Sep 17 00:00:00 2001 From: Joan Sanchez Date: Thu, 21 Feb 2019 08:44:03 +0100 Subject: [PATCH 09/10] removed unused getSubTotal() method --- modules/ticket/back/methods/ticket/summary.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/modules/ticket/back/methods/ticket/summary.js b/modules/ticket/back/methods/ticket/summary.js index 8af76b981..b47d325cd 100644 --- a/modules/ticket/back/methods/ticket/summary.js +++ b/modules/ticket/back/methods/ticket/summary.js @@ -149,14 +149,4 @@ module.exports = Self => { }; return await Self.app.models.TicketRequest.find(filter); } - - function getSubTotal(sales) { - let subTotal = 0.00; - - sales.forEach(sale => { - subTotal += sale.quantity * sale.price; - }); - - return subTotal; - } }; From 8d6fdc4b2f6ccb5e1421ab0cfb507918654dfc23 Mon Sep 17 00:00:00 2001 From: Gerard Date: Thu, 21 Feb 2019 10:06:38 +0100 Subject: [PATCH 10/10] added envialia and solved problems with worker popover --- .../ticket/back/methods/expedition/filter.js | 18 ++++++------------ modules/ticket/front/expedition/index.html | 5 ++++- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/modules/ticket/back/methods/expedition/filter.js b/modules/ticket/back/methods/expedition/filter.js index b8c634553..74c542806 100644 --- a/modules/ticket/back/methods/expedition/filter.js +++ b/modules/ticket/back/methods/expedition/filter.js @@ -25,23 +25,17 @@ module.exports = Self => { Self.filter = async filter => { const stmt = new ParameterizedSQL( `SELECT - e.id, - e.ticketFk, - e.isBox, - i1.name namePackage, - e.counter, - e.checked, - i2.name nameBox, - e.itemFk, - u.nickname userNickname, - u.id userId, - e.created + e.id, e.ticketFk, e.isBox, + i1.name namePackage, e.counter, + e.checked, i2.name nameBox, + e.itemFk, u.nickname userNickname, + u.id userId, e.created, e.externalId FROM vn.expedition e LEFT JOIN vn.item i2 ON i2.id = e.itemFk INNER JOIN vn.item i1 ON i1.id = e.isBox LEFT JOIN vn.worker w ON w.id = e.workerFk - JOIN account.user u ON u.id = w.id + JOIN account.user u ON u.id = w.userFk `); stmt.merge(Self.buildSuffix(filter, 'e')); diff --git a/modules/ticket/front/expedition/index.html b/modules/ticket/front/expedition/index.html index 1b713a9e6..d10a4bdcb 100644 --- a/modules/ticket/front/expedition/index.html +++ b/modules/ticket/front/expedition/index.html @@ -13,6 +13,8 @@ + Expedition + Envialia Item Name Package type @@ -30,6 +32,8 @@ vn-tooltip="Delete expedition">
+ {{expedition.id | zeroFill:6}} + {{expedition.externalId | zeroFill:6}} {{::expedition.nameBox}} {{::expedition.counter}} {{::expedition.checked}} - {{::expedition.userNickname}}