From 06be5351156d240fc5026ca3ff3e92922717c7b1 Mon Sep 17 00:00:00 2001 From: Joan Sanchez Date: Thu, 21 Feb 2019 08:43:04 +0100 Subject: [PATCH] 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 ;