Client consumption queue
gitea/salix/pipeline/head There was a failure building this commit
Details
gitea/salix/pipeline/head There was a failure building this commit
Details
This commit is contained in:
parent
7a7ad6ac5f
commit
3601881026
|
@ -1,5 +1,6 @@
|
|||
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||
VALUES
|
||||
('ClientConsumptionQueue', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Ticket', 'deliveryNotePdf', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Ticket', 'deliveryNoteEmail', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Client', 'campaignMetricsPdf', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
|
@ -17,6 +18,7 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp
|
|||
('Client', 'clientDebtStatementEmail', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Client', 'incotermsAuthorizationHtml', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Client', 'incotermsAuthorizationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||
('Client', 'consumptionSendQueued', 'WRITE', 'ALLOW', 'ROLE', 'system'),
|
||||
('InvoiceOut', 'invoiceEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
|
||||
('InvoiceOut', 'exportationPdf', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||
('InvoiceOut', 'sendQueued', 'WRITE', 'ALLOW', 'ROLE', 'system'),
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
create table `vn`.`clientConsumptionQueue`
|
||||
(
|
||||
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
params json not null,
|
||||
queued datetime default current_timestamp() not null,
|
||||
printed datetime null,
|
||||
status varchar(50) default '' null
|
||||
)
|
||||
comment 'Queue for client consumption PDF mailing';
|
|
@ -0,0 +1 @@
|
|||
rename table `vn`.`invoiceOut_queue` to `vn`.`invoiceOutQueue`;
|
|
@ -0,0 +1,80 @@
|
|||
const {Email} = require('vn-print');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('consumptionSendQueued', {
|
||||
description: 'Send all queued invoices',
|
||||
accessType: 'WRITE',
|
||||
accepts: [],
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: '/consumption-send-queued',
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.consumptionSendQueued = async() => {
|
||||
const queues = await Self.rawSql(`
|
||||
SELECT
|
||||
ccq.id,
|
||||
c.id AS clientFk,
|
||||
c.email AS clientEmail,
|
||||
eu.email salesPersonEmail,
|
||||
REPLACE(json_extract(params, '$.from'), '"', '') AS fromDate,
|
||||
REPLACE(json_extract(params, '$.to'), '"', '') AS toDate
|
||||
FROM clientConsumptionQueue ccq
|
||||
JOIN client c ON (
|
||||
JSON_SEARCH(
|
||||
JSON_ARRAY(
|
||||
json_extract(params, '$.clients')
|
||||
)
|
||||
, 'all', c.id) IS NOT NULL)
|
||||
JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
||||
JOIN ticket t ON t.clientFk = c.id
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
JOIN itemType it ON it.id = i.typeFk
|
||||
WHERE status = ''
|
||||
AND it.isPackaging = FALSE
|
||||
AND DATE(t.shipped) BETWEEN
|
||||
REPLACE(json_extract(params, '$.from'), '"', '') AND
|
||||
REPLACE(json_extract(params, '$.to'), '"', '')
|
||||
GROUP BY c.id`);
|
||||
|
||||
for (const queue of queues) {
|
||||
try {
|
||||
const args = {
|
||||
id: queue.clientFk,
|
||||
recipient: queue.clientEmail,
|
||||
replyTo: queue.salesPersonEmail,
|
||||
from: queue.fromDate,
|
||||
to: queue.toDate
|
||||
};
|
||||
|
||||
const email = new Email('campaign-metrics', args);
|
||||
await email.send();
|
||||
|
||||
await Self.rawSql(`
|
||||
UPDATE clientConsumptionQueue
|
||||
SET status = 'printed',
|
||||
printed = ?
|
||||
WHERE id = ?`,
|
||||
[new Date(), queue.id]);
|
||||
} catch (error) {
|
||||
await Self.rawSql(`
|
||||
UPDATE clientConsumptionQueue
|
||||
SET status = ?
|
||||
WHERE id = ?`,
|
||||
[error.message, queue.id]);
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
message: 'Success'
|
||||
};
|
||||
};
|
||||
};
|
|
@ -26,6 +26,9 @@
|
|||
"ClientCreditLimit": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ClientConsumptionQueue": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ClientLog": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "ClientConsumptionQueue",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "clientConsumptionQueue"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"params": {
|
||||
"type": "json"
|
||||
},
|
||||
"queued": {
|
||||
"type": "date"
|
||||
},
|
||||
"printed": {
|
||||
"type": "date"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"client": {
|
||||
"type": "belongsTo",
|
||||
"model": "Client",
|
||||
"foreignKey": "clientFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -42,4 +42,5 @@ module.exports = Self => {
|
|||
require('../methods/client/creditRequestEmail')(Self);
|
||||
require('../methods/client/incotermsAuthorizationHtml')(Self);
|
||||
require('../methods/client/incotermsAuthorizationEmail')(Self);
|
||||
require('../methods/client/consumptionSendQueued')(Self);
|
||||
};
|
||||
|
|
|
@ -77,13 +77,15 @@ export default class Controller extends Section {
|
|||
|
||||
onSendClientConsumption() {
|
||||
const clientIds = this.checked.map(client => client.id);
|
||||
const params = Object.assign({
|
||||
clientIds: clientIds
|
||||
}, this.campaign);
|
||||
const params = {
|
||||
clients: clientIds,
|
||||
from: this.campaign.from,
|
||||
to: this.campaign.to
|
||||
};
|
||||
|
||||
this.$http.post('schedule/consumption', params)
|
||||
this.$http.post('ClientConsumptionQueues', {params})
|
||||
.then(() => this.$.filters.hide())
|
||||
.then(() => this.vnApp.showSuccess(this.$t('Notifications sent!')));
|
||||
.then(() => this.vnApp.showSuccess(this.$t('Notifications queued')));
|
||||
}
|
||||
|
||||
exprBuilder(param, value) {
|
||||
|
|
|
@ -28,7 +28,7 @@ module.exports = Self => {
|
|||
c.hasToInvoice,
|
||||
co.hasDailyInvoice,
|
||||
eu.email salesPersonEmail
|
||||
FROM invoiceOut_queue ioq
|
||||
FROM invoiceOutQueue ioq
|
||||
JOIN invoiceOut io ON io.id = ioq.invoiceFk
|
||||
JOIN client c ON c.id = io.clientFk
|
||||
JOIN province p ON p.id = c.provinceFk
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
const db = require('vn-print/core/database');
|
||||
const closure = require('./closure');
|
||||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const reqArgs = request.body;
|
||||
|
||||
let toDate = new Date();
|
||||
toDate.setDate(toDate.getDate() - 1);
|
||||
|
||||
if (reqArgs.to) toDate = reqArgs.to;
|
||||
|
||||
const todayMinDate = new Date();
|
||||
minDate.setHours(0, 0, 0, 0);
|
||||
|
||||
const todayMaxDate = new Date();
|
||||
maxDate.setHours(23, 59, 59, 59);
|
||||
|
||||
// Prevent closure for current day
|
||||
if (toDate >= todayMinDate && toDate <= todayMaxDate)
|
||||
throw new Error('You cannot close tickets for today');
|
||||
|
||||
const tickets = await db.rawSql(`
|
||||
SELECT
|
||||
t.id,
|
||||
t.clientFk,
|
||||
t.companyFk,
|
||||
c.name clientName,
|
||||
c.email recipient,
|
||||
c.salesPersonFk,
|
||||
c.isToBeMailed,
|
||||
c.hasToInvoice,
|
||||
co.hasDailyInvoice,
|
||||
eu.email salesPersonEmail
|
||||
FROM ticket t
|
||||
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 country co ON co.id = p.countryFk
|
||||
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
||||
WHERE al.code = 'PACKED'
|
||||
AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY)
|
||||
AND util.dayEnd(?)
|
||||
AND t.refFk IS NULL
|
||||
GROUP BY t.id`, [toDate, toDate]);
|
||||
|
||||
await closure.start(tickets, response.locals);
|
||||
|
||||
await db.rawSql(`
|
||||
UPDATE ticket t
|
||||
JOIN ticketState ts ON t.id = ts.ticketFk
|
||||
JOIN alertLevel al ON al.id = ts.alertLevel
|
||||
JOIN agencyMode am ON am.id = t.agencyModeFk
|
||||
JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
|
||||
JOIN zone z ON z.id = t.zoneFk
|
||||
SET t.routeFk = NULL
|
||||
WHERE DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY)
|
||||
AND util.dayEnd(?)
|
||||
AND al.code NOT IN('DELIVERED','PACKED')
|
||||
AND t.routeFk
|
||||
AND z.name LIKE '%MADRID%'`, [toDate, toDate]);
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
|
@ -1,59 +0,0 @@
|
|||
const db = require('vn-print/core/database');
|
||||
const closure = require('./closure');
|
||||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const reqArgs = request.body;
|
||||
|
||||
if (!reqArgs.agencyModeId)
|
||||
throw new Error('The argument agencyModeId is required');
|
||||
|
||||
if (!reqArgs.warehouseId)
|
||||
throw new Error('The argument warehouseId is required');
|
||||
|
||||
if (!reqArgs.to)
|
||||
throw new Error('The argument to is required');
|
||||
|
||||
const agencyIds = reqArgs.agencyModeId.split(',');
|
||||
const tickets = await db.rawSql(`
|
||||
SELECT
|
||||
t.id,
|
||||
t.clientFk,
|
||||
t.companyFk,
|
||||
c.name clientName,
|
||||
c.email recipient,
|
||||
c.salesPersonFk,
|
||||
c.isToBeMailed,
|
||||
c.hasToInvoice,
|
||||
co.hasDailyInvoice,
|
||||
eu.email salesPersonEmail
|
||||
FROM expedition e
|
||||
JOIN ticket t ON t.id = e.ticketFk
|
||||
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 country co ON co.id = p.countryFk
|
||||
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
||||
WHERE al.code = 'PACKED'
|
||||
AND t.agencyModeFk IN(?)
|
||||
AND t.warehouseFk = ?
|
||||
AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY)
|
||||
AND util.dayEnd(?)
|
||||
AND t.refFk IS NULL
|
||||
GROUP BY e.ticketFk`, [
|
||||
agencyIds,
|
||||
reqArgs.warehouseId,
|
||||
reqArgs.to,
|
||||
reqArgs.to
|
||||
]);
|
||||
|
||||
await closure.start(tickets, response.locals);
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
|
@ -1,62 +0,0 @@
|
|||
const db = require('vn-print/core/database');
|
||||
const Email = require('vn-print/core/email');
|
||||
const closure = require('./closure');
|
||||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const reqArgs = request.body;
|
||||
|
||||
if (!reqArgs.routeId)
|
||||
throw new Error('The argument routeId is required');
|
||||
|
||||
const tickets = await db.rawSql(`
|
||||
SELECT
|
||||
t.id,
|
||||
t.clientFk,
|
||||
t.companyFk,
|
||||
c.name clientName,
|
||||
c.email recipient,
|
||||
c.salesPersonFk,
|
||||
c.isToBeMailed,
|
||||
c.hasToInvoice,
|
||||
co.hasDailyInvoice,
|
||||
eu.email salesPersonEmail
|
||||
FROM expedition e
|
||||
JOIN ticket t ON t.id = e.ticketFk
|
||||
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 country co ON co.id = p.countryFk
|
||||
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
||||
WHERE al.code = 'PACKED'
|
||||
AND t.routeFk = ?
|
||||
AND t.refFk IS NULL
|
||||
GROUP BY e.ticketFk`, [reqArgs.routeId]);
|
||||
|
||||
await closure.start(tickets, response.locals);
|
||||
|
||||
// Send route report to the agency
|
||||
const agencyMail = await db.findValue(`
|
||||
SELECT am.reportMail
|
||||
FROM route r
|
||||
JOIN agencyMode am ON am.id = r.agencyModeFk
|
||||
WHERE r.id = ?`, [reqArgs.routeId]);
|
||||
|
||||
if (agencyMail) {
|
||||
const args = Object.assign({
|
||||
routeId: Number.parseInt(reqArgs.routeId),
|
||||
recipient: agencyMail
|
||||
}, response.locals);
|
||||
|
||||
const email = new Email('driver-route', args);
|
||||
await email.send();
|
||||
}
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
|
@ -1,44 +0,0 @@
|
|||
const db = require('vn-print/core/database');
|
||||
const closure = require('./closure');
|
||||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const reqArgs = request.body;
|
||||
|
||||
if (!reqArgs.ticketId)
|
||||
throw new Error('The argument ticketId is required');
|
||||
|
||||
const tickets = await db.rawSql(`
|
||||
SELECT
|
||||
t.id,
|
||||
t.clientFk,
|
||||
t.companyFk,
|
||||
c.name clientName,
|
||||
c.email recipient,
|
||||
c.salesPersonFk,
|
||||
c.isToBeMailed,
|
||||
c.hasToInvoice,
|
||||
co.hasDailyInvoice,
|
||||
eu.email salesPersonEmail
|
||||
FROM expedition e
|
||||
JOIN ticket t ON t.id = e.ticketFk
|
||||
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 country co ON co.id = p.countryFk
|
||||
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
||||
WHERE al.code = 'PACKED'
|
||||
AND t.id = ?
|
||||
AND t.refFk IS NULL
|
||||
GROUP BY e.ticketFk`, [reqArgs.ticketId]);
|
||||
|
||||
await closure.start(tickets, response.locals);
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
|
@ -1,181 +0,0 @@
|
|||
const db = require('vn-print/core/database');
|
||||
const Report = require('vn-print/core/report');
|
||||
const Email = require('vn-print/core/email');
|
||||
const smtp = require('vn-print/core/smtp');
|
||||
const config = require('vn-print/core/config');
|
||||
const storage = require('vn-print/core/storage');
|
||||
|
||||
module.exports = {
|
||||
async start(tickets, reqArgs) {
|
||||
if (tickets.length == 0) return;
|
||||
|
||||
const failedtickets = [];
|
||||
for (const ticket of tickets) {
|
||||
try {
|
||||
await db.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id]);
|
||||
|
||||
const invoiceOut = await db.findOne(`
|
||||
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 isToBeMailed = ticket.recipient && ticket.salesPersonFk && ticket.isToBeMailed;
|
||||
|
||||
if (invoiceOut) {
|
||||
const args = Object.assign({
|
||||
refFk: invoiceOut.ref,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
}, reqArgs);
|
||||
|
||||
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 fileName = `${year}${invoiceOut.ref}.pdf`;
|
||||
|
||||
// Store invoice
|
||||
storage.write(stream, {
|
||||
type: 'invoice',
|
||||
path: `${year}/${month}/${day}`,
|
||||
fileName: fileName
|
||||
});
|
||||
|
||||
await db.rawSql('UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id]);
|
||||
|
||||
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`;
|
||||
|
||||
mailOptions.attachments.push({
|
||||
filename: fileName,
|
||||
content: stream
|
||||
});
|
||||
}
|
||||
|
||||
mailOptions.attachments.push(invoiceAttachment);
|
||||
|
||||
const email = new Email('invoice', args);
|
||||
await email.send(mailOptions);
|
||||
}
|
||||
} else if (isToBeMailed) {
|
||||
const args = Object.assign({
|
||||
ticketId: ticket.id,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
}, reqArgs);
|
||||
|
||||
const email = new Email('delivery-note-link', args);
|
||||
await email.send();
|
||||
}
|
||||
|
||||
// Incoterms authorization
|
||||
const {firstOrder} = await db.findOne(`
|
||||
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 = Object.assign({
|
||||
ticketId: ticket.id,
|
||||
recipientId: ticket.clientFk,
|
||||
recipient: ticket.recipient,
|
||||
replyTo: ticket.salesPersonEmail
|
||||
}, reqArgs);
|
||||
|
||||
const email = new Email('incoterms-authorization', args);
|
||||
await email.send();
|
||||
|
||||
const sample = await db.findOne(
|
||||
`SELECT id
|
||||
FROM sample
|
||||
WHERE code = 'incoterms-authorization'`);
|
||||
|
||||
await db.rawSql(`
|
||||
INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?)
|
||||
`, [ticket.clientFk, sample.id, ticket.companyFk]);
|
||||
}
|
||||
} catch (error) {
|
||||
// Domain not found
|
||||
if (error.responseCode == 450)
|
||||
return invalidEmail(ticket);
|
||||
|
||||
// Save tickets on a list of failed ids
|
||||
failedtickets.push({
|
||||
id: ticket.id,
|
||||
stacktrace: error
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Send email with failed tickets
|
||||
if (failedtickets.length > 0) {
|
||||
let body = 'This following tickets have failed:<br/><br/>';
|
||||
|
||||
for (const ticket of failedtickets) {
|
||||
body += `Ticket: <strong>${ticket.id}</strong>
|
||||
<br/> <strong>${ticket.stacktrace}</strong><br/><br/>`;
|
||||
}
|
||||
|
||||
smtp.send({
|
||||
to: config.app.reportEmail,
|
||||
subject: '[API] Nightly ticket closure report',
|
||||
html: body
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
async function invalidEmail(ticket) {
|
||||
await db.rawSql(`UPDATE client SET email = NULL WHERE id = ?`, [
|
||||
ticket.clientFk
|
||||
]);
|
||||
|
||||
const oldInstance = `{"email": "${ticket.recipient}"}`;
|
||||
const newInstance = `{"email": ""}`;
|
||||
await db.rawSql(`
|
||||
INSERT INTO clientLog (originFk, userFk, action, changedModel, oldInstance, newInstance)
|
||||
VALUES (?, NULL, 'UPDATE', 'Client', ?, ?)`, [
|
||||
ticket.clientFk,
|
||||
oldInstance,
|
||||
newInstance
|
||||
]);
|
||||
|
||||
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
|
||||
});
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
const express = require('express');
|
||||
const router = new express.Router();
|
||||
|
||||
router.post('/all', require('./closeAll'));
|
||||
router.post('/by-ticket', require('./closeByTicket'));
|
||||
router.post('/by-agency', require('./closeByAgency'));
|
||||
router.post('/by-route', require('./closeByRoute'));
|
||||
|
||||
module.exports = router;
|
|
@ -1,16 +0,0 @@
|
|||
const Email = require('vn-print/core/email');
|
||||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const templateName = request.params.name;
|
||||
const args = response.locals;
|
||||
const email = new Email(templateName, args);
|
||||
await email.send();
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Sent'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
|
@ -1,7 +0,0 @@
|
|||
const express = require('express');
|
||||
const router = new express.Router();
|
||||
|
||||
router.get('/:name', require('./email'));
|
||||
router.get('/:name/preview', require('./preview'));
|
||||
|
||||
module.exports = router;
|
|
@ -1,14 +0,0 @@
|
|||
const Email = require('vn-print/core/email');
|
||||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const templateName = request.params.name;
|
||||
const args = Object.assign({isPreview: true}, response.locals);
|
||||
const email = new Email(templateName, args);
|
||||
const template = await email.render();
|
||||
|
||||
response.send(template);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
|
@ -1,17 +0,0 @@
|
|||
const Report = require('vn-print/core/report');
|
||||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const reportName = request.params.name;
|
||||
const args = response.locals;
|
||||
const report = new Report(reportName, args);
|
||||
const stream = await report.toPdfStream();
|
||||
const fileName = await report.getFileName();
|
||||
|
||||
response.setHeader('Content-type', 'application/pdf');
|
||||
response.setHeader('Content-Disposition', `inline; filename="${fileName}"`);
|
||||
response.end(stream);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
|
@ -1,7 +0,0 @@
|
|||
const express = require('express');
|
||||
const router = new express.Router();
|
||||
|
||||
router.get('/:name', require('./document'));
|
||||
router.get('/:name/preview', require('./preview'));
|
||||
|
||||
module.exports = router;
|
|
@ -1,13 +0,0 @@
|
|||
const Report = require('vn-print/core/report');
|
||||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const reportName = request.params.name;
|
||||
const report = new Report(reportName, request.query);
|
||||
const template = await report.render();
|
||||
|
||||
response.send(template);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
|
@ -1,22 +1,6 @@
|
|||
module.exports = [
|
||||
{
|
||||
url: '/api/report',
|
||||
cb: require('./report')
|
||||
},
|
||||
{
|
||||
url: '/api/email',
|
||||
cb: require('./email')
|
||||
},
|
||||
{
|
||||
url: '/api/csv',
|
||||
cb: require('./csv')
|
||||
},
|
||||
{
|
||||
url: '/api/closure',
|
||||
cb: require('./closure')
|
||||
},
|
||||
{
|
||||
url: '/api/schedule',
|
||||
cb: require('./schedule')
|
||||
}
|
||||
];
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
const db = require('vn-print/core/database');
|
||||
const Email = require('vn-print/core/email');
|
||||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
const reqArgs = request.body;
|
||||
|
||||
if (!reqArgs.clientIds)
|
||||
throw new Error('The argument clientIds is required');
|
||||
if (!reqArgs.from)
|
||||
throw new Error('The argument from is required');
|
||||
if (!reqArgs.to)
|
||||
throw new Error('The argument to is required');
|
||||
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
|
||||
const clientIds = reqArgs.clientIds;
|
||||
|
||||
const clients = await db.rawSql(`
|
||||
SELECT
|
||||
c.id,
|
||||
c.email,
|
||||
eu.email salesPersonEmail
|
||||
FROM client c
|
||||
JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
||||
JOIN ticket t ON t.clientFk = c.id
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
JOIN itemType it ON it.id = i.typeFk
|
||||
WHERE c.id IN(?)
|
||||
AND it.isPackaging = FALSE
|
||||
AND DATE(t.shipped) BETWEEN ? AND ?
|
||||
GROUP BY c.id`, [clientIds, reqArgs.from, reqArgs.to]);
|
||||
|
||||
const clientData = new Map();
|
||||
for (const client of clients)
|
||||
clientData.set(client.id, client);
|
||||
|
||||
for (const clientId of reqArgs.clientIds) {
|
||||
const client = clientData.get(clientId);
|
||||
|
||||
if (client) {
|
||||
const args = Object.assign({
|
||||
recipientId: clientId,
|
||||
recipient: client.email,
|
||||
replyTo: client.salesPersonEmail
|
||||
}, response.locals);
|
||||
|
||||
const email = new Email('campaign-metrics', args);
|
||||
await email.send();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
|
@ -1,7 +0,0 @@
|
|||
const express = require('express');
|
||||
const router = new express.Router();
|
||||
|
||||
router.post('/consumption', require('./consumption'));
|
||||
router.post('/invoice', require('./invoice'));
|
||||
|
||||
module.exports = router;
|
|
@ -1,115 +0,0 @@
|
|||
const db = require('vn-print/core/database');
|
||||
const Email = require('vn-print/core/email');
|
||||
const Report = require('vn-print/core/report');
|
||||
const storage = require('vn-print/core/storage');
|
||||
|
||||
module.exports = async function(request, response, next) {
|
||||
try {
|
||||
response.status(200).json({
|
||||
message: 'Success'
|
||||
});
|
||||
|
||||
const invoices = await db.rawSql(`
|
||||
SELECT
|
||||
io.id,
|
||||
io.clientFk,
|
||||
io.issued,
|
||||
io.ref,
|
||||
c.email recipient,
|
||||
c.salesPersonFk,
|
||||
c.isToBeMailed,
|
||||
c.hasToInvoice,
|
||||
co.hasDailyInvoice,
|
||||
eu.email salesPersonEmail
|
||||
FROM invoiceOut_queue ioq
|
||||
JOIN invoiceOut io ON io.id = ioq.invoiceFk
|
||||
JOIN client c ON c.id = io.clientFk
|
||||
JOIN province p ON p.id = c.provinceFk
|
||||
JOIN country co ON co.id = p.countryFk
|
||||
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
|
||||
WHERE status = ''`);
|
||||
|
||||
let connection;
|
||||
let invoiceId;
|
||||
for (const invoiceOut of invoices) {
|
||||
try {
|
||||
invoiceId = invoiceOut.id;
|
||||
connection = await db.getConnection();
|
||||
connection.query('START TRANSACTION');
|
||||
|
||||
const args = Object.assign({
|
||||
refFk: invoiceOut.ref,
|
||||
recipientId: invoiceOut.clientFk,
|
||||
recipient: invoiceOut.recipient,
|
||||
replyTo: invoiceOut.salesPersonEmail
|
||||
}, response.locals);
|
||||
|
||||
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 fileName = `${year}${invoiceOut.ref}.pdf`;
|
||||
|
||||
// Store invoice
|
||||
storage.write(stream, {
|
||||
type: 'invoice',
|
||||
path: `${year}/${month}/${day}`,
|
||||
fileName: fileName
|
||||
});
|
||||
|
||||
connection.query('UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id]);
|
||||
|
||||
const isToBeMailed = invoiceOut.recipient && invoiceOut.salesPersonFk && invoiceOut.isToBeMailed;
|
||||
|
||||
if (isToBeMailed) {
|
||||
const mailOptions = {
|
||||
overrideAttachments: true,
|
||||
attachments: []
|
||||
};
|
||||
|
||||
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`;
|
||||
|
||||
mailOptions.attachments.push({
|
||||
filename: fileName,
|
||||
content: stream
|
||||
});
|
||||
}
|
||||
|
||||
mailOptions.attachments.push(invoiceAttachment);
|
||||
|
||||
const email = new Email('invoice', args);
|
||||
await email.send(mailOptions);
|
||||
}
|
||||
// Update queue status
|
||||
const date = new Date();
|
||||
sql = `UPDATE invoiceOut_queue
|
||||
SET status = "printed",
|
||||
printed = ?
|
||||
WHERE invoiceFk = ?`;
|
||||
connection.query(sql, [date, invoiceOut.id]);
|
||||
connection.query('COMMIT');
|
||||
} catch (error) {
|
||||
connection.query('ROLLBACK');
|
||||
connection.release();
|
||||
sql = `UPDATE invoiceOut_queue
|
||||
SET status = ?
|
||||
WHERE invoiceFk = ?`;
|
||||
await db.rawSql(sql, [error.message, invoiceId]);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue