ticket subtotal should check service prices #1151
gitea/salix/dev This commit has test failures
Details
gitea/salix/dev This commit has test failures
Details
This commit is contained in:
parent
0f496b9500
commit
06be535115
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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() => {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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() => {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
|
@ -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',
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
</vn-button>
|
||||
</vn-tool-bar>
|
||||
<vn-one class="taxes" ng-if="$ctrl.sales.length > 0">
|
||||
<p><vn-label translate>Subtotal</vn-label> {{$ctrl.subTotal | currency: 'EUR':2}}</p>
|
||||
<p><vn-label translate>Subtotal</vn-label> {{$ctrl.subtotal | currency: 'EUR':2}}</p>
|
||||
<p><vn-label translate>VAT</vn-label> {{$ctrl.VAT | currency: 'EUR':2}}</p>
|
||||
<p><vn-label><strong>Total</strong></vn-label> <strong>{{$ctrl.total | currency: 'EUR':2}}</strong></p>
|
||||
</vn-one>
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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('<vn-ticket-sale ticket="ticket"></vn-ticket-sale>')($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);
|
||||
});
|
||||
|
|
|
@ -46,8 +46,8 @@
|
|||
</vn-label-value>
|
||||
</vn-one>
|
||||
<vn-one class="taxes">
|
||||
<p><vn-label translate>Subtotal</vn-label> {{$ctrl.summary.subTotal | currency: 'EUR':2}}</p>
|
||||
<p><vn-label translate>VAT</vn-label> {{$ctrl.summary.VAT | currency: 'EUR':2}}</p>
|
||||
<p><vn-label translate>Subtotal</vn-label> {{$ctrl.summary.subtotal | currency: 'EUR':2}}</p>
|
||||
<p><vn-label translate>VAT</vn-label> {{$ctrl.summary.vat | currency: 'EUR':2}}</p>
|
||||
<p><vn-label><strong>Total</strong></vn-label> <strong>{{$ctrl.summary.total | currency: 'EUR':2}}</strong></p>
|
||||
</vn-one>
|
||||
<vn-auto name="sales">
|
||||
|
|
|
@ -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 ;
|
|
@ -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 ;
|
Loading…
Reference in New Issue