diff --git a/e2e/paths/ticket-module/03_list_sale.spec.js b/e2e/paths/ticket-module/03_list_sale.spec.js index b76e9cc5a..3391be521 100644 --- a/e2e/paths/ticket-module/03_list_sale.spec.js +++ b/e2e/paths/ticket-module/03_list_sale.spec.js @@ -1,74 +1,128 @@ import selectors from '../../helpers/selectors.js'; import createNightmare from '../../helpers/helpers'; -describe('Ticket', () => { - describe('List sale path', () => { - const nightmare = createNightmare(); +describe('Ticket List sale path', () => { + const nightmare = createNightmare(); - beforeAll(() => { - return nightmare - .waitForLogin('developer'); + beforeAll(() => { + return nightmare + .waitForLogin('developer'); + }); + + it('should click on the Tickets button of the top bar menu', () => { + return nightmare + .waitToClick(selectors.globalItems.applicationsMenuButton) + .wait(selectors.globalItems.applicationsMenuVisible) + .waitToClick(selectors.globalItems.ticketsButton) + .wait(selectors.ticketsIndex.createTicketButton) + .parsedUrl() + .then(url => { + expect(url.hash).toEqual('#!/ticket/index'); }); + }); - it('should click on the Tickets button of the top bar menu', () => { - return nightmare - .waitToClick(selectors.globalItems.applicationsMenuButton) - .wait(selectors.globalItems.applicationsMenuVisible) - .waitToClick(selectors.globalItems.ticketsButton) - .wait(selectors.ticketsIndex.createTicketButton) - .parsedUrl() - .then(url => { - expect(url.hash).toEqual('#!/ticket/index'); - }); + it('should search for the ticket 1', () => { + return nightmare + .wait(selectors.ticketsIndex.searchResult) + .type(selectors.ticketsIndex.searchTicketInput, 'id:1') + .click(selectors.ticketsIndex.searchButton) + .waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1) + .countElement(selectors.ticketsIndex.searchResult) + .then(result => { + expect(result).toEqual(1); }); + }); - it('should search for the ticket 1', () => { - return nightmare - .wait(selectors.ticketsIndex.searchResult) - .type(selectors.ticketsIndex.searchTicketInput, 'id:1') - .click(selectors.ticketsIndex.searchButton) - .waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1) - .countElement(selectors.ticketsIndex.searchResult) - .then(result => { - expect(result).toEqual(1); - }); + it(`should click on the search result to access to the ticket's sale`, () => { + return nightmare + .waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21') + .waitToClick(selectors.ticketsIndex.searchResult) + .waitToClick(selectors.ticketSales.saleButton) + .waitForURL('sale') + .url() + .then(url => { + expect(url).toContain('sale'); }); + }); - it(`should click on the search result to access to the ticket's sale`, () => { - return nightmare - .waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21') - .waitToClick(selectors.ticketsIndex.searchResult) - .waitToClick(selectors.ticketSales.saleButton) - .waitForURL('sale') - .url() - .then(url => { - expect(url).toContain('sale'); - }); + it('should confirm the first ticket sale contains the colour', () => { + return nightmare + .wait(selectors.ticketSales.firstSaleText) + .getInnerText(selectors.ticketSales.firstSaleColour) + .then(value => { + expect(value).toContain('Yellow'); }); + }); - it('should confirm the first ticket sale is the expected one', () => { - return nightmare - .wait(selectors.ticketSales.firstSaleText) - .getInnerText(selectors.ticketSales.firstSaleText) - .then(value => { - expect(value).toContain('Yellow'); - expect(value).toContain('5'); - expect(value).toContain('€9.60'); - expect(value).toContain('0 %'); - expect(value).toContain('€48.00'); - }); + it('should confirm the first ticket sale contains the lenght', () => { + return nightmare + .wait(selectors.ticketSales.firstSaleText) + .getInnerText(selectors.ticketSales.firstSaleText) + .then(value => { + expect(value).toContain('5'); }); + }); - it('should confirm the second ticket sale is the expected one', () => { - return nightmare - .wait(selectors.ticketSales.secondSaleText) - .getInnerText(selectors.ticketSales.secondSaleText) - .then(value => { - expect(value).toContain('Red'); - expect(value).toContain('€4.21'); - expect(value).toContain('0 %'); - expect(value).toContain('€42.10'); - }); + it('should confirm the first ticket sale contains the price', () => { + return nightmare + .wait(selectors.ticketSales.firstSaleText) + .getInnerText(selectors.ticketSales.firstSalePrice) + .then(value => { + expect(value).toContain('€11.42'); + }); + }); + + it('should confirm the first ticket sale contains the discount', () => { + return nightmare + .wait(selectors.ticketSales.firstSaleText) + .getInnerText(selectors.ticketSales.firstSaleDiscount) + .then(value => { + expect(value).toContain('0 %'); + }); + }); + + it('should confirm the first ticket sale contains the total import', () => { + return nightmare + .wait(selectors.ticketSales.firstSaleText) + .getInnerText(selectors.ticketSales.firstSaleImport) + .then(value => { + expect(value).toContain('57.10'); + }); + }); + + it('should confirm the second ticket sale contains the colour', () => { + return nightmare + .wait(selectors.ticketSales.secondSaleText) + .getInnerText(selectors.ticketSales.secondSaleColour) + .then(value => { + expect(value).toContain('Red'); + }); + }); + + it('should confirm the second ticket sale contains the price', () => { + return nightmare + .wait(selectors.ticketSales.secondSaleText) + .getInnerText(selectors.ticketSales.secondSalePrice) + .then(value => { + expect(value).toContain('€1.30'); + }); + }); + + it('should confirm the second ticket sale contains the discount', () => { + return nightmare + .wait(selectors.ticketSales.secondSaleText) + .getInnerText(selectors.ticketSales.secondSaleDiscount) + .then(value => { + expect(value).toContain('0 %'); + }); + }); + + it('should confirm the second ticket sale contains the total import', () => { + return nightmare + .wait(selectors.ticketSales.secondSaleText) + .getInnerText(selectors.ticketSales.secondSaleImport) + .then(value => { + expect(value).toContain('13.00'); }); }); }); diff --git a/e2e/paths/ticket-module/06_edit_basic_data_steps.spec.js b/e2e/paths/ticket-module/06_edit_basic_data_steps.spec.js index beeb1d749..4c1140d5e 100644 --- a/e2e/paths/ticket-module/06_edit_basic_data_steps.spec.js +++ b/e2e/paths/ticket-module/06_edit_basic_data_steps.spec.js @@ -120,7 +120,7 @@ describe('Ticket', () => { return nightmare .getInnerText(selectors.ticketBasicData.stepTwoTotalPriceDif) .then(result => { - expect(result).toContain('-€206.60'); + expect(result).toContain('-€20.65'); }); }); diff --git a/services/db/install/changes/1.1.0/ticketGetTax.sql b/services/db/install/changes/1.1.0/ticketGetTax.sql new file mode 100644 index 000000000..cd52b10f0 --- /dev/null +++ b/services/db/install/changes/1.1.0/ticketGetTax.sql @@ -0,0 +1,70 @@ +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.ticketTax Impuesto desglosado para cada ticket + * @return tmp.ticketAmount + */ + 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 (); + + DROP TEMPORARY TABLE IF EXISTS tmp.ticketTax; + CREATE TEMPORARY TABLE tmp.ticketTax + (INDEX (ticketFk)) + ENGINE = MEMORY + SELECT tmpTicket.ticketFk, + bp.pgcFk, + ROUND(SUM(s.quantity * s.price * (100 - s.discount)/100 + ),2) AS taxableBase, + ROUND(SUM(s.quantity * s.price * (100 - s.discount)/100 + ) * pgc.rate / 100,2) AS tax, + 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 + HAVING taxableBase != 0; + + DROP TEMPORARY TABLE IF EXISTS tmp.ticketAmount; + CREATE TEMPORARY TABLE tmp.ticketAmount + (INDEX (ticketFk)) + ENGINE = MEMORY + SELECT ticketFk, taxableBase, SUM(tax) tax + FROM tmp.ticketTax + GROUP BY ticketFk, code; + + DROP TEMPORARY TABLE IF EXISTS tmp.addressCompany; + DROP TEMPORARY TABLE IF EXISTS tmp.addressTaxArea; +END$$ + +DELIMITER ; + diff --git a/services/db/install/dump/fixtures.sql b/services/db/install/dump/fixtures.sql index a53f7b82c..7e8a25d09 100644 --- a/services/db/install/dump/fixtures.sql +++ b/services/db/install/dump/fixtures.sql @@ -517,18 +517,18 @@ INSERT INTO `vn`.`ticketPackaging`(`id`, `ticketFk`, `packagingFk`, `quantity`, INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `price`, `discount`, `reserved`, `isPicked`, `created`) VALUES - ( 1, 1, 1 , 'Gem of Time', 5 , 9.60, 0, 0, 0, CURDATE()), - ( 2, 2, 1 , 'Gem of Mind', 10 , 4.21, 0, 0, 0, CURDATE()), - ( 3, 1, 1 , 'Gem of Time', 2 , 9.60, 0, 0, 0, CURDATE()), - ( 4, 4, 1 , 'Mark I' , 20 , 7.06, 0, 0, 0, CURDATE()), - ( 5, 1, 2 , 'Gem of Time', 10 , 9.60, 0, 0, 0, CURDATE()), - ( 6, 1, 3 , 'Gem of Time', 15 , 9.60, 0, 0, 0, CURDATE()), - ( 7, 2, 11, 'Gem of Mind', 15 , 4.21, 0, 0, 0, CURDATE()), - ( 8, 4, 11, 'Mark I' , 10 , 7.06, 0, 0, 0, CURDATE()), - ( 9, 1, 16, 'Gem of Time', 5 , 9.60, 0, 0, 0, CURDATE()), - ( 10, 2, 16, 'Gem of Mind', 10 , 4.21, 0, 0, 0, CURDATE()), - ( 11, 1, 16, 'Gem of Time', 2 , 9.60, 0, 0, 0, CURDATE()), - ( 12, 4, 16, 'Mark I' , 20 , 7.06, 0, 0, 0, CURDATE()); + ( 1, 1, 1 , 'Gem of Time', 5 , 11.42, 0, 0, 0, CURDATE()), + ( 2, 2, 1 , 'Gem of Mind', 10 , 1.30, 0, 0, 0, CURDATE()), + ( 3, 1, 1 , 'Gem of Time', 2 , 11.42, 0, 0, 0, CURDATE()), + ( 4, 4, 1 , 'Mark I' , 20 , 3.26, 0, 0, 0, CURDATE()), + ( 5, 1, 2 , 'Gem of Time', 10 , 11.42, 0, 0, 0, CURDATE()), + ( 6, 1, 3 , 'Gem of Time', 15 , 11.42, 0, 0, 0, CURDATE()), + ( 7, 2, 11, 'Gem of Mind', 15 , 1.30, 0, 0, 0, CURDATE()), + ( 8, 4, 11, 'Mark I' , 10 , 3.26, 0, 0, 0, CURDATE()), + ( 9, 1, 16, 'Gem of Time', 5 , 11.42, 0, 0, 0, CURDATE()), + ( 10, 2, 16, 'Gem of Mind', 10 , 1.30, 0, 0, 0, CURDATE()), + ( 11, 1, 16, 'Gem of Time', 2 , 11.42, 0, 0, 0, CURDATE()), + ( 12, 4, 16, 'Mark I' , 20 , 3.26, 0, 0, 0, CURDATE()); INSERT INTO `vn`.`saleChecked`(`saleFk`, `isChecked`) VALUES @@ -785,12 +785,12 @@ INSERT INTO `bi`.`claims_ratio`(`id_Cliente`, `Consumo`, `Reclamaciones`, `Ratio INSERT INTO `vn`.`buy`(`id`,`entryFk`,`itemFk`,`buyingValue`,`quantity`,`packageFk`,`stickers`,`freightValue`,`packageValue`,`comissionValue`,`packing`,`grouping`,`groupingMode`,`location`,`price1`,`price2`,`price3`,`minPrice`,`producer`,`printedStickers`,`isChecked`,`isIgnored`, `created`) VALUES - (1, 1, 1, 2.5, 5000 , 1, 1, 0.350, 0.050, 0.000, 1, 1, 0, NULL, 1.50, 1.25, 1.30, 2.00, NULL, 0, 1, 0, DATE_ADD(CURDATE(), INTERVAL -2 MONTH)), - (2, 2, 1, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 1, 1, 0, NULL, 2.50, 1.00, 2.50, 2.00, NULL, 0, 1, 0, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)), - (3, 3, 1, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 1, 1, 0, NULL, 2.50, 1.00, 2.50, 2.00, NULL, 0, 1, 0, CURDATE()), - (4, 2, 2, 5 , 450 , 1, 1, 0.500, 0.100, 0.000, 1, 1, 0, NULL, 2, 1.00, 1.30, 2.00, NULL, 0, 1, 0, CURDATE()), - (5, 3, 3, 10 , 500 , 1, 1, 1.000, 0.050, 0.000, 1, 1, 0, NULL, 2.50, 1.00, 2.50, 2.00, NULL, 0, 1, 0, CURDATE()), - (6, 4, 4, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 1, 1, 0, NULL, 2.50, 1.00, 2.50, 2.00, NULL, 0, 1, 0, CURDATE()); + (1, 1, 1, 2.5, 5000 , 1, 1, 0.350, 0.050, 0.000, 10, 10, 1, NULL, 0.00, 1.30, 1.25, 1.00, NULL, 0, 1, 0, DATE_ADD(CURDATE(), INTERVAL -2 MONTH)), + (2, 2, 1, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 5, 5, 1, NULL, 0.00, 2.50, 2.00, 0.50, NULL, 0, 1, 0, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)), + (3, 3, 1, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 1, 1, 0, NULL, 0.00, 2.50, 2.00, 0.50, NULL, 0, 1, 0, CURDATE()), + (4, 2, 2, 5 , 450 , 1, 1, 0.500, 0.100, 0.000, 10, 10, 0, NULL, 0.00, 1.30, 1.00, 0.00, NULL, 0, 1, 0, CURDATE()), + (5, 3, 3, 10 , 500 , 1, 1, 1.000, 0.050, 0.000, 10, 10, 0, NULL, 0.00, 2.50, 1.00, 0.00, NULL, 0, 1, 0, CURDATE()), + (6, 4, 4, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 10, 10, 1, NULL, 0.00, 2.50, 1.00, 0.00, NULL, 0, 1, 0, CURDATE()); INSERT INTO `vn2008`.`tblContadores`(`id`,`FechaInventario`) VALUES diff --git a/services/loopback/common/methods/client/specs/getDebt.spec.js b/services/loopback/common/methods/client/specs/getDebt.spec.js index 66e026e3d..e406f16e6 100644 --- a/services/loopback/common/methods/client/specs/getDebt.spec.js +++ b/services/loopback/common/methods/client/specs/getDebt.spec.js @@ -4,7 +4,7 @@ describe('client getDebt()', () => { it('should return the client debt', async() => { let result = await app.models.Client.getDebt(101); - expect(result.debt).toEqual(1342.66); + expect(result.debt).toEqual(1048.76); }); }); diff --git a/services/loopback/common/methods/client/specs/summary.spec.js b/services/loopback/common/methods/client/specs/summary.spec.js index fcdb6fa38..4e3c7cec7 100644 --- a/services/loopback/common/methods/client/specs/summary.spec.js +++ b/services/loopback/common/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(1342.66); + expect(result.debt.debt).toEqual(1048.76); }); it('should return a summary object containing averageInvoiced', async() => { diff --git a/services/loopback/common/methods/sale/specs/priceDifference.spec.js b/services/loopback/common/methods/sale/specs/priceDifference.spec.js index 0205cf098..dc562ee57 100644 --- a/services/loopback/common/methods/sale/specs/priceDifference.spec.js +++ b/services/loopback/common/methods/sale/specs/priceDifference.spec.js @@ -10,8 +10,8 @@ describe('sale priceDifference()', () => { }; let result = await app.models.Sale.priceDifference(1, data); - expect(result.totalUnitPrice).toEqual(30.469999999999995); - expect(result.totalNewPrice).toEqual(26.12); - expect(result.totalDifference).toEqual(63.8); + expect(result.totalUnitPrice).toEqual(27.4); + expect(result.totalNewPrice).toEqual(22.33); + expect(result.totalDifference).toEqual(22.54); }); }); diff --git a/services/loopback/common/methods/ticket/getVAT.js b/services/loopback/common/methods/ticket/getVAT.js index 509a0d13c..087697b0c 100644 --- a/services/loopback/common/methods/ticket/getVAT.js +++ b/services/loopback/common/methods/ticket/getVAT.js @@ -27,6 +27,6 @@ module.exports = Self => { totalTax += tax.tax; }); - return totalTax; + return Math.round(totalTax * 100) / 100; }; }; diff --git a/services/loopback/common/methods/ticket/specs/getTaxes.spec.js b/services/loopback/common/methods/ticket/specs/getTaxes.spec.js index d9637ab85..feab81459 100644 --- a/services/loopback/common/methods/ticket/specs/getTaxes.spec.js +++ b/services/loopback/common/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(10.93); + expect(result[0].tax).toEqual(9.29); }); }); diff --git a/services/loopback/common/methods/ticket/specs/getTotal.spec.js b/services/loopback/common/methods/ticket/specs/getTotal.spec.js index 1d211fbba..b80ff3d97 100644 --- a/services/loopback/common/methods/ticket/specs/getTotal.spec.js +++ b/services/loopback/common/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(291.08); + expect(result).toEqual(181.12); }); it(`should return zero if the ticket doesn't have lines`, async() => { diff --git a/services/loopback/common/methods/ticket/specs/getTotalVolume.spec.js b/services/loopback/common/methods/ticket/specs/getTotalVolume.spec.js index c6ed836ec..df566f1c4 100644 --- a/services/loopback/common/methods/ticket/specs/getTotalVolume.spec.js +++ b/services/loopback/common/methods/ticket/specs/getTotalVolume.spec.js @@ -4,7 +4,7 @@ describe('ticket getTotalVolume()', () => { it('should return the total volume of a ticket', async() => { let ticketFk = 1; - let expectedResult = 0.276; + let expectedResult = 0.078; let result = await app.models.Ticket.getTotalVolume(ticketFk); diff --git a/services/loopback/common/methods/ticket/specs/getVAT.spec.js b/services/loopback/common/methods/ticket/specs/getVAT.spec.js index 300744502..629452376 100644 --- a/services/loopback/common/methods/ticket/specs/getVAT.spec.js +++ b/services/loopback/common/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(40.58); + expect(response).toEqual(22.98); }); }); diff --git a/services/loopback/common/methods/ticket/specs/summary.spec.js b/services/loopback/common/methods/ticket/specs/summary.spec.js index 96e0153be..9abb0fecd 100644 --- a/services/loopback/common/methods/ticket/specs/summary.spec.js +++ b/services/loopback/common/methods/ticket/specs/summary.spec.js @@ -17,18 +17,19 @@ describe('ticket summary()', () => { it('should return a summary object containing subTotal for 1 ticket', async() => { let result = await app.models.Ticket.summary(1); - expect(result.subTotal).toEqual(250.5); + expect(result.subTotal).toEqual(158.14); }); it('should return a summary object containing VAT for 1 ticket', async() => { let result = await app.models.Ticket.summary(1); - expect(result.VAT).toEqual(40.58); + expect(Math.round(result.VAT * 100) / 100).toEqual(22.98); }); it('should return a summary object containing total for 1 ticket', async() => { let result = await app.models.Ticket.summary(1); - let expectedTotal = result.subTotal + result.VAT; + let total = result.subTotal + result.VAT; + let expectedTotal = Math.round(total * 100) / 100; expect(result.total).toEqual(expectedTotal); });