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 function(ctx, Self, tickets, options) { const userId = ctx.req.accessToken.userId; const myOptions = {userId}; if (typeof options == 'object') Object.assign(myOptions, options); let tx; // IMPORTANT: Due to its high cost in production, wrapping this process in a transaction may cause timeouts. if (tickets.length == 0) return; const failedtickets = []; for (const ticket of tickets) { try { await Self.rawSql(`CALL util.debugAdd('invoicingTicket', ?)`, [ticket.id], myOptions); await Self.app.models.InvoiceOut.getSerial( ticket.clientFk, ticket.companyFk, ticket.addressFk, 'quick', myOptions); await Self.rawSql( `CALL vn.ticket_closeByTicket(?)`, [ticket.id], myOptions ); 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], myOptions); const mailOptions = { overrideAttachments: true, attachments: [], }; const isToBeMailed = ticket.recipient && ticket.salesPersonFk && ticket.isToBeMailed; 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 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 await storage.write(stream, { type: 'invoice', path: `${year}/${month}/${day}`, fileName: fileName, }); await Self.rawSql( 'UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id], myOptions ); 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 = { id: ticket.id, recipientId: ticket.clientFk, recipient: ticket.recipient, replyTo: ticket.salesPersonEmail, }; 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], myOptions); if (firstOrder == 1) { const args = { id: ticket.clientFk, companyId: ticket.companyFk, recipientId: ticket.clientFk, recipient: ticket.recipient, replyTo: ticket.salesPersonEmail, addressId: ticket.addressFk, }; const email = new Email('incoterms-authorization', args); await email.send(); const [sample] = await Self.rawSql(` SELECT id FROM sample WHERE code = 'incoterms-authorization' `, null, myOptions); await Self.rawSql(` INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?) `, [ticket.clientFk, sample.id, ticket.companyFk], myOptions); } } catch (error) { await Self.rawSql(` INSERT INTO util.debug (variable, value) VALUES ('invoicingTicketError', ?) `, [ticket.id + ' - ' + error]); if (error.responseCode == 450) { await invalidEmail(ticket); continue; } failedtickets.push({ id: ticket.id, stacktrace: error, }); } } if (failedtickets.length > 0) { let body = 'This following tickets have failed:

'; for (const ticket of failedtickets) { body += `Ticket: ${ticket.id}
${ticket.stacktrace}

`; } smtp.send({ to: config.app.reportEmail, subject: '[API] Nightly ticket closure report', html: body, }).catch(err => console.error(err)); } if (tx) await tx.commit(); async function invalidEmail(ticket) { await Self.rawSql( `UPDATE client SET email = NULL WHERE id = ?`, [ticket.clientFk], myOptions ); const body = `No se ha podido enviar el albarán ${ticket.id} al cliente ${ticket.clientFk} - ${ticket.clientName} porque la dirección de email "${ticket.recipient}" no es correcta o no está disponible.

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, }).catch(err => console.error(err)); } };