Merge branch 'test' into 8227-roadmapChanges
gitea/salix/pipeline/pr-test This commit looks good
Details
gitea/salix/pipeline/pr-test This commit looks good
Details
This commit is contained in:
commit
bd53f7367c
|
@ -18,6 +18,7 @@ BEGIN
|
||||||
DECLARE vWithPackage BOOL;
|
DECLARE vWithPackage BOOL;
|
||||||
DECLARE vHasToInvoice BOOL;
|
DECLARE vHasToInvoice BOOL;
|
||||||
DECLARE vSerial VARCHAR(2);
|
DECLARE vSerial VARCHAR(2);
|
||||||
|
DECLARE vStateCode VARCHAR(45);
|
||||||
|
|
||||||
DECLARE cur CURSOR FOR
|
DECLARE cur CURSOR FOR
|
||||||
SELECT ticketFk FROM tmp.ticket_close;
|
SELECT ticketFk FROM tmp.ticket_close;
|
||||||
|
@ -80,27 +81,14 @@ BEGIN
|
||||||
AND getSpecialPrice(e.freightItemFk, vClientFk) > 0
|
AND getSpecialPrice(e.freightItemFk, vClientFk) > 0
|
||||||
GROUP BY e.freightItemFk);
|
GROUP BY e.freightItemFk);
|
||||||
|
|
||||||
IF(vHasDailyInvoice) AND vHasToInvoice THEN
|
|
||||||
SELECT invoiceSerial(vClientFk, vCompanyFk, 'quick') INTO vSerial;
|
|
||||||
IF vSerial IS NULL THEN
|
|
||||||
CALL util.throw('Cannot booking without a serial');
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
CALL ticket_setState(vCurTicketFk, 'DELIVERED');
|
IF vHasDailyInvoice AND vHasToInvoice THEN
|
||||||
|
SET vStateCode = 'DELIVERED';
|
||||||
IF vIsTaxDataChecked THEN
|
|
||||||
CALL invoiceOut_newFromClient(
|
|
||||||
vClientFk,
|
|
||||||
vSerial,
|
|
||||||
vShipped,
|
|
||||||
vCompanyFk,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
vNewInvoiceId);
|
|
||||||
END IF;
|
|
||||||
ELSE
|
ELSE
|
||||||
CALL ticket_setState(vCurTicketFk, (SELECT vn.getAlert3State(vCurTicketFk)));
|
SELECT vn.getAlert3State(vCurTicketFk) INTO vStateCode;
|
||||||
END IF;
|
END IF;
|
||||||
|
CALL ticket_setState(vCurTicketFk, vStateCode);
|
||||||
|
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
CLOSE cur;
|
CLOSE cur;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
DELIMITER $$
|
DELIMITER $$
|
||||||
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`ticket_doCmr`(vSelf INT)
|
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`ticket_doCmr`(
|
||||||
|
vSelf INT
|
||||||
|
)
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Crea u actualiza la información del CMR asociado con
|
* Crea u actualiza la información del CMR asociado con
|
||||||
|
@ -19,6 +21,7 @@ BEGIN
|
||||||
a.id addressFk,
|
a.id addressFk,
|
||||||
c2.defaultAddressFk,
|
c2.defaultAddressFk,
|
||||||
IFNULL(sat.supplierFk, su.id) supplierFk,
|
IFNULL(sat.supplierFk, su.id) supplierFk,
|
||||||
|
t.packages,
|
||||||
t.landed
|
t.landed
|
||||||
FROM ticket t
|
FROM ticket t
|
||||||
JOIN client c ON c.id = t.clientFk
|
JOIN client c ON c.id = t.clientFk
|
||||||
|
@ -52,9 +55,10 @@ BEGIN
|
||||||
c.addressToFk = t.addressFk,
|
c.addressToFk = t.addressFk,
|
||||||
c.addressFromFk = t.defaultAddressFk,
|
c.addressFromFk = t.defaultAddressFk,
|
||||||
c.supplierFk = t.supplierFk,
|
c.supplierFk = t.supplierFk,
|
||||||
|
c.packagesList = t.packages,
|
||||||
c.ead = t.landed
|
c.ead = t.landed
|
||||||
WHERE id = vCmrFk;
|
WHERE id = vCmrFk;
|
||||||
ELSE
|
ELSE
|
||||||
INSERT INTO cmr (
|
INSERT INTO cmr (
|
||||||
senderInstruccions,
|
senderInstruccions,
|
||||||
truckPlate,
|
truckPlate,
|
||||||
|
@ -62,6 +66,7 @@ BEGIN
|
||||||
addressToFk,
|
addressToFk,
|
||||||
addressFromFk,
|
addressFromFk,
|
||||||
supplierFk,
|
supplierFk,
|
||||||
|
packagesList,
|
||||||
ead
|
ead
|
||||||
)
|
)
|
||||||
SELECT * FROM tTicket;
|
SELECT * FROM tTicket;
|
||||||
|
|
|
@ -3,21 +3,25 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`ticket_setState`(
|
||||||
vSelf INT,
|
vSelf INT,
|
||||||
vStateCode VARCHAR(255) COLLATE utf8_general_ci
|
vStateCode VARCHAR(255) COLLATE utf8_general_ci
|
||||||
)
|
)
|
||||||
BEGIN
|
proc:BEGIN
|
||||||
/**
|
/**
|
||||||
* Modifica el estado de un ticket si se cumplen las condiciones necesarias.
|
* Modifica el estado de un ticket si se cumplen las condiciones necesarias.
|
||||||
*
|
*
|
||||||
* @param vSelf el id del ticket
|
* @param vSelf el id del ticket
|
||||||
* @param vStateCode estado a modificar del ticket
|
* @param vStateCode estado a modificar del ticket
|
||||||
*/
|
*/
|
||||||
DECLARE vticketAlertLevel INT;
|
DECLARE vTicketAlertLevel INT;
|
||||||
DECLARE vTicketStateCode VARCHAR(255);
|
DECLARE vTicketStateCode VARCHAR(255) COLLATE utf8_general_ci;
|
||||||
DECLARE vCanChangeState BOOL;
|
DECLARE vCanChangeState BOOL;
|
||||||
DECLARE vPackedAlertLevel INT;
|
DECLARE vPackedAlertLevel INT;
|
||||||
DECLARE vZoneFk INT;
|
DECLARE vZoneFk INT;
|
||||||
|
DECLARE vOldWorkerFk INT;
|
||||||
|
DECLARE vNewWorkerFk INT;
|
||||||
|
|
||||||
SELECT s.alertLevel, s.`code`, t.zoneFk
|
SET vNewWorkerFk = account.myUser_getId();
|
||||||
INTO vticketAlertLevel, vTicketStateCode, vZoneFk
|
|
||||||
|
SELECT s.alertLevel, s.`code`, t.zoneFk, tt.userFk
|
||||||
|
INTO vTicketAlertLevel, vTicketStateCode, vZoneFk, vOldWorkerFk
|
||||||
FROM state s
|
FROM state s
|
||||||
JOIN ticketTracking tt ON tt.stateFk = s.id
|
JOIN ticketTracking tt ON tt.stateFk = s.id
|
||||||
JOIN ticket t ON t.id = tt.ticketFk
|
JOIN ticket t ON t.id = tt.ticketFk
|
||||||
|
@ -33,24 +37,27 @@ BEGIN
|
||||||
|
|
||||||
SET vCanChangeState = ((
|
SET vCanChangeState = ((
|
||||||
vStateCode <> 'ON_CHECKING' AND vStateCode <> 'CHECKED') OR
|
vStateCode <> 'ON_CHECKING' AND vStateCode <> 'CHECKED') OR
|
||||||
vticketAlertLevel < vPackedAlertLevel
|
vTicketAlertLevel < vPackedAlertLevel
|
||||||
)AND NOT (
|
) AND NOT (
|
||||||
vTicketStateCode IN ('CHECKED', 'CHECKING')
|
vTicketStateCode IN ('CHECKED', 'CHECKING')
|
||||||
AND vStateCode IN ('PREPARED', 'ON_PREPARATION')
|
AND vStateCode IN ('PREPARED', 'ON_PREPARATION')
|
||||||
);
|
);
|
||||||
|
|
||||||
IF vCanChangeState THEN
|
IF vCanChangeState THEN
|
||||||
INSERT INTO ticketTracking (stateFk, ticketFk, userFk)
|
|
||||||
SELECT id, vSelf, account.myUser_getId()
|
|
||||||
FROM state
|
|
||||||
WHERE `code` = vStateCode COLLATE utf8_unicode_ci;
|
|
||||||
|
|
||||||
IF vStateCode = 'PACKED' THEN
|
IF vStateCode = 'PACKED' THEN
|
||||||
CALL ticket_doCmr(vSelf);
|
CALL ticket_doCmr(vSelf);
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
|
IF vStateCode = vTicketStateCode AND vOldWorkerFk = vNewWorkerFk THEN
|
||||||
|
LEAVE proc;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
INSERT INTO ticketTracking (stateFk, ticketFk, userFk)
|
||||||
|
SELECT id, vSelf, vNewWorkerFk
|
||||||
|
FROM state
|
||||||
|
WHERE `code` = vStateCode COLLATE utf8_unicode_ci;
|
||||||
ELSE
|
ELSE
|
||||||
CALL util.throw('INCORRECT_TICKET_STATE');
|
CALL util.throw('INCORRECT_TICKET_STATE');
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const closure = require('./closure');
|
const smtp = require('vn-print/core/smtp');
|
||||||
|
const config = require('vn-print/core/config');
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('closeAll', {
|
Self.remoteMethodCtx('closeAll', {
|
||||||
|
@ -25,122 +26,46 @@ module.exports = Self => {
|
||||||
Self.closeAll = async(ctx, options) => {
|
Self.closeAll = async(ctx, options) => {
|
||||||
const userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
const myOptions = {userId};
|
const myOptions = {userId};
|
||||||
|
let tx;
|
||||||
if (typeof options == 'object')
|
if (typeof options == 'object')
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
let tx;
|
if (!myOptions.transaction) {
|
||||||
// IMPORTANT: Due to its high cost in production, wrapping this process in a transaction may cause timeouts.
|
tx = await Self.beginTransaction({});
|
||||||
|
myOptions.transaction = tx;
|
||||||
|
}
|
||||||
const toDate = Date.vnNew();
|
const toDate = Date.vnNew();
|
||||||
toDate.setHours(0, 0, 0, 0);
|
toDate.setHours(0, 0, 0, 0);
|
||||||
toDate.setDate(toDate.getDate() - 1);
|
toDate.setDate(toDate.getDate() - 1);
|
||||||
|
|
||||||
const tickets = await Self.rawSql(`
|
await Self.rawSql(`
|
||||||
SELECT t.id,
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticket_close;
|
||||||
t.clientFk,
|
CREATE TEMPORARY TABLE tmp.ticket_close
|
||||||
t.companyFk,
|
ENGINE = MEMORY
|
||||||
c.id clientFk,
|
SELECT
|
||||||
c.name clientName,
|
DISTINCT t.id ticketFk,
|
||||||
c.email recipient,
|
t.clientFk,
|
||||||
c.salesPersonFk,
|
c.name clientName,
|
||||||
c.isToBeMailed,
|
c.email recipient,
|
||||||
c.hasToInvoice,
|
eu.email salesPersonEmail,
|
||||||
c.hasDailyInvoice,
|
t.addressFk,
|
||||||
eu.email salesPersonEmail,
|
c.hasDailyInvoice,
|
||||||
t.addressFk
|
c.hasToInvoiceByAddress,
|
||||||
FROM ticket t
|
t.totalWithVat,
|
||||||
JOIN agencyMode am ON am.id = t.agencyModeFk
|
t.companyFk
|
||||||
JOIN warehouse wh ON wh.id = t.warehouseFk AND wh.hasComission
|
FROM ticket t
|
||||||
JOIN ticketState ts ON ts.ticketFk = t.id
|
JOIN agencyMode am ON am.id = t.agencyModeFk
|
||||||
JOIN alertLevel al ON al.id = ts.alertLevel
|
JOIN warehouse wh ON wh.id = t.warehouseFk AND wh.hasComission
|
||||||
JOIN client c ON c.id = t.clientFk
|
JOIN ticketState ts ON ts.ticketFk = t.id
|
||||||
JOIN province p ON p.id = c.provinceFk
|
JOIN alertLevel al ON al.id = ts.alertLevel
|
||||||
JOIN country co ON co.id = p.countryFk
|
JOIN client c ON c.id = t.clientFk
|
||||||
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
||||||
JOIN ticketConfig tc ON TRUE
|
JOIN ticketConfig tc ON TRUE
|
||||||
WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered'))
|
WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered'))
|
||||||
AND t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?)
|
AND t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?)
|
||||||
AND t.refFk IS NULL
|
AND t.refFk IS NULL;
|
||||||
GROUP BY t.id
|
CALL ticket_close();
|
||||||
`, [toDate, toDate], myOptions);
|
`, [toDate, toDate], myOptions);
|
||||||
const ticketIds = tickets.map(ticket => ticket.id);
|
|
||||||
await Self.rawSql(`
|
|
||||||
INSERT INTO util.debug (variable, value)
|
|
||||||
VALUES ('nightInvoicing', ?)
|
|
||||||
`, [ticketIds.join(',')], myOptions);
|
|
||||||
|
|
||||||
await Self.rawSql(`
|
|
||||||
WITH ticketNotInvoiceable AS(
|
|
||||||
SELECT JSON_OBJECT(
|
|
||||||
'tickets',
|
|
||||||
JSON_ARRAYAGG(
|
|
||||||
JSON_OBJECT(
|
|
||||||
'ticketId', ticketFk,
|
|
||||||
'reason', reason,
|
|
||||||
'clientId', clientFk
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)errors
|
|
||||||
FROM (
|
|
||||||
SELECT ticketFk,
|
|
||||||
CONCAT_WS(', ',
|
|
||||||
IF(hasErrorToInvoice, 'Facturar', NULL),
|
|
||||||
IF(hasErrorTaxDataChecked, 'Datos comprobados', NULL),
|
|
||||||
IF(hasErrorDeleted, 'Eliminado', NULL),
|
|
||||||
IF(hasErrorItemTaxCountry, 'Impuesto no informado', NULL),
|
|
||||||
IF(hasErrorAddress, 'Sin dirección', NULL),
|
|
||||||
IF(hasErrorInfoTaxAreaWorld, 'Datos exportaciones', NULL)) reason,
|
|
||||||
clientFk
|
|
||||||
FROM (
|
|
||||||
SELECT t.id ticketFk,
|
|
||||||
SUM(NOT c.hasToInvoice) hasErrorToInvoice,
|
|
||||||
SUM(NOT c.isTaxDataChecked) hasErrorTaxDataChecked,
|
|
||||||
SUM(t.isDeleted) hasErrorDeleted,
|
|
||||||
SUM(itc.id IS NULL) hasErrorItemTaxCountry,
|
|
||||||
SUM(a.id IS NULL) hasErrorAddress,
|
|
||||||
SUM(ios.code IS NOT NULL
|
|
||||||
AND(ad.customsAgentFk IS NULL
|
|
||||||
OR ad.incotermsFk IS NULL)) hasErrorInfoTaxAreaWorld,
|
|
||||||
t.clientFk clientFk
|
|
||||||
FROM ticket t
|
|
||||||
LEFT JOIN address ad ON ad.id = t.addressFk
|
|
||||||
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 agencyMode am ON am.id = t.agencyModeFk
|
|
||||||
JOIN warehouse wh ON wh.id = t.warehouseFk AND wh.hasComission
|
|
||||||
JOIN ticketState ts ON ts.ticketFk = t.id
|
|
||||||
JOIN alertLevel al ON al.id = ts.alertLevel
|
|
||||||
JOIN client c ON c.id = t.clientFk
|
|
||||||
JOIN province p ON p.id = c.provinceFk
|
|
||||||
JOIN ticketConfig tc ON TRUE
|
|
||||||
LEFT JOIN autonomy a ON a.id = p.autonomyFk
|
|
||||||
JOIN country co ON co.id = p.countryFk
|
|
||||||
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
|
||||||
LEFT JOIN itemTaxCountry itc ON itc.itemFk = i.id
|
|
||||||
AND itc.countryFk = su.countryFk
|
|
||||||
LEFT JOIN vn.invoiceOutSerial ios ON ios.taxAreaFk = 'WORLD'
|
|
||||||
AND ios.code = invoiceSerial(t.clientFk, t.companyFk, 'multiple')
|
|
||||||
WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered'))
|
|
||||||
AND t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?)
|
|
||||||
AND t.refFk IS NULL
|
|
||||||
AND c.hasDailyInvoice
|
|
||||||
GROUP BY ticketFk
|
|
||||||
HAVING hasErrorToInvoice
|
|
||||||
OR hasErrorTaxDataChecked
|
|
||||||
OR hasErrorDeleted
|
|
||||||
OR hasErrorItemTaxCountry
|
|
||||||
OR hasErrorAddress
|
|
||||||
OR hasErrorInfoTaxAreaWorld
|
|
||||||
)sub
|
|
||||||
)sub2
|
|
||||||
) SELECT IF(errors = '{"tickets": null}',
|
|
||||||
'No errors',
|
|
||||||
util.notification_send('invoice-ticket-closure', errors, NULL))
|
|
||||||
FROM ticketNotInvoiceable`, [toDate, toDate], myOptions);
|
|
||||||
|
|
||||||
await closure(ctx, Self, tickets, myOptions);
|
|
||||||
|
|
||||||
await Self.rawSql(`
|
await Self.rawSql(`
|
||||||
UPDATE ticket t
|
UPDATE ticket t
|
||||||
|
@ -157,11 +82,95 @@ module.exports = Self => {
|
||||||
AND tob.id IS NULL
|
AND tob.id IS NULL
|
||||||
AND t.routeFk`, [toDate, toDate], myOptions);
|
AND t.routeFk`, [toDate, toDate], myOptions);
|
||||||
|
|
||||||
|
const [clients] = await Self.rawSql(`
|
||||||
|
SELECT clientFk clientId,
|
||||||
|
clientName,
|
||||||
|
recipient,
|
||||||
|
salesPersonEmail,
|
||||||
|
addressFk addressId,
|
||||||
|
companyFk,
|
||||||
|
SUM(totalWithVat) total,
|
||||||
|
'quick' serialType
|
||||||
|
FROM tmp.ticket_close
|
||||||
|
WHERE hasDailyInvoice
|
||||||
|
GROUP BY IF (hasToInvoiceByAddress, addressFk, clientFk), companyFk
|
||||||
|
HAVING total > 0;
|
||||||
|
DROP TEMPORARY TABLE tmp.ticket_close;
|
||||||
|
`, [], myOptions);
|
||||||
|
|
||||||
if (tx)
|
if (tx)
|
||||||
await tx.commit();
|
await tx.commit();
|
||||||
|
|
||||||
|
const failedClients = [];
|
||||||
|
// Only for testing
|
||||||
|
const nestedTransaction = options?.transaction ? myOptions : {};
|
||||||
|
for (const client of clients) {
|
||||||
|
ctx.args = {
|
||||||
|
...client,
|
||||||
|
invoiceDate: Date.vnNew(),
|
||||||
|
maxShipped: toDate
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const id = await Self.app.models.InvoiceOut.invoiceClient(ctx, nestedTransaction);
|
||||||
|
if (id)
|
||||||
|
await Self.app.models.InvoiceOut.makePdfAndNotify(ctx, id, null, nestedTransaction);
|
||||||
|
} catch (error) {
|
||||||
|
await Self.rawSql(`
|
||||||
|
INSERT INTO util.debug (variable, value)
|
||||||
|
VALUES ('invoicingTicketError', ?)
|
||||||
|
`, [client.clientId + ' - ' + error]);
|
||||||
|
|
||||||
|
if (error.responseCode == 450) {
|
||||||
|
await invalidEmail(client);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
failedClients.push({
|
||||||
|
id: client.clientId,
|
||||||
|
address: client.addressId,
|
||||||
|
error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failedClients.length > 0) {
|
||||||
|
let body = 'This following tickets have failed:<br/><br/>';
|
||||||
|
|
||||||
|
for (const client of failedClients) {
|
||||||
|
body += `Client: <strong>${client.id}</strong>
|
||||||
|
Address: <strong>${client.address}</strong>
|
||||||
|
<br/> <strong>${client.error}</strong><br/><br/>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
smtp.send({
|
||||||
|
to: config.app.reportEmail,
|
||||||
|
subject: '[API] Nightly ticket closure report',
|
||||||
|
html: body,
|
||||||
|
}).catch(err => console.error(err));
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: 'Success'
|
message: 'Success'
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function invalidEmail(client) {
|
||||||
|
await Self.rawSql(
|
||||||
|
`UPDATE client SET email = NULL WHERE id = ?`,
|
||||||
|
[client.clientId],
|
||||||
|
myOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
const body = `No se ha podido facturar al cliente <strong>${client.clientId} - ${client.clientName}</strong>
|
||||||
|
porque la dirección de email <strong>"${client.recipient}"</strong> no es correcta
|
||||||
|
o no está disponible.<br/><br/>
|
||||||
|
Para evitar que se repita este error, se ha eliminado la dirección de email de la ficha del cliente.
|
||||||
|
Actualiza la dirección de email con una correcta.`;
|
||||||
|
|
||||||
|
smtp.send({
|
||||||
|
to: client.salesPersonEmail,
|
||||||
|
subject: 'No se ha podido enviar el albarán',
|
||||||
|
html: body,
|
||||||
|
}).catch(err => console.error(err));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
<td width="5%">{{sale.itemFk}}</td>
|
<td width="5%">{{sale.itemFk}}</td>
|
||||||
<td class="number">{{sale.quantity}}</td>
|
<td class="number">{{sale.quantity}}</td>
|
||||||
<td width="50%">{{sale.concept}}</td>
|
<td width="50%">{{sale.concept}}</td>
|
||||||
<td width="5%" class="font light-gray" v-if="sale.subName">{{sale.subName}}</td>
|
<td width="5%" class="font light-gray">{{sale.subName}}</td>
|
||||||
<td class="number" v-if="showPrices">{{sale.price | currency('EUR', $i18n.locale)}}</td>
|
<td class="number" v-if="showPrices">{{sale.price | currency('EUR', $i18n.locale)}}</td>
|
||||||
<td class="centered" width="5%" v-if="showPrices">{{(sale.discount / 100) | percentage}}</td>
|
<td class="centered" width="5%" v-if="showPrices">{{(sale.discount / 100) | percentage}}</td>
|
||||||
<td class="centered" v-if="showPrices">{{sale.vatType}}</td>
|
<td class="centered" v-if="showPrices">{{sale.vatType}}</td>
|
||||||
|
|
Loading…
Reference in New Issue