diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 43ff4b86a..7a973460d 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -115,7 +115,7 @@ "This client is not invoiceable": "This client is not invoiceable", "INACTIVE_PROVIDER": "Inactive provider", "reference duplicated": "reference duplicated", - "The PDF document does not exists": "The PDF document does not exists. Try regenerating it from 'Regenerate invoice PDF' option", + "The PDF document does not exist": "The PDF document does not exists. Try regenerating it from 'Regenerate invoice PDF' option", "This item is not available": "This item is not available", "Deny buy request": "Purchase request for ticket id [{{ticketId}}]({{{url}}}) has been rejected. Reason: {{observation}}", "The type of business must be filled in basic data": "The type of business must be filled in basic data", diff --git a/loopback/locale/es.json b/loopback/locale/es.json index b66a13569..2afe5bab5 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -211,7 +211,7 @@ "You don't have enough privileges to set this credit amount": "No tienes suficientes privilegios para establecer esta cantidad de crédito", "You can't change the credit set to zero from a financialBoss": "No puedes cambiar el cŕedito establecido a cero por un jefe de finanzas", "Amounts do not match": "Las cantidades no coinciden", - "The PDF document does not exists": "El documento PDF no existe. Prueba a regenerarlo desde la opción 'Regenerar PDF factura'", + "The PDF document does not exist": "El documento PDF no existe. Prueba a regenerarlo desde la opción 'Regenerar PDF factura'", "The type of business must be filled in basic data": "El tipo de negocio debe estar rellenado en datos básicos", "You can't create a claim from a ticket delivered more than seven days ago": "No puedes crear una reclamación de un ticket entregado hace más de siete días", "The worker has hours recorded that day": "El trabajador tiene horas fichadas ese día", @@ -293,5 +293,7 @@ "Pass expired": "La contraseña ha caducado, cambiela desde Salix", "Invalid NIF for VIES": "Invalid NIF for VIES", "Ticket does not exist": "Este ticket no existe", - "Ticket is already signed": "Este ticket ya ha sido firmado" -} + "Ticket is already signed": "Este ticket ya ha sido firmado", + "Fecha fuera de rango": "Fecha fuera de rango", + "Error while generating PDF": "Error while generating PDF" +} \ No newline at end of file diff --git a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js index dfdb3c1a7..8cc584c94 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js +++ b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js @@ -1,5 +1,4 @@ const UserError = require('vn-loopback/util/user-error'); -const print = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('createPdf', { @@ -26,9 +25,6 @@ module.exports = Self => { Self.createPdf = async function(ctx, id, options) { const models = Self.app.models; - if (process.env.NODE_ENV == 'test') - throw new UserError(`Action not allowed on the test environment`); - let tx; const myOptions = {}; @@ -41,40 +37,20 @@ module.exports = Self => { } try { - const invoiceOut = await Self.findById(id, null, myOptions); - const canCreatePdf = await models.ACL.checkAccessAcl(ctx, 'InvoiceOut', 'canCreatePdf', 'WRITE'); + const invoiceOut = await Self.findById(id, {fields: ['hasPdf']}, myOptions); - if (invoiceOut.hasPdf && !canCreatePdf) - throw new UserError(`You don't have enough privileges`); + if (invoiceOut.hasPdf) { + const canCreatePdf = await models.ACL.checkAccessAcl(ctx, 'InvoiceOut', 'canCreatePdf', 'WRITE'); + if (!canCreatePdf) + throw new UserError(`You don't have enough privileges`); + } - await invoiceOut.updateAttributes({ - hasPdf: true - }, myOptions); - - const invoiceReport = new print.Report('invoice', { - reference: invoiceOut.ref, - recipientId: invoiceOut.clientFk - }); - const buffer = 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 print.storage.write(buffer, { - type: 'invoice', - path: `${year}/${month}/${day}`, - fileName: fileName - }); + await Self.makePdf(id, myOptions); if (tx) await tx.commit(); - } catch (e) { + } catch (err) { if (tx) await tx.rollback(); - throw e; + throw err; } }; }; diff --git a/modules/invoiceOut/back/methods/invoiceOut/download.js b/modules/invoiceOut/back/methods/invoiceOut/download.js index 5c787428b..49bba046b 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/download.js +++ b/modules/invoiceOut/back/methods/invoiceOut/download.js @@ -43,7 +43,9 @@ module.exports = Self => { Object.assign(myOptions, options); try { - const invoiceOut = await models.InvoiceOut.findById(id, null, myOptions); + const invoiceOut = await models.InvoiceOut.findById(id, { + fields: ['ref', 'issued'] + }, myOptions); const issued = invoiceOut.issued; const year = issued.getFullYear().toString(); @@ -73,7 +75,7 @@ module.exports = Self => { return [stream, file.contentType, `filename="${file.name}"`]; } catch (error) { if (error.code === 'ENOENT') - throw new UserError('The PDF document does not exists'); + throw new UserError('The PDF document does not exist'); throw error; } diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js index 421cbaea1..ff814fea9 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js @@ -109,17 +109,22 @@ module.exports = Self => { ], myOptions); const [newInvoice] = await Self.rawSql(`SELECT @invoiceId id`, null, myOptions); - if (newInvoice.id) { - await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions); + if (!newInvoice) + throw new UserError('No tickets to invoice', 'notInvoiced'); - invoiceOut = await models.InvoiceOut.findById(newInvoice.id, { - include: { - relation: 'client' + await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions); + + invoiceOut = await models.InvoiceOut.findById(newInvoice.id, { + fields: ['id', 'ref', 'clientFk'], + include: { + relation: 'client', + scope: { + fields: ['email', 'isToBeMailed'] } - }, myOptions); + } + }, myOptions); - invoiceId = newInvoice.id; - } + invoiceId = newInvoice.id; if (tx) await tx.commit(); } catch (e) { @@ -127,26 +132,32 @@ module.exports = Self => { throw e; } - if (invoiceId) { - if (!invoiceOut.client().isToBeMailed) { - const query = ` - CALL vn.report_print( - 'invoice', - ?, - account.myUser_getId(), - JSON_OBJECT('refFk', ?), - 'normal' - );`; - await models.InvoiceOut.rawSql(query, [args.printerFk, invoiceOut.ref]); - } else { - ctx.args = { - reference: invoiceOut.ref, - recipientId: invoiceOut.clientFk, - recipient: invoiceOut.client().email - }; - await models.InvoiceOut.invoiceEmail(ctx, invoiceOut.ref); - } + try { + await Self.makePdf(invoiceId); + } catch (err) { + console.error(err); + throw new UserError('Error while generating PDF', 'pdfError'); } + + if (invoiceOut.client().isToBeMailed) { + ctx.args = { + reference: invoiceOut.ref, + recipientId: args.clientId, + recipient: invoiceOut.client().email + }; + await models.InvoiceOut.invoiceEmail(ctx, invoiceOut.ref); + } else { + const query = ` + CALL vn.report_print( + 'invoice', + ?, + account.myUser_getId(), + JSON_OBJECT('refFk', ?), + 'normal' + );`; + await models.InvoiceOut.rawSql(query, [args.printerFk, invoiceOut.ref]); + } + return invoiceId; }; diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js index 83cb84881..45894e9c5 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js @@ -1,3 +1,4 @@ +const UserError = require('vn-loopback/util/user-error'); const {Email} = require('vn-print'); module.exports = Self => { @@ -74,6 +75,10 @@ module.exports = Self => { ] }; - return email.send(mailOptions); + try { + return email.send(mailOptions); + } catch(err) { + throw new UserError('Error when sending mail to client', 'mailNotSent'); + } }; }; diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index 5fcef7744..bfef57f58 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -1,3 +1,5 @@ +const print = require('vn-print'); + module.exports = Self => { require('../methods/invoiceOut/filter')(Self); require('../methods/invoiceOut/summary')(Self); @@ -19,4 +21,35 @@ module.exports = Self => { require('../methods/invoiceOut/getInvoiceDate')(Self); require('../methods/invoiceOut/negativeBases')(Self); require('../methods/invoiceOut/negativeBasesCsv')(Self); + + Self.makePdf = async function(id, options) { + const fields = ['id', 'hasPdf', 'ref', 'issued']; + const invoiceOut = await Self.findById(id, {fields}, options); + + const invoiceReport = new print.Report('invoice', { + reference: invoiceOut.ref + }); + const buffer = 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 invoiceOut.updateAttributes({ + hasPdf: true + }, options); + + if (process.env.NODE_ENV !== 'test') { + await print.storage.write(buffer, { + type: 'invoice', + path: `${year}/${month}/${day}`, + fileName: fileName + }); + } + } }; diff --git a/modules/invoiceOut/front/global-invoicing/index.html b/modules/invoiceOut/front/global-invoicing/index.html index 3f0a10650..52bf8b619 100644 --- a/modules/invoiceOut/front/global-invoicing/index.html +++ b/modules/invoiceOut/front/global-invoicing/index.html @@ -55,7 +55,11 @@ {{::error.address.nickname}} - {{::error.message}} + + {{::error.message}} + diff --git a/modules/invoiceOut/front/global-invoicing/index.js b/modules/invoiceOut/front/global-invoicing/index.js index 70838a5a2..2e4ac1888 100644 --- a/modules/invoiceOut/front/global-invoicing/index.js +++ b/modules/invoiceOut/front/global-invoicing/index.js @@ -108,9 +108,18 @@ class Controller extends Section { this.$http.post(`InvoiceOuts/invoiceClient`, params) .then(() => this.invoiceNext()) .catch(res => { - const message = res.data?.error?.message || res.message; if (res.status >= 400 && res.status < 500) { - this.errors.unshift({address, message}); + const error = res.data?.error; + let isWarning; + switch(error?.code) { + case 'pdfError': + case 'mailNotSent': + isWarning = true; + break; + } + + const message = error?.message || res.message; + this.errors.unshift({address, message, isWarning}); this.invoiceNext(); } else { this.invoicing = false; diff --git a/print/core/smtp.js b/print/core/smtp.js index 61b115b5a..04bede5b5 100644 --- a/print/core/smtp.js +++ b/print/core/smtp.js @@ -46,14 +46,21 @@ module.exports = { const fileNames = attachments.join(',\n'); await db.rawSql(` - INSERT INTO vn.mail (receiver, replyTo, sent, subject, body, attachment, status) - VALUES (?, ?, 1, ?, ?, ?, ?)`, [ + INSERT INTO vn.mail + SET receiver = ?, + replyTo = ?, + sent = ?, + subject = ?, + body = ?, + attachment = ?, + status = ?`, [ options.to, options.replyTo, + error ? 2 : 1, options.subject, options.text || options.html, fileNames, - error && error.message || 'Sent' + error && error.message || 'OK' ]); }