Client consumption queue
gitea/salix/pipeline/head There was a failure building this commit Details

This commit is contained in:
Joan Sanchez 2022-09-29 14:43:27 +02:00
parent 7a7ad6ac5f
commit 3601881026
25 changed files with 134 additions and 703 deletions

View File

@ -1,5 +1,6 @@
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES VALUES
('ClientConsumptionQueue', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'deliveryNotePdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Ticket', 'deliveryNotePdf', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'deliveryNoteEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Ticket', 'deliveryNoteEmail', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Client', 'campaignMetricsPdf', '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', 'clientDebtStatementEmail', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Client', 'incotermsAuthorizationHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'incotermsAuthorizationHtml', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Client', 'incotermsAuthorizationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'incotermsAuthorizationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Client', 'consumptionSendQueued', 'WRITE', 'ALLOW', 'ROLE', 'system'),
('InvoiceOut', 'invoiceEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('InvoiceOut', 'invoiceEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('InvoiceOut', 'exportationPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('InvoiceOut', 'exportationPdf', 'READ', 'ALLOW', 'ROLE', 'employee'),
('InvoiceOut', 'sendQueued', 'WRITE', 'ALLOW', 'ROLE', 'system'), ('InvoiceOut', 'sendQueued', 'WRITE', 'ALLOW', 'ROLE', 'system'),

View File

@ -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';

View File

@ -0,0 +1 @@
rename table `vn`.`invoiceOut_queue` to `vn`.`invoiceOutQueue`;

View File

@ -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'
};
};
};

View File

@ -26,6 +26,9 @@
"ClientCreditLimit": { "ClientCreditLimit": {
"dataSource": "vn" "dataSource": "vn"
}, },
"ClientConsumptionQueue": {
"dataSource": "vn"
},
"ClientLog": { "ClientLog": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

@ -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"
}
}
}

View File

@ -42,4 +42,5 @@ module.exports = Self => {
require('../methods/client/creditRequestEmail')(Self); require('../methods/client/creditRequestEmail')(Self);
require('../methods/client/incotermsAuthorizationHtml')(Self); require('../methods/client/incotermsAuthorizationHtml')(Self);
require('../methods/client/incotermsAuthorizationEmail')(Self); require('../methods/client/incotermsAuthorizationEmail')(Self);
require('../methods/client/consumptionSendQueued')(Self);
}; };

View File

@ -77,13 +77,15 @@ export default class Controller extends Section {
onSendClientConsumption() { onSendClientConsumption() {
const clientIds = this.checked.map(client => client.id); const clientIds = this.checked.map(client => client.id);
const params = Object.assign({ const params = {
clientIds: clientIds clients: clientIds,
}, this.campaign); 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.$.filters.hide())
.then(() => this.vnApp.showSuccess(this.$t('Notifications sent!'))); .then(() => this.vnApp.showSuccess(this.$t('Notifications queued')));
} }
exprBuilder(param, value) { exprBuilder(param, value) {

View File

@ -28,7 +28,7 @@ module.exports = Self => {
c.hasToInvoice, c.hasToInvoice,
co.hasDailyInvoice, co.hasDailyInvoice,
eu.email salesPersonEmail eu.email salesPersonEmail
FROM invoiceOut_queue ioq FROM invoiceOutQueue ioq
JOIN invoiceOut io ON io.id = ioq.invoiceFk JOIN invoiceOut io ON io.id = ioq.invoiceFk
JOIN client c ON c.id = io.clientFk JOIN client c ON c.id = io.clientFk
JOIN province p ON p.id = c.provinceFk JOIN province p ON p.id = c.provinceFk

View File

@ -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);
}
};

View File

@ -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);
}
};

View File

@ -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);
}
};

View File

@ -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);
}
};

View File

@ -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
});
}

View File

@ -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;

View File

@ -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);
}
};

View File

@ -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;

View File

@ -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);
}
};

View File

@ -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);
}
};

View File

@ -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;

View File

@ -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);
}
};

View File

@ -1,22 +1,6 @@
module.exports = [ module.exports = [
{
url: '/api/report',
cb: require('./report')
},
{
url: '/api/email',
cb: require('./email')
},
{ {
url: '/api/csv', url: '/api/csv',
cb: require('./csv') cb: require('./csv')
},
{
url: '/api/closure',
cb: require('./closure')
},
{
url: '/api/schedule',
cb: require('./schedule')
} }
]; ];

View File

@ -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);
}
};

View File

@ -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;

View File

@ -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);
}
};