5995-newCmr #1698
|
@ -0,0 +1,36 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('cmr', {
|
||||
description: 'Returns the cmr',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The cmr id',
|
||||
http: {source: 'path'}
|
||||
}
|
||||
],
|
||||
returns: [
|
||||
{
|
||||
arg: 'body',
|
||||
type: 'file',
|
||||
root: true
|
||||
}, {
|
||||
arg: 'Content-Type',
|
||||
type: 'String',
|
||||
http: {target: 'header'}
|
||||
}, {
|
||||
arg: 'Content-Disposition',
|
||||
type: 'String',
|
||||
http: {target: 'header'}
|
||||
}
|
||||
],
|
||||
http: {
|
||||
path: '/:id/cmr',
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.cmr = (ctx, id) => Self.printReport(ctx, id, 'cmr');
|
||||
};
|
|
@ -14,6 +14,7 @@ module.exports = Self => {
|
|||
require('../methods/route/driverRouteEmail')(Self);
|
||||
require('../methods/route/sendSms')(Self);
|
||||
require('../methods/route/downloadZip')(Self);
|
||||
require('../methods/route/cmr')(Self);
|
||||
|
||||
Self.validate('kmStart', validateDistance, {
|
||||
message: 'Distance must be lesser than 1000'
|
||||
|
|
|
@ -5,177 +5,208 @@ const config = require('vn-print/core/config');
|
|||
const storage = require('vn-print/core/storage');
|
||||
|
||||
module.exports = async function(ctx, Self, tickets, reqArgs = {}) {
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
if (tickets.length == 0) return;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
if (tickets.length == 0) return;
|
||||
|
||||
const failedtickets = [];
|
||||
for (const ticket of tickets) {
|
||||
try {
|
||||
await Self.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id], {userId});
|
||||
const failedtickets = [];
|
||||
for (const ticket of tickets) {
|
||||
try {
|
||||
await Self.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id], {userId});
|
||||
|
||||
const [invoiceOut] = await Self.rawSql(`
|
||||
SELECT io.id, io.ref, io.serial, cny.code companyCode, io.issued
|
||||
FROM ticket t
|
||||
JOIN invoiceOut io ON io.ref = t.refFk
|
||||
JOIN company cny ON cny.id = io.companyFk
|
||||
WHERE t.id = ?
|
||||
`, [ticket.id]);
|
||||
const [invoiceOut] = await Self.rawSql(`
|
||||
SELECT io.id, io.ref, io.serial, cny.code companyCode, io.issued
|
||||
FROM ticket t
|
||||
JOIN invoiceOut io ON io.ref = t.refFk
|
||||
JOIN company cny ON cny.id = io.companyFk
|
||||
WHERE t.id = ?
|
||||
`, [ticket.id]);
|
||||
|
||||
const mailOptions = {
|
||||
overrideAttachments: true,
|
||||
attachments: []
|
||||
};
|
||||
const mailOptions = {
|
||||
overrideAttachments: true,
|
||||
attachments: []
|
||||
};
|
||||
|
||||
const isToBeMailed = ticket.recipient && ticket.salesPersonFk && ticket.isToBeMailed;
|
||||
const isToBeMailed = ticket.recipient && ticket.salesPersonFk && ticket.isToBeMailed;
|
||||
|
||||
if (invoiceOut) {
|
||||
const args = {
|
||||
reference: invoiceOut.ref,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
if (invoiceOut) {
|
||||
const args = {
|
||||
reference: invoiceOut.ref,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
|
||||
const invoiceReport = new Report('invoice', args);
|
||||
const stream = await invoiceReport.toPdfStream();
|
||||
const invoiceReport = new Report('invoice', args);
|
||||
const stream = await invoiceReport.toPdfStream();
|
||||
|
||||
const issued = invoiceOut.issued;
|
||||
const year = issued.getFullYear().toString();
|
||||
const month = (issued.getMonth() + 1).toString();
|
||||
const day = issued.getDate().toString();
|
||||
const issued = invoiceOut.issued;
|
||||
const year = issued.getFullYear().toString();
|
||||
const month = (issued.getMonth() + 1).toString();
|
||||
const day = issued.getDate().toString();
|
||||
|
||||
const fileName = `${year}${invoiceOut.ref}.pdf`;
|
||||
const fileName = `${year}${invoiceOut.ref}.pdf`;
|
||||
|
||||
// Store invoice
|
||||
await storage.write(stream, {
|
||||
type: 'invoice',
|
||||
path: `${year}/${month}/${day}`,
|
||||
fileName: fileName
|
||||
});
|
||||
// Store invoice
|
||||
await storage.write(stream, {
|
||||
type: 'invoice',
|
||||
path: `${year}/${month}/${day}`,
|
||||
fileName: fileName
|
||||
});
|
||||
|
||||
await Self.rawSql('UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id], {userId});
|
||||
await Self.rawSql('UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id], {userId});
|
||||
|
||||
if (isToBeMailed) {
|
||||
const invoiceAttachment = {
|
||||
filename: fileName,
|
||||
content: stream
|
||||
};
|
||||
if (isToBeMailed) {
|
||||
const invoiceAttachment = {
|
||||
filename: fileName,
|
||||
content: stream
|
||||
};
|
||||
|
||||
if (invoiceOut.serial == 'E' && invoiceOut.companyCode == 'VNL') {
|
||||
const exportation = new Report('exportation', args);
|
||||
const stream = await exportation.toPdfStream();
|
||||
const fileName = `CITES-${invoiceOut.ref}.pdf`;
|
||||
if (invoiceOut.serial == 'E' && invoiceOut.companyCode == 'VNL') {
|
||||
const exportation = new Report('exportation', args);
|
||||
const stream = await exportation.toPdfStream();
|
||||
const fileName = `CITES-${invoiceOut.ref}.pdf`;
|
||||
|
||||
mailOptions.attachments.push({
|
||||
filename: fileName,
|
||||
content: stream
|
||||
});
|
||||
}
|
||||
mailOptions.attachments.push({
|
||||
filename: fileName,
|
||||
content: stream
|
||||
});
|
||||
}
|
||||
|
||||
mailOptions.attachments.push(invoiceAttachment);
|
||||
mailOptions.attachments.push(invoiceAttachment);
|
||||
|
||||
const email = new Email('invoice', args);
|
||||
await email.send(mailOptions);
|
||||
}
|
||||
} else if (isToBeMailed) {
|
||||
const args = {
|
||||
id: ticket.id,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
const email = new Email('invoice', args);
|
||||
await email.send(mailOptions);
|
||||
}
|
||||
} else if (isToBeMailed) {
|
||||
const args = {
|
||||
id: ticket.id,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
|
||||
const email = new Email('delivery-note-link', args);
|
||||
await email.send();
|
||||
}
|
||||
const email = new Email('delivery-note-link', args);
|
||||
await email.send();
|
||||
}
|
||||
|
||||
// Incoterms authorization
|
||||
const [{firstOrder}] = await Self.rawSql(`
|
||||
SELECT COUNT(*) as firstOrder
|
||||
FROM ticket t
|
||||
JOIN client c ON c.id = t.clientFk
|
||||
WHERE t.clientFk = ?
|
||||
AND NOT t.isDeleted
|
||||
AND c.isVies
|
||||
`, [ticket.clientFk]);
|
||||
// Incoterms authorization
|
||||
const [{firstOrder}] = await Self.rawSql(`
|
||||
SELECT COUNT(*) as firstOrder
|
||||
FROM ticket t
|
||||
JOIN client c ON c.id = t.clientFk
|
||||
WHERE t.clientFk = ?
|
||||
AND NOT t.isDeleted
|
||||
AND c.isVies
|
||||
`, [ticket.clientFk]);
|
||||
|
||||
if (firstOrder == 1) {
|
||||
const args = {
|
||||
id: ticket.clientFk,
|
||||
companyId: ticket.companyFk,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
if (firstOrder == 1) {
|
||||
const args = {
|
||||
id: ticket.clientFk,
|
||||
companyId: ticket.companyFk,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
};
|
||||
|
||||
const email = new Email('incoterms-authorization', args);
|
||||
await email.send();
|
||||
const email = new Email('incoterms-authorization', args);
|
||||
await email.send();
|
||||
|
||||
const [sample] = await Self.rawSql(
|
||||
`SELECT id
|
||||
FROM sample
|
||||
WHERE code = 'incoterms-authorization'
|
||||
`);
|
||||
const [sample] = await Self.rawSql(
|
||||
`SELECT id
|
||||
FROM sample
|
||||
WHERE code = 'incoterms-authorization'
|
||||
`);
|
||||
|
||||
await Self.rawSql(`
|
||||
INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?)
|
||||
`, [ticket.clientFk, sample.id, ticket.companyFk], {userId});
|
||||
}
|
||||
} catch (error) {
|
||||
// Domain not found
|
||||
if (error.responseCode == 450)
|
||||
return invalidEmail(ticket);
|
||||
await Self.rawSql(`
|
||||
INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?)
|
||||
`, [ticket.clientFk, sample.id, ticket.companyFk], {userId});
|
||||
}
|
||||
|
||||
// Save tickets on a list of failed ids
|
||||
failedtickets.push({
|
||||
id: ticket.id,
|
||||
stacktrace: error
|
||||
});
|
||||
}
|
||||
}
|
||||
await Self.rawSql(`
|
||||
INSERT INTO cmr (ticketFk, companyFk, addressToFk, addressFromFk, supplierFk, ead)
|
||||
SELECT t.id,
|
||||
com.id,
|
||||
a.id,
|
||||
c2.defaultAddressFk,
|
||||
su.id,
|
||||
t.landed
|
||||
FROM ticket t
|
||||
JOIN ticketState ts ON ts.ticketFk = t.id
|
||||
JOIN state s ON s.id = ts.stateFk
|
||||
JOIN alertLevel al ON al.id = s.alertLevel
|
||||
JOIN client c ON c.id = t.clientFk
|
||||
JOIN address a ON a.id = t.addressFk
|
||||
JOIN province p ON p.id = a.provinceFk
|
||||
JOIN country co ON co.id = p.countryFk
|
||||
JOIN agencyMode am ON am.id = t.agencyModeFk
|
||||
JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
|
||||
JOIN warehouse w ON w.id = t.warehouseFk
|
||||
JOIN company com ON com.id = t.companyFk
|
||||
JOIN client c2 ON c2.id = com.clientFk
|
||||
JOIN supplierAccount sa ON sa.id = com.supplierAccountFk
|
||||
JOIN supplier su ON su.id = sa.supplierFk
|
||||
WHERE shipped BETWEEN util.yesterday() AND util.dayEnd(util.yesterday())
|
||||
AND al.code IN ('PACKED', 'DELIVERED')
|
||||
AND co.code <> 'ES'
|
||||
AND am.name <> 'ABONO'
|
||||
AND w.code = 'ALG'
|
||||
AND dm.code = 'DELIVERY'
|
||||
`);
|
||||
} catch (error) {
|
||||
// Domain not found
|
||||
if (error.responseCode == 450)
|
||||
return invalidEmail(ticket);
|
||||
|
||||
// Send email with failed tickets
|
||||
if (failedtickets.length > 0) {
|
||||
let body = 'This following tickets have failed:<br/><br/>';
|
||||
// Save tickets on a list of failed ids
|
||||
failedtickets.push({
|
||||
id: ticket.id,
|
||||
stacktrace: error
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const ticket of failedtickets) {
|
||||
body += `Ticket: <strong>${ticket.id}</strong>
|
||||
<br/> <strong>${ticket.stacktrace}</strong><br/><br/>`;
|
||||
}
|
||||
// Send email with failed tickets
|
||||
if (failedtickets.length > 0) {
|
||||
let body = 'This following tickets have failed:<br/><br/>';
|
||||
|
||||
smtp.send({
|
||||
to: config.app.reportEmail,
|
||||
subject: '[API] Nightly ticket closure report',
|
||||
html: body
|
||||
});
|
||||
}
|
||||
for (const ticket of failedtickets) {
|
||||
body += `Ticket: <strong>${ticket.id}</strong>
|
||||
<br/> <strong>${ticket.stacktrace}</strong><br/><br/>`;
|
||||
}
|
||||
|
||||
async function invalidEmail(ticket) {
|
||||
await Self.rawSql(`UPDATE client SET email = NULL WHERE id = ?`, [
|
||||
ticket.clientFk
|
||||
], {userId});
|
||||
smtp.send({
|
||||
to: config.app.reportEmail,
|
||||
subject: '[API] Nightly ticket closure report',
|
||||
html: body
|
||||
});
|
||||
}
|
||||
|
||||
const oldInstance = `{"email": "${ticket.recipient}"}`;
|
||||
const newInstance = `{"email": ""}`;
|
||||
await Self.rawSql(`
|
||||
INSERT INTO clientLog (originFk, userFk, action, changedModel, oldInstance, newInstance)
|
||||
VALUES (?, NULL, 'UPDATE', 'Client', ?, ?)`, [
|
||||
ticket.clientFk,
|
||||
oldInstance,
|
||||
newInstance
|
||||
], {userId});
|
||||
async function invalidEmail(ticket) {
|
||||
await Self.rawSql(`UPDATE client SET email = NULL WHERE id = ?`, [
|
||||
ticket.clientFk
|
||||
], {userId});
|
||||
|
||||
const body = `No se ha podido enviar el albarán <strong>${ticket.id}</strong>
|
||||
al cliente <strong>${ticket.clientFk} - ${ticket.clientName}</strong>
|
||||
porque la dirección de email <strong>"${ticket.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.`;
|
||||
const oldInstance = `{"email": "${ticket.recipient}"}`;
|
||||
const newInstance = `{"email": ""}`;
|
||||
await Self.rawSql(`
|
||||
INSERT INTO clientLog (originFk, userFk, action, changedModel, oldInstance, newInstance)
|
||||
VALUES (?, NULL, 'UPDATE', 'Client', ?, ?)`, [
|
||||
ticket.clientFk,
|
||||
oldInstance,
|
||||
newInstance
|
||||
], {userId});
|
||||
|
||||
smtp.send({
|
||||
to: ticket.salesPersonEmail,
|
||||
subject: 'No se ha podido enviar el albarán',
|
||||
html: body
|
||||
});
|
||||
}
|
||||
const body = `No se ha podido enviar el albarán <strong>${ticket.id}</strong>
|
||||
al cliente <strong>${ticket.clientFk} - ${ticket.clientName}</strong>
|
||||
porque la dirección de email <strong>"${ticket.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: ticket.salesPersonEmail,
|
||||
subject: 'No se ha podido enviar el albarán',
|
||||
html: body
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
const Stylesheet = require(`vn-print/core/stylesheet`);
|
||||
|
||||
const path = require('path');
|
||||
const vnPrintPath = path.resolve('print');
|
||||
|
||||
module.exports = new Stylesheet([
|
||||
`${vnPrintPath}/common/css/spacing.css`,
|
||||
`${vnPrintPath}/common/css/misc.css`,
|
||||
`${vnPrintPath}/common/css/layout.css`,
|
||||
`${vnPrintPath}/common/css/report.css`,
|
||||
`${__dirname}/style.css`])
|
||||
.mergeStyles();
|
|
@ -0,0 +1,101 @@
|
|||
html {
|
||||
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
|
||||
margin: 10px;
|
||||
font-size: 22px;
|
||||
}
|
||||
.mainTable, .specialTable, .categoryTable {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: inherit;
|
||||
}
|
||||
.mainTable td {
|
||||
width: 50%;
|
||||
border: 1px solid black;
|
||||
vertical-align: top;
|
||||
padding: 15px;
|
||||
font-size: inherit;
|
||||
}
|
||||
.signTable {
|
||||
height: 12%;
|
||||
}
|
||||
.signTable td {
|
||||
width: calc(100% / 3);
|
||||
border: 1px solid black;
|
||||
vertical-align: top;
|
||||
font-size: inherit;
|
||||
padding: 15px;
|
||||
border-top: none;
|
||||
}
|
||||
#title {
|
||||
font-weight: bold;
|
||||
font-size: 85px;
|
||||
}
|
||||
hr {
|
||||
border: 1px solid #cccccc;
|
||||
height: 0px;
|
||||
border-radius: 25px;
|
||||
}
|
||||
#cellHeader {
|
||||
border: 0px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#label, #merchandiseLabels {
|
||||
font-size: 13px;
|
||||
}
|
||||
#merchandiseLabels {
|
||||
border: none;
|
||||
}
|
||||
.imgSection {
|
||||
text-align: center;
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
}
|
||||
img {
|
||||
object-fit: contain;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
#lineBreak {
|
||||
white-space: pre-line;
|
||||
}
|
||||
.specialTable td {
|
||||
border: 1px solid black;
|
||||
vertical-align: top;
|
||||
padding: 15px;
|
||||
font-size: inherit;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
.specialTable #itemCategoryList {
|
||||
width: 70%;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.categoryTable {
|
||||
padding-bottom: none;
|
||||
}
|
||||
.categoryTable td {
|
||||
vertical-align: top;
|
||||
font-size: inherit;
|
||||
border: none;
|
||||
padding: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.categoryTable #merchandiseLabels {
|
||||
border-bottom: 4px solid #cccccc;
|
||||
padding: none;
|
||||
}
|
||||
#merchandiseDetail {
|
||||
font-weight: bold;
|
||||
padding-top: 10px;
|
||||
}
|
||||
#merchandiseData {
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
#merchandiseLabels td {
|
||||
padding-bottom: 11px;
|
||||
max-width: 300px;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -0,0 +1,212 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
<table class="mainTable">
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">1. Remitente / Expediteur / Sender</span>
|
||||
<hr>
|
||||
<b>{{data.senderName}}</b><br>
|
||||
{{data.senderStreet}}<br>
|
||||
{{data.senderPostCode}} {{data.senderCity}} {{(data.senderCountry) ? `(${data.senderCountry})` : null}}
|
||||
</td>
|
||||
<td id="cellHeader">
|
||||
<span id="title">CMR</span><br>
|
||||
{{data.cmrFk}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">2. Consignatario / Destinataire / Consignee</span>
|
||||
<hr>
|
||||
<b>{{data.deliveryAddressFk}}<br>
|
||||
{{data.deliveryName}}<br>
|
||||
{{data.deliveryPhone || data.clientPhone}}
|
||||
{{((data.deliveryPhone || data.clientPhone) && data.deliveryMobile) ? '/' : null}}
|
||||
{{data.deliveryMobile}}</b>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">16. Transportista / Transporteur / Carrier</span>
|
||||
<hr>
|
||||
<b>{{data.carrierName}}</b><br>
|
||||
{{data.carrierStreet}}<br>
|
||||
{{data.carrierPostalCode}} {{data.carrierCity}} {{(data.carrierCountry) ? `(${data.carrierCountry})` : null}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
3. Lugar y fecha de entrega /
|
||||
Lieu et date de livraison /
|
||||
Place and date of delivery
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.deliveryStreet}}<br>
|
||||
{{data.deliveryPostalCode}} {{data.deliveryCity}} {{(data.deliveryCountry) ? `(${data.deliveryCountry})` : null}}<br>
|
||||
{{(data.ead) ? formatDate(data.ead, '%d/%m/%Y') : null}}</b>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">17. Porteadores sucesivos / Transporteurs succesifs / Succesive Carriers</span>
|
||||
<hr>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
4. Lugar y fecha de carga /
|
||||
Lieu et date del prise en charge de la merchandise /
|
||||
Place and date of taking over the goods
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.loadStreet}}<br>
|
||||
{{data.loadPostalCode}} {{data.loadCity}} {{(data.loadCountry) ? `(${data.loadCountry})` : null}}<br>
|
||||
{{formatDate(data.created, '%d/%m/%Y')}}</b>
|
||||
</td>
|
||||
<td rowspan="2">
|
||||
<span id="label">
|
||||
18. Obervaciones del transportista /
|
||||
Reserves et observations du transporteur /
|
||||
Carrier's reservations and observations
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.truckPlate}}</b><br>
|
||||
{{data.observations}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">5. Documentos anexos / Documents annexes / Documents attached</span>
|
||||
<hr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="specialTable">
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
7 & 8. Número de bultos y clase de embalage /
|
||||
Number of packages and packaging class /
|
||||
Nombre de colis et classe d'emballage
|
||||
</span>
|
||||
<hr>
|
||||
<div id="lineBreak">
|
||||
<b>{{data.packagesList}}</b>
|
||||
</div>
|
||||
</td>
|
||||
<td id="itemCategoryList">
|
||||
<table class="categoryTable">
|
||||
<tr id="merchandiseLabels">
|
||||
<td>6. Marcas y números / Brands and numbers / Marques et numéros</td>
|
||||
<td>9. Naturaleza de la merc. / Nature of goods / Nature des marchandises</td>
|
||||
<td>10. nº Estadístico / Statistical no. / n° statistique</td>
|
||||
<td>11. Peso bruto / Gross weight / Poids brut (kg)</td>
|
||||
<td>12. Volumen / Volume (m3)</td>
|
||||
</tr>
|
||||
<tr v-for="merchandise in merchandises" id="merchandiseData">
|
||||
<td>{{merchandise.ticketFk}}</td>
|
||||
<td>{{merchandise.name}}</td>
|
||||
<td>N/A</td>
|
||||
<td>{{merchandise.weight}}</td>
|
||||
<td>{{merchandise.volume}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div v-if="!merchandises" id="merchandiseDetail">
|
||||
{{data.merchandiseDetail}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="mainTable">
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
13. Instrucciones del remitente /
|
||||
Instrunstions de l'expèditeur / Sender
|
||||
instruccions
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.senderInstruccions}}</b>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">
|
||||
19. Estipulaciones particulares /
|
||||
Conventions particulieres /
|
||||
Special agreements
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.specialAgreements}}</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
14. Forma de pago /
|
||||
Prescriptions d'affranchissement /
|
||||
Instruction as to payment for carriage
|
||||
</span>
|
||||
<hr>
|
||||
<b>{{data.paymentInstruccions}}</b>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">20. A pagar por / Être payé pour / To be paid by</span>
|
||||
<hr>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">21. Formalizado en / Etabile a / Estabilshed in</span>
|
||||
<hr>
|
||||
<b>{{data.loadStreet}}</b><br>
|
||||
{{data.loadPostalCode}} {{data.loadCity}} {{(data.loadCountry) ? `(${data.loadCountry})` : null}} <br>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">15. Reembolso / Remboursement / Cash on delivery</span>
|
||||
<hr>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<table class="signTable">
|
||||
<tr>
|
||||
<td>
|
||||
<span id="label">
|
||||
22. Firma y sello del remitente /
|
||||
Signature et timbre de l'expèditeur /
|
||||
Signature and stamp of the sender
|
||||
</span>
|
||||
<hr>
|
||||
<div class="imgSection">
|
||||
<img v-bind:src="getReportSrc('signature.png')"/>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">
|
||||
23. Firma y sello del transportista /
|
||||
Signature et timbre du transporteur /
|
||||
Signature and stamp of the carrier
|
||||
</span>
|
||||
<hr>
|
||||
<div class="imgSection">
|
||||
<img v-bind:src="dmsPath"/>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span id="label">
|
||||
24. Firma y sello del consignatario /
|
||||
Signature et timbre du destinataire /
|
||||
Signature and stamp of the consignee
|
||||
</span>
|
||||
<hr>
|
||||
<div class="imgSection">
|
||||
<img v-bind:src="dmsPath(true)"/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,38 @@
|
|||
const config = require(`vn-print/core/config`);
|
||||
const vnReport = require('../../../core/mixins/vn-report.js');
|
||||
const md5 = require('md5');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
module.exports = {
|
||||
name: 'cmr',
|
||||
mixins: [vnReport],
|
||||
async serverPrefetch() {
|
||||
this.data = await this.findOneFromDef('data', [this.id]);
|
||||
if (this.data.ticketFk) {
|
||||
this.merchandises = await this.rawSqlFromDef('merchandise', [this.data.ticketFk]);
|
||||
this.signatures = await this.findOneFromDef('signatures', [this.data.ticketFk]);
|
||||
}
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
description: 'The cmr id'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
dmsPath(isClient) {
|
||||
if (!this.signatures) return;
|
||||
|
||||
const signatureName = (isClient)
|
||||
? this.signatures.clientSignature
|
||||
: this.signatures.deliverySignature;
|
||||
const hash = md5(signatureName.toString()).substring(0, 3);
|
||||
const file = `${config.storage.root}/${hash}/${signatureName}.png`;
|
||||
|
||||
if (!fs.existsSync(file)) return null;
|
||||
|
||||
return `data:image/png;base64, ${Buffer.from(fs.readFileSync(file), 'utf8').toString('base64')}`;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
reportName: cmr
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"format": "A4"
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
SELECT c.id cmrFk,
|
||||
c.ticketFk,
|
||||
c.truckPlate,
|
||||
c.observations,
|
||||
c.senderInstruccions,
|
||||
c.paymentInstruccions,
|
||||
c.specialAgreements,
|
||||
c.created,
|
||||
c.packagesList,
|
||||
c.merchandiseDetail,
|
||||
c.ead,
|
||||
s.name carrierName,
|
||||
s.street carrierStreet,
|
||||
s.postCode carrierPostCode,
|
||||
s.city carrierCity,
|
||||
cou.country carrierCountry,
|
||||
s2.name senderName,
|
||||
s2.street senderStreet,
|
||||
s2.postCode senderPostCode,
|
||||
s2.city senderCity,
|
||||
cou2.country senderCountry,
|
||||
a.street deliveryStreet,
|
||||
a.id deliveryAddressFk,
|
||||
a.postalCode deliveryPostalCode,
|
||||
a.city deliveryCity,
|
||||
a.nickname deliveryName,
|
||||
a.phone deliveryPhone,
|
||||
a.mobile deliveryMobile,
|
||||
cou3.country deliveryCountry,
|
||||
cl.phone clientPhone,
|
||||
a2.street loadStreet,
|
||||
a2.postalCode loadPostalCode,
|
||||
a2.city loadCity,
|
||||
cou4.country loadCountry
|
||||
FROM cmr c
|
||||
LEFT JOIN supplier s ON s.id = c.supplierFk
|
||||
LEFT JOIN country cou ON cou.id = s.countryFk
|
||||
LEFT JOIN company co ON co.id = c.companyFk
|
||||
LEFT JOIN supplierAccount sa ON sa.id = co.supplierAccountFk
|
||||
LEFT JOIN supplier s2 ON s2.id = sa.supplierFk
|
||||
LEFT JOIN country cou2 ON cou2.id = s2.countryFk
|
||||
LEFT JOIN `address` a ON a.id = c.addressToFk
|
||||
LEFT JOIN province p ON p.id = a.provinceFk
|
||||
LEFT JOIN country cou3 ON cou3.id = p.countryFk
|
||||
LEFT JOIN client cl ON cl.id = a.clientFk
|
||||
LEFT JOIN `address` a2 ON a2.id = c.addressFromFk
|
||||
LEFT JOIN province p2 ON p2.id = a2.provinceFk
|
||||
LEFT JOIN country cou4 ON cou4.id = p2.countryFk
|
||||
WHERE c.id = ?
|
|
@ -0,0 +1,11 @@
|
|||
SELECT s.ticketFk,
|
||||
ic.name,
|
||||
CAST(SUM(sv.weight) AS DECIMAL(10,2)) `weight`,
|
||||
CAST(SUM(sv.volume) AS DECIMAL(10,3)) volume
|
||||
FROM sale s
|
||||
JOIN saleVolume sv ON sv.saleFk = s.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
JOIN itemType it ON it.id = i.typeFk
|
||||
JOIN itemCategory ic ON ic.id = it.categoryFk
|
||||
WHERE sv.ticketFk = ?
|
||||
GROUP BY ic.id
|
|
@ -0,0 +1,7 @@
|
|||
SELECT dc.id clientSignature, dd.id deliverySignature
|
||||
FROM ticket t
|
||||
JOIN ticketDms dt ON dt.ticketFk = t.id
|
||||
LEFT JOIN dms dc ON dc.id = dt.dmsFk
|
||||
JOIN `route` r ON r.id = t.routeFk
|
||||
LEFT JOIN dms dd ON dd.id = r.deliverySignFk
|
||||
WHERE t.id = ?
|
Loading…
Reference in New Issue