diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index e33494836..9d7f61116 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -104,17 +104,17 @@ INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`) (3, 'GBP', 'Libra', 1), (4, 'JPY', 'Yen Japones', 1); -INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`, `continentFk`) +INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`, `continentFk`, `hasDailyInvoice`, `CEE`) VALUES - (1, 'España', 1, 'ES', 1, 24, 4), - (2, 'Italia', 1, 'IT', 1, 27, 4), - (3, 'Alemania', 1, 'DE', 1, 22, 4), - (4, 'Rumania', 1, 'RO', 1, 24, 4), - (5, 'Holanda', 1, 'NL', 1, 18, 4), - (8, 'Portugal', 1, 'PT', 1, 27, 4), - (13,'Ecuador', 0, 'EC', 1, 24, 2), - (19,'Francia', 1, 'FR', 1, 27, 4), - (30,'Canarias', 1, 'IC', 1, 24, 4); + (1, 'España', 1, 'ES', 1, 24, 4, 0, 1), + (2, 'Italia', 1, 'IT', 1, 27, 4, 0, 1), + (3, 'Alemania', 1, 'DE', 1, 22, 4, 0, 1), + (4, 'Rumania', 1, 'RO', 1, 24, 4, 0, 1), + (5, 'Holanda', 1, 'NL', 1, 18, 4, 0, 1), + (8, 'Portugal', 1, 'PT', 1, 27, 4, 0, 1), + (13,'Ecuador', 0, 'EC', 1, 24, 2, 1, 2), + (19,'Francia', 1, 'FR', 1, 27, 4, 0, 1), + (30,'Canarias', 1, 'IC', 1, 24, 4, 1, 2); INSERT INTO `hedera`.`language` (`code`, `name`, `orgName`, `isActive`) VALUES @@ -243,7 +243,7 @@ INSERT INTO `vn`.`province`(`id`, `name`, `countryFk`, `autonomyFk`, `warehouseF VALUES (1, 'Province one', 1, 1, NULL), (2, 'Province two', 1, 1, NULL), - (3, 'Province three', 1, 2, NULL), + (3, 'Province three', 30, 2, NULL), (4, 'Province four', 2, 3, NULL), (5, 'Province five', 13, 4, NULL); @@ -486,7 +486,9 @@ INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaF ('A', 'Global nacional', 1, 'NATIONAL', 0), ('T', 'Española rapida', 1, 'NATIONAL', 0), ('V', 'Intracomunitaria global', 0, 'CEE', 1), - ('M', 'Múltiple nacional', 1, 'NATIONAL', 0); + ('M', 'Múltiple nacional', 1, 'NATIONAL', 0), + ('E', 'Exportación rápida', 0, 'WORLD', 0); +; INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`) VALUES diff --git a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js index f4f4567ea..50582d3c2 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js +++ b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js @@ -1,7 +1,7 @@ const UserError = require('vn-loopback/util/user-error'); const fs = require('fs-extra'); -const got = require('got'); const path = require('path'); +const axios = require('axios'); module.exports = Self => { Self.remoteMethodCtx('createPdf', { @@ -57,39 +57,35 @@ module.exports = Self => { hasPdf: true }, myOptions); - const response = got.stream(`${origin}/api/report/invoice`, { - searchParams: { + return axios.get(`${origin}/api/report/invoice`, { + responseType: 'stream', + params: { authorization: auth.id, invoiceId: id } - }); + }).then(async response => { + 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 container = await models.InvoiceContainer.container(year); + const rootPath = container.client.root; + const fileName = `${year}${invoiceOut.ref}.pdf`; + const src = path.join(rootPath, year, month, day); + fileSrc = path.join(src, fileName); - const container = await models.InvoiceContainer.container(year); - const rootPath = container.client.root; - const fileName = `${year}${invoiceOut.ref}.pdf`; - const src = path.join(rootPath, year, month, day); - fileSrc = path.join(src, fileName); + await fs.mkdir(src, {recursive: true}); - await fs.mkdir(src, {recursive: true}); + if (tx) await tx.commit(); - if (tx) await tx.commit(); - - const writeStream = fs.createWriteStream(fileSrc); - writeStream.on('open', () => response.pipe(writeStream)); - writeStream.on('finish', () => writeStream.end()); - - return new Promise(resolve => { - writeStream.on('close', () => resolve(invoiceOut)); + response.data.pipe(fs.createWriteStream(fileSrc)); + }).catch(async() => { + if (fs.existsSync(fileSrc)) + await fs.unlink(fileSrc); }); } catch (e) { if (tx) await tx.rollback(); - if (fs.existsSync(fileSrc)) - await fs.unlink(fileSrc); throw e; } }; diff --git a/modules/invoiceOut/front/descriptor-menu/index.js b/modules/invoiceOut/front/descriptor-menu/index.js index b6e7e0261..7e80a4a7c 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.js +++ b/modules/invoiceOut/front/descriptor-menu/index.js @@ -19,6 +19,10 @@ class Controller extends Section { this.id = value.id; } + get hasInvoicing() { + return this.aclService.hasAny(['invoicing']); + } + loadData() { const filter = { include: [ diff --git a/package.json b/package.json index dc132131a..e5b817e20 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "node": ">=14" }, "dependencies": { + "axios": "^0.25.0", "bmp-js": "^0.1.0", "compression": "^1.7.3", "fs-extra": "^5.0.0", @@ -42,6 +43,7 @@ "strong-error-handler": "^2.3.2", "uuid": "^3.3.3", "vn-loopback": "file:./loopback", + "vn-print": "file:./print", "xml2js": "^0.4.23" }, "devDependencies": { diff --git a/print/boot.js b/print/boot.js index 8cd0eaad7..d5c06264c 100644 --- a/print/boot.js +++ b/print/boot.js @@ -1,11 +1,9 @@ const express = require('express'); const path = require('path'); const fs = require('fs'); -const puppeteer = require('puppeteer'); const templatesPath = path.resolve(__dirname, './templates'); const componentsPath = path.resolve(__dirname, './core/components'); -const config = require('./core/config'); module.exports = async app => { global.appPath = __dirname; @@ -53,21 +51,4 @@ module.exports = async app => { app.use(`/api/${templateName}/assets`, express.static(assetsDir)); }); }); - - // Instantiate Puppeteer browser - async function launchBrowser() { - config.browser = await puppeteer.launch({ - headless: true, - args: [ - '--no-sandbox', - '--disable-setuid-sandbox', - '--single-process', - '--no-zygote' - ] - }); - - config.browser.on('disconnected', launchBrowser); - } - - launchBrowser(); }; diff --git a/print/common/css/layout.css b/print/common/css/layout.css index 4f521bea4..c1af4807d 100644 --- a/print/common/css/layout.css +++ b/print/common/css/layout.css @@ -6,6 +6,8 @@ .grid { font-family: Arial, Helvetica, sans-serif; font-size: 16px !important; + max-width: 1200px; + margin: 0 auto; width: 100% } diff --git a/print/config/print.json b/print/config/print.json index ceb7cbb28..d288c585d 100755 --- a/print/config/print.json +++ b/print/config/print.json @@ -48,6 +48,12 @@ "pool": true }, "storage": { - "root": "./storage/dms" + "root": "./storage/dms", + "invoice": { + "root": "./storage/pdfs/invoice" + }, + "signature": { + "root": "./storage/signatures" + } } } \ No newline at end of file diff --git a/print/core/component.js b/print/core/component.js index 12474566e..37656c240 100644 --- a/print/core/component.js +++ b/print/core/component.js @@ -27,29 +27,50 @@ class Component { get locale() { if (!this._locale) - this.getLocale(); + this._locale = this.getLocales(); return this._locale; } - getLocale() { - const mergedLocale = {messages: {}}; + getLocales() { + const mergedLocales = {messages: {}}; const localePath = path.resolve(__dirname, `${this.path}/locale`); if (!fs.existsSync(localePath)) - return mergedLocale; + return mergedLocales; const localeDir = fs.readdirSync(localePath); - localeDir.forEach(locale => { + for (const locale of localeDir) { const fullPath = path.join(localePath, '/', locale); const yamlLocale = fs.readFileSync(fullPath, 'utf8'); const jsonLocale = yaml.safeLoad(yamlLocale); const localeName = locale.replace('.yml', ''); - mergedLocale.messages[localeName] = jsonLocale; - }); + mergedLocales.messages[localeName] = jsonLocale; + } - this._locale = mergedLocale; + return mergedLocales; + } + + async getUserLocale() { + let locale = this.args.auth.locale; + + // Fetches user locale from mixing method getLocale() + if (this.args.recipientId) { + const component = await this.component(); + locale = await component.getLocale(this.args.recipientId); + } + + const messages = this.locale.messages; + const userTranslations = messages[locale]; + + if (!userTranslations) { + const fallbackLocale = config.i18n.fallbackLocale; + + return messages[fallbackLocale]; + } + + return userTranslations; } get stylesheet() { @@ -75,7 +96,7 @@ class Component { build() { const fullPath = path.resolve(__dirname, this.path); if (!fs.existsSync(fullPath)) - throw new Error(`Sample "${this.name}" not found`); + throw new Error(`Template "${this.name}" not found`); const component = require(`${this.path}/${this.name}`); component.i18n = this.locale; diff --git a/print/core/email.js b/print/core/email.js index 620c1e083..bc8345cab 100644 --- a/print/core/email.js +++ b/print/core/email.js @@ -19,22 +19,7 @@ class Email extends Component { } async getSubject() { - const component = await this.component(); - let locale = this.args.auth.locale; - - if (this.args.recipientId) - locale = await component.getLocale(this.args.recipientId); - - const messages = this.locale.messages; - const userTranslations = messages[locale]; - - if (!userTranslations) { - const fallbackLocale = config.i18n.fallbackLocale; - - return messages[fallbackLocale].subject; - } - - return userTranslations.subject; + return (await this.getUserLocale())['subject']; } /** @@ -63,6 +48,7 @@ class Email extends Component { const reportName = fileName.replace('.pdf', ''); const report = new Report(reportName, this.args); fileCopy.content = await report.toPdfStream(); + fileCopy.filename = await report.getFileName(); } attachments.push(fileCopy); diff --git a/print/core/report.js b/print/core/report.js index b20b8e5df..093f5e99e 100644 --- a/print/core/report.js +++ b/print/core/report.js @@ -2,6 +2,7 @@ const fs = require('fs'); const path = require('path'); const config = require('./config'); const Component = require('./component'); +const puppeteer = require('puppeteer'); if (!process.env.OPENSSL_CONF) process.env.OPENSSL_CONF = '/etc/ssl/'; @@ -17,6 +18,10 @@ class Report extends Component { return `../templates/reports/${this.name}`; } + async getName() { + return (await this.getUserLocale())['reportName']; + } + async toPdfStream() { const template = await this.render(); const defaultOptions = Object.assign({}, config.pdf); @@ -27,7 +32,17 @@ class Report extends Component { if (fs.existsSync(fullPath)) options = require(optionsPath); - const page = (await config.browser.pages())[0]; + const browser = await puppeteer.launch({ + headless: true, + args: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--single-process', + '--no-zygote' + ] + }); + + const page = (await browser.pages())[0]; await page.emulateMedia('screen'); await page.setContent(template); @@ -47,8 +62,43 @@ class Report extends Component { const buffer = await page.pdf(options); + await browser.close(); + return buffer; } + + /** + * Returns all the params that ends with id + * + * @return {array} List of identifiers + */ + getIdentifiers() { + const identifiers = []; + const args = this.args; + const keys = Object.keys(args); + + for (let arg of keys) { + if (arg.endsWith('Id')) + identifiers.push(arg); + } + + return identifiers; + } + + async getFileName() { + const args = this.args; + const identifiers = this.getIdentifiers(args); + const name = await this.getName(); + const params = []; + params.push(name); + + for (let id of identifiers) + params.push(args[id]); + + const fileName = params.join('_'); + + return `${fileName}.pdf`; + } } module.exports = Report; diff --git a/print/core/router.js b/print/core/router.js index c0f20dd9a..cd64ba07e 100644 --- a/print/core/router.js +++ b/print/core/router.js @@ -1,43 +1,30 @@ -const path = require('path'); -const fs = require('fs'); const db = require('./database'); module.exports = app => { - const methodsPath = path.resolve(__dirname, '../methods'); - const methodsDir = fs.readdirSync(methodsPath); - const methods = []; + const routes = require('../methods/routes'); - // Get all methods - for (let method of methodsDir) { - if (method.includes('.js')) - methods.push(method.replace('.js', '')); - } - - // Auth middleware - const paths = []; - for (let method of methods) - paths.push(`/api/${method}/*`); - - app.use(paths, async function(req, res, next) { - const token = getToken(req); - const query = `SELECT at.id, at.userId, eu.email, u.lang, at.ttl, at.created - FROM salix.AccessToken at - JOIN account.user u ON u.id = at.userid - JOIN account.emailUser eu ON eu.userFk = u.id - WHERE at.id = ?`; + const paths = routes.map(route => route.url); + app.use(paths, async function(request, response, next) { try { + const token = getToken(request); + const query = `SELECT at.id, at.userId, eu.email, u.lang, at.ttl, at.created + FROM salix.AccessToken at + JOIN account.user u ON u.id = at.userid + JOIN account.emailUser eu ON eu.userFk = u.id + WHERE at.id = ?`; + const auth = await db.findOne(query, [token]); if (!auth || isTokenExpired(auth.created, auth.ttl)) throw new Error('Invalid authorization token'); - const args = Object.assign({}, req.query); - const props = Object.assign(args, req.body); + const args = Object.assign({}, request.query); + const props = Object.assign(args, request.body); props.authorization = auth.id; - req.args = props; - req.args.auth = { + response.locals = props; + response.locals.auth = { userId: auth.userId, token: auth.id, email: auth.email, @@ -50,6 +37,10 @@ module.exports = app => { } }); + // Register routes + for (let route of routes) + app.use(route.url, route.cb); + function getToken(request) { const headers = request.headers; const queryParams = request.query; @@ -68,8 +59,4 @@ module.exports = app => { return false; } - - // Mount methods - for (let method of methods) - require(`../methods/${method}`)(app); }; diff --git a/print/core/smtp.js b/print/core/smtp.js index 36a76dbaf..50a413673 100644 --- a/print/core/smtp.js +++ b/print/core/smtp.js @@ -25,14 +25,17 @@ module.exports = { throw err; }).finally(async() => { const attachments = []; - for (let attachment of options.attachments) { - const fileName = attachment.filename; - const filePath = attachment.path; - if (fileName.includes('.png')) return; + if (options.attachments) { + for (let attachment of options.attachments) { + const fileName = attachment.filename; + const filePath = attachment.path; + if (fileName.includes('.png')) return; - if (fileName || filePath) - attachments.push(filePath ? filePath : fileName); + if (fileName || filePath) + attachments.push(filePath ? filePath : fileName); + } } + const fileNames = attachments.join(',\n'); await db.rawSql(` INSERT INTO vn.mail (receiver, replyTo, sent, subject, body, attachment, status) diff --git a/print/core/storage.js b/print/core/storage.js new file mode 100644 index 000000000..063a2fbec --- /dev/null +++ b/print/core/storage.js @@ -0,0 +1,28 @@ +const config = require('./config.js'); +const path = require('path'); +const fs = require('fs-extra'); + +module.exports = { + async write(stream, options) { + const storage = config.storage[options.type]; + + if (!storage) return; + + const src = path.join(storage.root, options.path); + const fileSrc = path.join(src, options.fileName); + + await fs.mkdir(src, {recursive: true}); + + const writeStream = fs.createWriteStream(fileSrc); + writeStream.on('open', () => writeStream.write(stream)); + writeStream.on('finish', () => writeStream.end()); + + return new Promise(resolve => { + writeStream.on('close', () => resolve()); + }); + }, + + load(type, data) { + + } +}; diff --git a/print/core/stylesheet.js b/print/core/stylesheet.js index ffa141968..42a44fb57 100644 --- a/print/core/stylesheet.js +++ b/print/core/stylesheet.js @@ -7,9 +7,8 @@ class Stylesheet { } mergeStyles() { - this.files.forEach(file => { + for (const file of this.files) this.css.push(fs.readFileSync(file)); - }); return this.css.join('\n'); } diff --git a/print/methods/closure.js b/print/methods/closure.js deleted file mode 100644 index 07bd1768d..000000000 --- a/print/methods/closure.js +++ /dev/null @@ -1,311 +0,0 @@ -const db = require('../core/database'); -const Email = require('../core/email'); -const Report = require('../core/report'); -const smtp = require('../core/smtp'); -const config = require('../core/config'); - -module.exports = app => { - app.get('/api/closure/all', async function(req, res, next) { - try { - const reqArgs = req.args; - if (!reqArgs.to) - throw new Error('The argument to is required'); - - res.status(200).json({ - message: 'Task executed successfully' - }); - - const tickets = await db.rawSql(` - SELECT - t.id - FROM expedition e - JOIN ticket t ON t.id = e.ticketFk - 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 - WHERE al.code = 'PACKED' - AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) - AND util.dayEnd(?) - AND t.refFk IS NULL - GROUP BY e.ticketFk`, [reqArgs.to, reqArgs.to]); - const ticketIds = tickets.map(ticket => ticket.id); - - await closeAll(ticketIds, req.args); - 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%'`, [reqArgs.to, reqArgs.to]); - } catch (error) { - next(error); - } - }); - - app.get('/api/closure/by-ticket', async function(req, res, next) { - try { - const reqArgs = req.args; - if (!reqArgs.ticketId) - throw new Error('The argument ticketId is required'); - - res.status(200).json({ - message: 'Task executed successfully' - }); - - const tickets = await db.rawSql(` - SELECT - t.id - 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 - WHERE al.code = 'PACKED' - AND t.id = ? - AND t.refFk IS NULL - GROUP BY e.ticketFk`, [reqArgs.ticketId]); - const ticketIds = tickets.map(ticket => ticket.id); - - await closeAll(ticketIds, reqArgs); - } catch (error) { - next(error); - } - }); - - app.get('/api/closure/by-agency', async function(req, res, next) { - try { - const reqArgs = req.args; - 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'); - - res.status(200).json({ - message: 'Task executed successfully' - }); - - const agenciesId = reqArgs.agencyModeId.split(','); - const tickets = await db.rawSql(` - SELECT - t.id - 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 - WHERE al.code = 'PACKED' - AND t.agencyModeFk IN(?) - AND t.warehouseFk = ? - AND DATE(t.shipped) BETWEEN DATE_ADD(:to, INTERVAL -2 DAY) - AND util.dayEnd(?) - AND t.refFk IS NULL - GROUP BY e.ticketFk`, [ - agenciesId, - reqArgs.warehouseId, - reqArgs.to, - reqArgs.to - ]); - const ticketIds = tickets.map(ticket => ticket.id); - - await closeAll(ticketIds, reqArgs); - } catch (error) { - next(error); - } - }); - - app.get('/api/closure/by-route', async function(req, res, next) { - try { - const reqArgs = req.args; - if (!reqArgs.routeId) - throw new Error('The argument routeId is required'); - - res.status(200).json({ - message: 'Task executed successfully' - }); - - const tickets = await db.rawSql(` - SELECT - t.id - 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 - WHERE al.code = 'PACKED' - AND t.routeFk = ? - AND t.refFk IS NULL - GROUP BY e.ticketFk`, [reqArgs.routeId]); - const ticketIds = tickets.map(ticket => ticket.id); - await closeAll(ticketIds, reqArgs); - - // 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: reqArgs.routeId, - recipient: agencyMail - }, reqArgs); - - const email = new Email('driver-route', args); - await email.send(); - } - } catch (error) { - next(error); - } - }); - - async function closeAll(ticketIds, reqArgs) { - const failedtickets = []; - const tickets = await db.rawSql(` - SELECT - t.id, - t.clientFk, - c.name clientName, - c.email recipient, - c.salesPersonFk, - c.isToBeMailed, - c.hasToInvoice, - co.hasDailyInvoice, - eu.email salesPersonEmail - FROM ticket t - 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 t.id IN(?)`, [ticketIds]); - - for (const ticket of tickets) { - try { - await db.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id]); - - if (!ticket.salesPersonFk || !ticket.isToBeMailed) continue; - - if (!ticket.recipient) { - const body = `No se ha podido enviar el albarán ${ticket.id} - al cliente ${ticket.clientFk} porque no tiene un email especificado.

- Para dejar de recibir esta notificación, asígnale un email o desactiva - la notificación por email para este cliente.`; - smtp.send({ - to: ticket.salesPersonEmail, - subject: 'No se ha podido enviar el albarán', - html: body - }); - - continue; - } - - const hasToInvoice = ticket.hasToInvoice && ticket.hasDailyInvoice; - if (hasToInvoice) { - const invoice = await db.findOne(` - SELECT io.id, io.ref, io.serial, cny.code companyCode - 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 args = Object.assign({ - invoiceId: invoice.id, - recipientId: ticket.clientFk, - recipient: ticket.recipient, - replyTo: ticket.salesPersonEmail - }, reqArgs); - - let mailOptions = {}; - if (invoice.serial == 'E' && invoice.companyCode == 'VNL') { - const exportation = new Report('exportation', args); - const stream = await exportation.toPdfStream(); - const fileName = `exportation-${invoice.ref}.pdf`; - mailOptions = { - overrideAttachments: false, - attachments: [{ - filename: fileName, - content: stream - }] - }; - } - - const email = new Email('invoice', args); - await email.send(mailOptions); - } else { - 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(); - } - } 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:

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

`; - } - - 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 ${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 - }); - } -}; diff --git a/print/methods/closure/closeAll.js b/print/methods/closure/closeAll.js new file mode 100644 index 000000000..7af3676f2 --- /dev/null +++ b/print/methods/closure/closeAll.js @@ -0,0 +1,58 @@ +const db = require('vn-print/core/database'); +const closure = require('./closure'); + +module.exports = async function(request, response, next) { + try { + const reqArgs = request.query; + if (!reqArgs.to) + throw new Error('The argument to is required'); + + response.status(200).json({ + message: 'Success' + }); + + const tickets = await db.rawSql(` + SELECT + t.id, + t.clientFk, + 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`, [reqArgs.to, reqArgs.to]); + + 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%'`, [reqArgs.to, reqArgs.to]); + } catch (error) { + next(error); + } +}; diff --git a/print/methods/closure/closeByAgency.js b/print/methods/closure/closeByAgency.js new file mode 100644 index 000000000..7807de23a --- /dev/null +++ b/print/methods/closure/closeByAgency.js @@ -0,0 +1,58 @@ +const db = require('vn-print/core/database'); +const closure = require('./closure'); + +module.exports = async function(request, response, next) { + try { + const reqArgs = request.query; + + 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'); + + response.status(200).json({ + message: 'Success' + }); + + const agencyIds = reqArgs.agencyModeId.split(','); + const tickets = await db.rawSql(` + SELECT + t.id, + t.clientFk, + 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); + } catch (error) { + next(error); + } +}; diff --git a/print/methods/closure/closeByRoute.js b/print/methods/closure/closeByRoute.js new file mode 100644 index 000000000..2c0bfd1eb --- /dev/null +++ b/print/methods/closure/closeByRoute.js @@ -0,0 +1,61 @@ +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.query; + + if (!reqArgs.routeId) + throw new Error('The argument routeId is required'); + + response.status(200).json({ + message: 'Success' + }); + + const tickets = await db.rawSql(` + SELECT + t.id, + t.clientFk, + 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(); + } + } catch (error) { + next(error); + } +}; diff --git a/print/methods/closure/closeByTicket.js b/print/methods/closure/closeByTicket.js new file mode 100644 index 000000000..c71b3ecd0 --- /dev/null +++ b/print/methods/closure/closeByTicket.js @@ -0,0 +1,43 @@ +const db = require('vn-print/core/database'); +const closure = require('./closure'); + +module.exports = async function(request, response, next) { + try { + const reqArgs = request.query; + + if (!reqArgs.ticketId) + throw new Error('The argument ticketId is required'); + + response.status(200).json({ + message: 'Success' + }); + + const tickets = await db.rawSql(` + SELECT + t.id, + t.clientFk, + 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); + } catch (error) { + next(error); + } +}; diff --git a/print/methods/closure/closure.js b/print/methods/closure/closure.js new file mode 100644 index 000000000..8cce8237c --- /dev/null +++ b/print/methods/closure/closure.js @@ -0,0 +1,153 @@ +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('START TRANSACTION'); + + 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({ + invoiceId: invoiceOut.id, + 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(); + } + await db.rawSql('COMMIT'); + } catch (error) { + await db.rawSql('ROLLBACK'); + // 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:

'; + + 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 + }); + } + }, + + async 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 ${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 + }); + } +}; diff --git a/print/methods/closure/index.js b/print/methods/closure/index.js new file mode 100644 index 000000000..fcca76f71 --- /dev/null +++ b/print/methods/closure/index.js @@ -0,0 +1,9 @@ +const express = require('express'); +const router = new express.Router(); + +router.get('/all', require('./closeAll')); +router.get('/by-ticket', require('./closeByTicket')); +router.get('/by-agency', require('./closeByAgency')); +router.get('/by-route', require('./closeByRoute')); + +module.exports = router; diff --git a/print/methods/csv.js b/print/methods/csv.js deleted file mode 100644 index 4f4cdf2af..000000000 --- a/print/methods/csv.js +++ /dev/null @@ -1,31 +0,0 @@ -module.exports = app => { - app.use('/api/csv/delivery-note', require('./csv/delivery-note')(app)); - app.use('/api/csv/invoice', require('./csv/invoice')(app)); - - app.toCSV = function toCSV(rows) { - const [columns] = rows; - let content = Object.keys(columns).join('\t'); - for (let row of rows) { - const values = Object.values(row); - const finalValues = values.map(value => { - if (value instanceof Date) return formatDate(value); - if (value === null) return ''; - return value; - }); - content += '\n'; - content += finalValues.join('\t'); - } - return content; - }; - - function formatDate(date) { - return new Intl.DateTimeFormat('es', { - year: 'numeric', - month: 'numeric', - day: 'numeric', - hour: '2-digit', - minute: '2-digit', - second: '2-digit' - }).format(date); - } -}; diff --git a/print/methods/csv/csv.js b/print/methods/csv/csv.js new file mode 100644 index 000000000..d8725582d --- /dev/null +++ b/print/methods/csv/csv.js @@ -0,0 +1,31 @@ +function toCSV(rows) { + const [columns] = rows; + let content = Object.keys(columns).join('\t'); + for (let row of rows) { + const values = Object.values(row); + const finalValues = values.map(value => { + if (value instanceof Date) return formatDate(value); + if (value === null) return ''; + return value; + }); + content += '\n'; + content += finalValues.join('\t'); + } + return content; +} + +function formatDate(date) { + return new Intl.DateTimeFormat('es', { + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }).format(date); +} + +module.exports = { + toCSV, + formatDate +}; diff --git a/print/methods/csv/delivery-note/download.js b/print/methods/csv/delivery-note/download.js new file mode 100644 index 000000000..d369d5f4a --- /dev/null +++ b/print/methods/csv/delivery-note/download.js @@ -0,0 +1,24 @@ +const path = require('path'); +const db = require('vn-print/core/database'); + +const {toCSV} = require('../csv'); +const sqlPath = path.join(__dirname, 'sql'); + +module.exports = async function(request, response, next) { + try { + const reqArgs = request.query; + if (!reqArgs.ticketId) + throw new Error('The argument ticketId is required'); + + const ticketId = reqArgs.ticketId; + const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [ticketId]); + const content = toCSV(sales); + const fileName = `ticket_${ticketId}.csv`; + + response.setHeader('Content-type', 'text/csv'); + response.setHeader('Content-Disposition', `inline; filename="${fileName}"`); + response.end(content); + } catch (error) { + next(error); + } +}; diff --git a/print/methods/csv/delivery-note/index.js b/print/methods/csv/delivery-note/index.js deleted file mode 100644 index 9ef0e33fa..000000000 --- a/print/methods/csv/delivery-note/index.js +++ /dev/null @@ -1,82 +0,0 @@ -const express = require('express'); -const router = new express.Router(); -const path = require('path'); -const db = require('../../../core/database'); -const sqlPath = path.join(__dirname, 'sql'); - -module.exports = app => { - router.get('/preview', async function(req, res, next) { - try { - const reqArgs = req.args; - if (!reqArgs.ticketId) - throw new Error('The argument ticketId is required'); - - const ticketId = reqArgs.ticketId; - const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [ticketId]); - const content = app.toCSV(sales); - const fileName = `ticket_${ticketId}.csv`; - - res.setHeader('Content-type', 'application/json; charset=utf-8'); - res.setHeader('Content-Disposition', `inline; filename="${fileName}"`); - res.end(content); - } catch (error) { - next(error); - } - }); - - router.get('/download', async function(req, res, next) { - try { - const reqArgs = req.args; - if (!reqArgs.ticketId) - throw new Error('The argument ticketId is required'); - - const ticketId = reqArgs.ticketId; - const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [ticketId]); - const content = app.toCSV(sales); - const fileName = `ticket_${ticketId}.csv`; - - res.setHeader('Content-type', 'text/csv'); - res.setHeader('Content-Disposition', `inline; filename="${fileName}"`); - res.end(content); - } catch (error) { - next(error); - } - }); - - const Email = require('../../../core/email'); - router.get('/send', async function(req, res, next) { - try { - const reqArgs = req.args; - if (!reqArgs.ticketId) - throw new Error('The argument ticketId is required'); - - const ticketId = reqArgs.ticketId; - const ticket = await db.findOneFromDef(`${sqlPath}/ticket`, [ticketId]); - const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [ticketId]); - - const args = Object.assign({ - ticketId: (String(ticket.id)), - recipientId: ticket.clientFk, - recipient: ticket.recipient, - replyTo: ticket.salesPersonEmail - }, reqArgs); - - const content = app.toCSV(sales); - const fileName = `ticket_${ticketId}.csv`; - const email = new Email('delivery-note', args); - await email.send({ - overrideAttachments: true, - attachments: [{ - filename: fileName, - content: content - }] - }); - - res.status(200).json({message: 'ok'}); - } catch (error) { - next(error); - } - }); - - return router; -}; diff --git a/print/methods/csv/delivery-note/send.js b/print/methods/csv/delivery-note/send.js new file mode 100644 index 000000000..478f20f57 --- /dev/null +++ b/print/methods/csv/delivery-note/send.js @@ -0,0 +1,40 @@ +const path = require('path'); +const db = require('vn-print/core/database'); +const Email = require('vn-print/core/email'); + +const {toCSV} = require('../csv'); +const sqlPath = path.join(__dirname, 'sql'); + +module.exports = async function(request, response, next) { + try { + const reqArgs = request.query; + if (!reqArgs.ticketId) + throw new Error('The argument ticketId is required'); + + const ticketId = reqArgs.ticketId; + const ticket = await db.findOneFromDef(`${sqlPath}/ticket`, [ticketId]); + const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [ticketId]); + + const args = Object.assign({ + ticketId: (String(ticket.id)), + recipientId: ticket.clientFk, + recipient: ticket.recipient, + replyTo: ticket.salesPersonEmail + }, response.locals); + + const content = toCSV(sales); + const fileName = `ticket_${ticketId}.csv`; + const email = new Email('delivery-note', args); + await email.send({ + overrideAttachments: true, + attachments: [{ + filename: fileName, + content: content + }] + }); + + response.status(200).json({message: 'Success'}); + } catch (error) { + next(error); + } +}; diff --git a/print/methods/csv/index.js b/print/methods/csv/index.js new file mode 100644 index 000000000..6bdd1b60d --- /dev/null +++ b/print/methods/csv/index.js @@ -0,0 +1,9 @@ +const express = require('express'); +const router = new express.Router(); + +router.get('/delivery-note/download', require('./delivery-note/download')); +router.get('/delivery-note/send', require('./delivery-note/send')); +router.get('/invoice/download', require('./invoice/download')); +router.get('/invoice/send', require('./invoice/send')); + +module.exports = router; diff --git a/print/methods/csv/invoice/download.js b/print/methods/csv/invoice/download.js new file mode 100644 index 000000000..593d2d8d0 --- /dev/null +++ b/print/methods/csv/invoice/download.js @@ -0,0 +1,24 @@ +const path = require('path'); +const db = require('vn-print/core/database'); + +const {toCSV} = require('../csv'); +const sqlPath = path.join(__dirname, 'sql'); + +module.exports = async function(request, response, next) { + try { + const reqArgs = request.query; + if (!reqArgs.invoiceId) + throw new Error('The argument invoiceId is required'); + + const invoiceId = reqArgs.invoiceId; + const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [invoiceId]); + const content = toCSV(sales); + const fileName = `invoice_${invoiceId}.csv`; + + response.setHeader('Content-type', 'text/csv'); + response.setHeader('Content-Disposition', `inline; filename="${fileName}"`); + response.end(content); + } catch (error) { + next(error); + } +}; diff --git a/print/methods/csv/invoice/index.js b/print/methods/csv/invoice/index.js deleted file mode 100644 index 8f325be02..000000000 --- a/print/methods/csv/invoice/index.js +++ /dev/null @@ -1,82 +0,0 @@ -const express = require('express'); -const router = new express.Router(); -const path = require('path'); -const db = require('../../../core/database'); -const sqlPath = path.join(__dirname, 'sql'); - -module.exports = app => { - router.get('/preview', async function(req, res, next) { - try { - const reqArgs = req.args; - if (!reqArgs.invoiceId) - throw new Error('The argument invoiceId is required'); - - const invoiceId = reqArgs.invoiceId; - const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [invoiceId]); - const content = app.toCSV(sales); - const fileName = `invoice_${invoiceId}.csv`; - - res.setHeader('Content-type', 'application/json; charset=utf-8'); - res.setHeader('Content-Disposition', `inline; filename="${fileName}"`); - res.end(content); - } catch (error) { - next(error); - } - }); - - router.get('/download', async function(req, res, next) { - try { - const reqArgs = req.args; - if (!reqArgs.invoiceId) - throw new Error('The argument invoiceId is required'); - - const invoiceId = reqArgs.invoiceId; - const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [invoiceId]); - const content = app.toCSV(sales); - const fileName = `invoice_${invoiceId}.csv`; - - res.setHeader('Content-type', 'text/csv'); - res.setHeader('Content-Disposition', `inline; filename="${fileName}"`); - res.end(content); - } catch (error) { - next(error); - } - }); - - const Email = require('../../../core/email'); - router.get('/send', async function(req, res, next) { - try { - const reqArgs = req.args; - if (!reqArgs.invoiceId) - throw new Error('The argument invoiceId is required'); - - const invoiceId = reqArgs.invoiceId; - const invoice = await db.findOneFromDef(`${sqlPath}/invoice`, [invoiceId]); - const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [invoiceId]); - - const args = Object.assign({ - invoiceId: (String(invoice.id)), - recipientId: invoice.clientFk, - recipient: invoice.recipient, - replyTo: invoice.salesPersonEmail - }, reqArgs); - - const content = app.toCSV(sales); - const fileName = `invoice_${invoiceId}.csv`; - const email = new Email('invoice', args); - await email.send({ - overrideAttachments: true, - attachments: [{ - filename: fileName, - content: content - }] - }); - - res.status(200).json({message: 'ok'}); - } catch (error) { - next(error); - } - }); - - return router; -}; diff --git a/print/methods/csv/invoice/send.js b/print/methods/csv/invoice/send.js new file mode 100644 index 000000000..919d7aeb1 --- /dev/null +++ b/print/methods/csv/invoice/send.js @@ -0,0 +1,40 @@ +const path = require('path'); +const db = require('vn-print/core/database'); +const Email = require('vn-print/core/email'); + +const {toCSV} = require('../csv'); +const sqlPath = path.join(__dirname, 'sql'); + +module.exports = async function(request, response, next) { + try { + const reqArgs = request.query; + if (!reqArgs.invoiceId) + throw new Error('The argument invoiceId is required'); + + const invoiceId = reqArgs.invoiceId; + const invoice = await db.findOneFromDef(`${sqlPath}/invoice`, [invoiceId]); + const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [invoiceId]); + + const args = Object.assign({ + invoiceId: (String(invoice.id)), + recipientId: invoice.clientFk, + recipient: invoice.recipient, + replyTo: invoice.salesPersonEmail + }, response.locals); + + const content = toCSV(sales); + const fileName = `invoice_${invoiceId}.csv`; + const email = new Email('invoice', args); + await email.send({ + overrideAttachments: true, + attachments: [{ + filename: fileName, + content: content + }] + }); + + response.status(200).json({message: 'Success'}); + } catch (error) { + next(error); + } +}; diff --git a/print/methods/email.js b/print/methods/email.js deleted file mode 100644 index cc4590e5d..000000000 --- a/print/methods/email.js +++ /dev/null @@ -1,33 +0,0 @@ -const Email = require('../core/email'); - -module.exports = app => { - app.get(`/api/email/:name`, async(req, res, next) => { - try { - const reportName = req.params.name; - const email = new Email(reportName, req.args); - - await email.send(); - - res.status(200).json({ - message: 'Sent' - }); - } catch (e) { - next(e); - } - }); - - app.get(`/api/email/:name/preview`, async(req, res, next) => { - try { - const reportName = req.params.name; - const args = req.args; - args.isPreview = true; - - const email = new Email(reportName, args); - const rendered = await email.render(); - - res.send(rendered); - } catch (e) { - next(e); - } - }); -}; diff --git a/print/methods/email/email.js b/print/methods/email/email.js new file mode 100644 index 000000000..5d6882f7d --- /dev/null +++ b/print/methods/email/email.js @@ -0,0 +1,16 @@ +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); + } +}; diff --git a/print/methods/email/index.js b/print/methods/email/index.js new file mode 100644 index 000000000..10c2d2325 --- /dev/null +++ b/print/methods/email/index.js @@ -0,0 +1,7 @@ +const express = require('express'); +const router = new express.Router(); + +router.get('/:name', require('./email')); +router.get('/:name/preview', require('./preview')); + +module.exports = router; diff --git a/print/methods/email/preview.js b/print/methods/email/preview.js new file mode 100644 index 000000000..e6a1aaf35 --- /dev/null +++ b/print/methods/email/preview.js @@ -0,0 +1,14 @@ +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); + } +}; diff --git a/print/methods/report.js b/print/methods/report.js deleted file mode 100644 index 750fec4c8..000000000 --- a/print/methods/report.js +++ /dev/null @@ -1,54 +0,0 @@ -const Report = require('../core/report'); - -module.exports = app => { - app.get(`/api/report/:name`, async(req, res, next) => { - try { - const reportName = req.params.name; - const fileName = getFileName(reportName, req.args); - const report = new Report(reportName, req.args); - if (req.args.preview) { - const template = await report.render(); - res.send(template); - } else { - const stream = await report.toPdfStream(); - - res.setHeader('Content-type', 'application/pdf'); - res.setHeader('Content-Disposition', `inline; filename="${fileName}"`); - res.end(stream); - } - } catch (error) { - next(error); - } - }); - - /** - * Returns all the params that ends with id - * @param {object} args - Params object - * - * @return {array} List of identifiers - */ - function getIdentifiers(args) { - const identifiers = []; - const keys = Object.keys(args); - - for (let arg of keys) { - if (arg.endsWith('Id')) - identifiers.push(arg); - } - - return identifiers; - } - - function getFileName(name, args) { - const identifiers = getIdentifiers(args); - const params = []; - params.push(name); - - for (let id of identifiers) - params.push(args[id]); - - const fileName = params.join('_'); - - return `${fileName}.pdf`; - } -}; diff --git a/print/methods/report/document.js b/print/methods/report/document.js new file mode 100644 index 000000000..b24abf4ac --- /dev/null +++ b/print/methods/report/document.js @@ -0,0 +1,17 @@ +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); + } +}; diff --git a/print/methods/report/index.js b/print/methods/report/index.js new file mode 100644 index 000000000..c422c76df --- /dev/null +++ b/print/methods/report/index.js @@ -0,0 +1,7 @@ +const express = require('express'); +const router = new express.Router(); + +router.get('/:name', require('./document')); +router.get('/:name/preview', require('./preview')); + +module.exports = router; diff --git a/print/methods/report/preview.js b/print/methods/report/preview.js new file mode 100644 index 000000000..0d6ad6f43 --- /dev/null +++ b/print/methods/report/preview.js @@ -0,0 +1,13 @@ +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); + } +}; diff --git a/print/methods/routes.js b/print/methods/routes.js new file mode 100644 index 000000000..0c452028e --- /dev/null +++ b/print/methods/routes.js @@ -0,0 +1,18 @@ +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') + }, +]; diff --git a/print/templates/email/campaign-metrics/campaign-metrics.js b/print/templates/email/campaign-metrics/campaign-metrics.js index 0ace0fc25..2bd93b725 100755 --- a/print/templates/email/campaign-metrics/campaign-metrics.js +++ b/print/templates/email/campaign-metrics/campaign-metrics.js @@ -21,6 +21,7 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true }, from: { diff --git a/print/templates/email/claim-pickup-order/claim-pickup-order.js b/print/templates/email/claim-pickup-order/claim-pickup-order.js index 4396b144a..cf4ba7d12 100755 --- a/print/templates/email/claim-pickup-order/claim-pickup-order.js +++ b/print/templates/email/claim-pickup-order/claim-pickup-order.js @@ -10,6 +10,7 @@ module.exports = { }, props: { claimId: { + type: [Number, String], required: true } } diff --git a/print/templates/email/client-debt-statement/client-debt-statement.js b/print/templates/email/client-debt-statement/client-debt-statement.js index c32e68943..f32f9e239 100755 --- a/print/templates/email/client-debt-statement/client-debt-statement.js +++ b/print/templates/email/client-debt-statement/client-debt-statement.js @@ -16,6 +16,7 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true }, from: { diff --git a/print/templates/email/client-welcome/client-welcome.js b/print/templates/email/client-welcome/client-welcome.js index f562339cc..eeb11bb78 100755 --- a/print/templates/email/client-welcome/client-welcome.js +++ b/print/templates/email/client-welcome/client-welcome.js @@ -18,6 +18,7 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true } } diff --git a/print/templates/email/delivery-note-link/delivery-note-link.js b/print/templates/email/delivery-note-link/delivery-note-link.js index 009fe7b5b..471b370d9 100755 --- a/print/templates/email/delivery-note-link/delivery-note-link.js +++ b/print/templates/email/delivery-note-link/delivery-note-link.js @@ -10,6 +10,7 @@ module.exports = { }, props: { ticketId: { + type: [Number, String], required: true } } diff --git a/print/templates/email/delivery-note/delivery-note.js b/print/templates/email/delivery-note/delivery-note.js index 64839b8e0..ffd2fe202 100755 --- a/print/templates/email/delivery-note/delivery-note.js +++ b/print/templates/email/delivery-note/delivery-note.js @@ -10,7 +10,7 @@ module.exports = { }, props: { ticketId: { - type: String, + type: [Number, String], required: true } } diff --git a/print/templates/email/driver-route/driver-route.js b/print/templates/email/driver-route/driver-route.js index de1dd9c39..378cd82ce 100755 --- a/print/templates/email/driver-route/driver-route.js +++ b/print/templates/email/driver-route/driver-route.js @@ -10,7 +10,7 @@ module.exports = { }, props: { routeId: { - type: String, + type: [Number, String], required: true } } diff --git a/print/templates/email/invoice/invoice.js b/print/templates/email/invoice/invoice.js index b8d3b8282..d92b65cb3 100755 --- a/print/templates/email/invoice/invoice.js +++ b/print/templates/email/invoice/invoice.js @@ -18,7 +18,7 @@ module.exports = { }, props: { invoiceId: { - type: String, + type: [Number, String], required: true } } diff --git a/print/templates/email/letter-debtor-nd/letter-debtor-nd.js b/print/templates/email/letter-debtor-nd/letter-debtor-nd.js index ba9f7957d..5e010d1ba 100755 --- a/print/templates/email/letter-debtor-nd/letter-debtor-nd.js +++ b/print/templates/email/letter-debtor-nd/letter-debtor-nd.js @@ -30,9 +30,11 @@ module.exports = { required: true }, recipientId: { + type: [Number, String], required: true }, companyId: { + type: [Number, String], required: true } } diff --git a/print/templates/email/letter-debtor-st/letter-debtor-st.js b/print/templates/email/letter-debtor-st/letter-debtor-st.js index 56fc7c8a8..a514097cf 100755 --- a/print/templates/email/letter-debtor-st/letter-debtor-st.js +++ b/print/templates/email/letter-debtor-st/letter-debtor-st.js @@ -1,5 +1,4 @@ const Component = require(`${appPath}/core/component`); -const db = require(`${appPath}/core/database`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); @@ -28,9 +27,11 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true }, companyId: { + type: [Number, String], required: true }, } diff --git a/print/templates/email/payment-update/payment-update.js b/print/templates/email/payment-update/payment-update.js index eb6690c02..2b92976a3 100755 --- a/print/templates/email/payment-update/payment-update.js +++ b/print/templates/email/payment-update/payment-update.js @@ -26,6 +26,7 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true } } diff --git a/print/templates/email/printer-setup/printer-setup.js b/print/templates/email/printer-setup/printer-setup.js index f6f168163..95dff8ebb 100755 --- a/print/templates/email/printer-setup/printer-setup.js +++ b/print/templates/email/printer-setup/printer-setup.js @@ -24,6 +24,7 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true } } diff --git a/print/templates/email/sepa-core/sepa-core.js b/print/templates/email/sepa-core/sepa-core.js index 76f8d842f..743c6719c 100755 --- a/print/templates/email/sepa-core/sepa-core.js +++ b/print/templates/email/sepa-core/sepa-core.js @@ -16,9 +16,11 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true }, companyId: { + type: [Number, String], required: true } } diff --git a/print/templates/email/supplier-campaign-metrics/supplier-campaign-metrics.js b/print/templates/email/supplier-campaign-metrics/supplier-campaign-metrics.js index 20113d8ea..3cf290e4d 100755 --- a/print/templates/email/supplier-campaign-metrics/supplier-campaign-metrics.js +++ b/print/templates/email/supplier-campaign-metrics/supplier-campaign-metrics.js @@ -21,6 +21,7 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true }, from: { diff --git a/print/templates/reports/campaign-metrics/campaign-metrics.js b/print/templates/reports/campaign-metrics/campaign-metrics.js index 07d261a61..6669ce067 100755 --- a/print/templates/reports/campaign-metrics/campaign-metrics.js +++ b/print/templates/reports/campaign-metrics/campaign-metrics.js @@ -25,6 +25,7 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true }, from: { diff --git a/print/templates/reports/campaign-metrics/locale/es.yml b/print/templates/reports/campaign-metrics/locale/es.yml index 8a4cc4637..c455be5a8 100644 --- a/print/templates/reports/campaign-metrics/locale/es.yml +++ b/print/templates/reports/campaign-metrics/locale/es.yml @@ -1,3 +1,4 @@ +reportName: consumo-cliente title: Consumo Client: Cliente clientData: Datos del cliente diff --git a/print/templates/reports/claim-pickup-order/claim-pickup-order.js b/print/templates/reports/claim-pickup-order/claim-pickup-order.js index 0d1228a4e..fa2124057 100755 --- a/print/templates/reports/claim-pickup-order/claim-pickup-order.js +++ b/print/templates/reports/claim-pickup-order/claim-pickup-order.js @@ -32,6 +32,7 @@ module.exports = { }, props: { claimId: { + type: [Number, String], required: true } } diff --git a/print/templates/reports/claim-pickup-order/locale/es.yml b/print/templates/reports/claim-pickup-order/locale/es.yml index 9faf9ac06..faa6eac33 100644 --- a/print/templates/reports/claim-pickup-order/locale/es.yml +++ b/print/templates/reports/claim-pickup-order/locale/es.yml @@ -1,3 +1,4 @@ +reportName: orden-de-recogida title: Ord. recogida claimId: Reclamación clientId: Cliente diff --git a/print/templates/reports/client-debt-statement/client-debt-statement.js b/print/templates/reports/client-debt-statement/client-debt-statement.js index 09b99590b..f006b0a92 100755 --- a/print/templates/reports/client-debt-statement/client-debt-statement.js +++ b/print/templates/reports/client-debt-statement/client-debt-statement.js @@ -69,6 +69,7 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true }, from: { diff --git a/print/templates/reports/client-debt-statement/locale/es.yml b/print/templates/reports/client-debt-statement/locale/es.yml index ccdce7b5b..2c8e18ee1 100644 --- a/print/templates/reports/client-debt-statement/locale/es.yml +++ b/print/templates/reports/client-debt-statement/locale/es.yml @@ -1,3 +1,4 @@ +reportName: extracto-cliente title: Extracto clientId: Cliente clientData: Datos del cliente diff --git a/print/templates/reports/client-debt-statement/locale/fr.yml b/print/templates/reports/client-debt-statement/locale/fr.yml index 12534f9ff..4edb29d8a 100644 --- a/print/templates/reports/client-debt-statement/locale/fr.yml +++ b/print/templates/reports/client-debt-statement/locale/fr.yml @@ -1,3 +1,4 @@ +reportName: releve-de-compte title: Relevé de compte clientId: Client clientData: Données client diff --git a/print/templates/reports/cmr-authorization/cmr-authorization.js b/print/templates/reports/cmr-authorization/cmr-authorization.js index da08b6ec8..1adc75fa6 100755 --- a/print/templates/reports/cmr-authorization/cmr-authorization.js +++ b/print/templates/reports/cmr-authorization/cmr-authorization.js @@ -8,9 +8,8 @@ module.exports = { this.ticket = await this.findOneFromDef('ticket', [this.ticketId]); if (!this.ticket) throw new Error('Something went wrong'); - - this.client = await this.findOneFromDef('client', [this.ticket.clientFk]); + this.client = await this.findOneFromDef('client', [this.ticket.clientFk]); }, computed: { issued: function() { @@ -23,6 +22,7 @@ module.exports = { }, props: { ticketId: { + type: [Number, String], required: true } } diff --git a/print/templates/reports/cmr-authorization/locale/es.yml b/print/templates/reports/cmr-authorization/locale/es.yml index 779dc0c8f..37e40202d 100644 --- a/print/templates/reports/cmr-authorization/locale/es.yml +++ b/print/templates/reports/cmr-authorization/locale/es.yml @@ -1,3 +1,4 @@ +reportName: autorizacion-cmr description: '{socialName} una sociedad debidamente constituida con responsabilidad limitada y registrada conforme al derecho de sociedades de {country} y aquí representada por ___________________. {socialName}, con domicilio en {address}, diff --git a/print/templates/reports/credit-request/locale/es.yml b/print/templates/reports/credit-request/locale/es.yml index e4e9739a5..cd6f92dc5 100644 --- a/print/templates/reports/credit-request/locale/es.yml +++ b/print/templates/reports/credit-request/locale/es.yml @@ -1,3 +1,4 @@ +reportName: solicitud-de-credito fields: title: Solicitud de crédito date: Fecha diff --git a/print/templates/reports/delivery-note/delivery-note.js b/print/templates/reports/delivery-note/delivery-note.js index 9b3328d05..0ee7c8c91 100755 --- a/print/templates/reports/delivery-note/delivery-note.js +++ b/print/templates/reports/delivery-note/delivery-note.js @@ -117,7 +117,7 @@ module.exports = { }, props: { ticketId: { - type: String, + type: [Number, String], required: true } } diff --git a/print/templates/reports/delivery-note/locale/en.yml b/print/templates/reports/delivery-note/locale/en.yml index 8a3ff834b..16d0954e2 100644 --- a/print/templates/reports/delivery-note/locale/en.yml +++ b/print/templates/reports/delivery-note/locale/en.yml @@ -1,3 +1,4 @@ +reportName: delivery-note title: Delivery note ticketId: Delivery note clientId: Client diff --git a/print/templates/reports/delivery-note/locale/es.yml b/print/templates/reports/delivery-note/locale/es.yml index f9c2e02f3..ca670ad59 100644 --- a/print/templates/reports/delivery-note/locale/es.yml +++ b/print/templates/reports/delivery-note/locale/es.yml @@ -1,3 +1,4 @@ +reportName: albaran title: Albarán ticketId: Albarán clientId: Cliente diff --git a/print/templates/reports/delivery-note/locale/fr.yml b/print/templates/reports/delivery-note/locale/fr.yml index 72ca771e1..6b3779a5b 100644 --- a/print/templates/reports/delivery-note/locale/fr.yml +++ b/print/templates/reports/delivery-note/locale/fr.yml @@ -1,3 +1,4 @@ +reportName: bon-de-livraison title: Bon de livraison ticketId: BL clientId: Client diff --git a/print/templates/reports/delivery-note/locale/pt.yml b/print/templates/reports/delivery-note/locale/pt.yml index e83087142..1a9c1fbd1 100644 --- a/print/templates/reports/delivery-note/locale/pt.yml +++ b/print/templates/reports/delivery-note/locale/pt.yml @@ -1,3 +1,4 @@ +reportName: nota-de-entrega title: Nota de Entrega ticketId: Nota de Entrega clientId: Cliente diff --git a/print/templates/reports/driver-route/driver-route.js b/print/templates/reports/driver-route/driver-route.js index 0b2638239..c34de37cc 100755 --- a/print/templates/reports/driver-route/driver-route.js +++ b/print/templates/reports/driver-route/driver-route.js @@ -39,6 +39,7 @@ module.exports = { }, props: { routeId: { + type: [Number, String], required: true } } diff --git a/print/templates/reports/driver-route/locale/es.yml b/print/templates/reports/driver-route/locale/es.yml index 4f0f3ac3c..4c922ba64 100644 --- a/print/templates/reports/driver-route/locale/es.yml +++ b/print/templates/reports/driver-route/locale/es.yml @@ -1,3 +1,4 @@ +reportName: hoja-de-ruta title: Hoja de ruta information: Información date: Fecha diff --git a/print/templates/reports/entry-order/entry-order.js b/print/templates/reports/entry-order/entry-order.js index de396df2c..52a56bf03 100755 --- a/print/templates/reports/entry-order/entry-order.js +++ b/print/templates/reports/entry-order/entry-order.js @@ -40,7 +40,7 @@ module.exports = { }, props: { entryId: { - type: String, + type: [Number, String], required: true } } diff --git a/print/templates/reports/entry-order/locale/es.yml b/print/templates/reports/entry-order/locale/es.yml index 3c29d6401..5c633aeaa 100644 --- a/print/templates/reports/entry-order/locale/es.yml +++ b/print/templates/reports/entry-order/locale/es.yml @@ -1,3 +1,4 @@ +reportName: pedido-de-entrada title: Pedido supplierName: Proveedor supplierStreet: Dirección diff --git a/print/templates/reports/exportation/exportation.js b/print/templates/reports/exportation/exportation.js index f63d17930..fbf663249 100755 --- a/print/templates/reports/exportation/exportation.js +++ b/print/templates/reports/exportation/exportation.js @@ -28,6 +28,7 @@ module.exports = { }, props: { invoiceId: { + type: [Number, String], required: true } } diff --git a/print/templates/reports/exportation/locale/es.yml b/print/templates/reports/exportation/locale/es.yml index d5fb78b4c..a689e245b 100644 --- a/print/templates/reports/exportation/locale/es.yml +++ b/print/templates/reports/exportation/locale/es.yml @@ -1,3 +1,4 @@ +reportName: carta-CITES title: 'Carta CITES' toAttention: 'A la atención del Sr. Administrador de la Aduana de la Farga de Moles.' declaration: 'Por la presente DECLARO, bajo mi responsabilidad, que las mercancías detalladas en la factura diff --git a/print/templates/reports/extra-community/locale/es.yml b/print/templates/reports/extra-community/locale/es.yml index 1112b0fe8..36201400f 100644 --- a/print/templates/reports/extra-community/locale/es.yml +++ b/print/templates/reports/extra-community/locale/es.yml @@ -1,3 +1,4 @@ +reportName: orden-de-carga title: Orden de carga reference: Referencia information: Información diff --git a/print/templates/reports/invoice-incoterms/invoice-incoterms.js b/print/templates/reports/invoice-incoterms/invoice-incoterms.js index 95bf1f397..99e23e15f 100755 --- a/print/templates/reports/invoice-incoterms/invoice-incoterms.js +++ b/print/templates/reports/invoice-incoterms/invoice-incoterms.js @@ -32,7 +32,7 @@ module.exports = { }, props: { invoiceId: { - type: String, + type: [Number, String], required: true } } diff --git a/print/templates/reports/invoice-incoterms/locale/es.yml b/print/templates/reports/invoice-incoterms/locale/es.yml index 9828564d7..a69805935 100644 --- a/print/templates/reports/invoice-incoterms/locale/es.yml +++ b/print/templates/reports/invoice-incoterms/locale/es.yml @@ -1,3 +1,4 @@ +reportName: factura title: Factura invoice: Factura clientId: Cliente diff --git a/print/templates/reports/invoice/invoice.js b/print/templates/reports/invoice/invoice.js index b56a5533c..bd85a812c 100755 --- a/print/templates/reports/invoice/invoice.js +++ b/print/templates/reports/invoice/invoice.js @@ -115,7 +115,7 @@ module.exports = { }, props: { invoiceId: { - type: String, + type: [Number, String], required: true } } diff --git a/print/templates/reports/invoice/locale/en.yml b/print/templates/reports/invoice/locale/en.yml new file mode 100644 index 000000000..4e4688b55 --- /dev/null +++ b/print/templates/reports/invoice/locale/en.yml @@ -0,0 +1,36 @@ +reportName: invoice +title: Invoice +invoice: Invoice +clientId: Client +invoiceData: Invoice data +fiscalId: FI / NIF +invoiceRef: Invoice {0} +deliveryNote: Delivery note +shipped: Shipped +date: Date +reference: Ref. +quantity: Qty. +concept: Concept +price: PSP/u +discount: Disc. +vat: VAT +amount: Amount +type: Type +taxBase: Tax base +tax: Tax +fee: Fee +total: Total +subtotal: Subtotal +taxBreakdown: Tax breakdown +notes: Notes +intrastat: Intrastat +code: Code +description: Description +stems: Stems +netKg: Net kg +rectifiedInvoices: Rectified invoices +issued: Issued +plantPassport: Plant passport +observations: Observations +wireTransfer: "Pay method: Transferencia" +accountNumber: "Account number: {0}" \ No newline at end of file diff --git a/print/templates/reports/invoice/locale/es.yml b/print/templates/reports/invoice/locale/es.yml index 6fdfc8a14..d37e77943 100644 --- a/print/templates/reports/invoice/locale/es.yml +++ b/print/templates/reports/invoice/locale/es.yml @@ -1,3 +1,4 @@ +reportName: factura title: Factura invoice: Factura clientId: Cliente diff --git a/print/templates/reports/letter-debtor/letter-debtor.js b/print/templates/reports/letter-debtor/letter-debtor.js index bdb3a504a..354b1d8d8 100755 --- a/print/templates/reports/letter-debtor/letter-debtor.js +++ b/print/templates/reports/letter-debtor/letter-debtor.js @@ -63,9 +63,11 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true }, companyId: { + type: [Number, String], required: true } } diff --git a/print/templates/reports/letter-debtor/locale/es.yml b/print/templates/reports/letter-debtor/locale/es.yml index a9bd8c796..6c66f0717 100644 --- a/print/templates/reports/letter-debtor/locale/es.yml +++ b/print/templates/reports/letter-debtor/locale/es.yml @@ -1,3 +1,4 @@ +reportName: extracto-de-cuenta title: Extracto claimId: Reclamación clientId: Cliente diff --git a/print/templates/reports/letter-debtor/locale/fr.yml b/print/templates/reports/letter-debtor/locale/fr.yml index eff39d783..277c1162f 100644 --- a/print/templates/reports/letter-debtor/locale/fr.yml +++ b/print/templates/reports/letter-debtor/locale/fr.yml @@ -1,3 +1,4 @@ +reportName: releve-de-compte title: Relevé de compte claimId: Réclamation clientId: Client diff --git a/print/templates/reports/receipt/locale/es.yml b/print/templates/reports/receipt/locale/es.yml index 67b9a948f..41be106df 100644 --- a/print/templates/reports/receipt/locale/es.yml +++ b/print/templates/reports/receipt/locale/es.yml @@ -1,3 +1,4 @@ +reportName: receipt title: 'Recibo' date: 'Fecha' payed: 'En {0}, a {1} de {2} de {3}' diff --git a/print/templates/reports/receipt/receipt.js b/print/templates/reports/receipt/receipt.js index d34735bb7..d7f4dd6da 100755 --- a/print/templates/reports/receipt/receipt.js +++ b/print/templates/reports/receipt/receipt.js @@ -25,6 +25,7 @@ module.exports = { }, props: { receiptId: { + type: [Number, String], required: true } } diff --git a/print/templates/reports/sepa-core/locale/es.yml b/print/templates/reports/sepa-core/locale/es.yml index bb9cc4e49..5f3f08fc3 100644 --- a/print/templates/reports/sepa-core/locale/es.yml +++ b/print/templates/reports/sepa-core/locale/es.yml @@ -1,3 +1,4 @@ +reportName: orden-de-domiciliacion title: Orden de domiciliación de adeudo SEPA CORE description: Mediante la firma de esta orden de domiciliación, el deudor autoriza (A) al acreedor a enviar instrucciones a la entidad del deudor para adeudar su cuenta diff --git a/print/templates/reports/sepa-core/locale/fr.yml b/print/templates/reports/sepa-core/locale/fr.yml index 45a9039ea..354c06114 100644 --- a/print/templates/reports/sepa-core/locale/fr.yml +++ b/print/templates/reports/sepa-core/locale/fr.yml @@ -1,3 +1,4 @@ +reportName: direct-debit title: Direct Debit description: En signant ce formulaire de mandat, vous autorisez VERDNATURA LEVANTE SL à envoyer des instructions à votre banque pour débiter votre compte, et (B) votre banque diff --git a/print/templates/reports/sepa-core/locale/pt.yml b/print/templates/reports/sepa-core/locale/pt.yml index e7127d06b..5459779ec 100644 --- a/print/templates/reports/sepa-core/locale/pt.yml +++ b/print/templates/reports/sepa-core/locale/pt.yml @@ -1,3 +1,4 @@ +reportName: autorizacao-de-debito title: Autorização de débito directo SEPA CORE description: Ao subscrever esta autorização, está a autorizar a (A) Verdnatura Levante S.L. a enviar instruções ao seu banco para debitar a sua conta e (B) seu banco a diff --git a/print/templates/reports/sepa-core/sepa-core.js b/print/templates/reports/sepa-core/sepa-core.js index 55487d829..7e3dd3566 100755 --- a/print/templates/reports/sepa-core/sepa-core.js +++ b/print/templates/reports/sepa-core/sepa-core.js @@ -40,9 +40,11 @@ const rptSepaCore = { }, props: { recipientId: { + type: [Number, String], required: true }, companyId: { + type: [Number, String], required: true } } diff --git a/print/templates/reports/supplier-campaign-metrics/locale/es.yml b/print/templates/reports/supplier-campaign-metrics/locale/es.yml index 31c1e17dd..1a38541fa 100644 --- a/print/templates/reports/supplier-campaign-metrics/locale/es.yml +++ b/print/templates/reports/supplier-campaign-metrics/locale/es.yml @@ -1,3 +1,4 @@ +reportName: consumo-proveedor title: Consumo Supplier: Proveedor supplierData: Datos del proveedor diff --git a/print/templates/reports/supplier-campaign-metrics/supplier-campaign-metrics.js b/print/templates/reports/supplier-campaign-metrics/supplier-campaign-metrics.js index c37155556..1a460daa9 100755 --- a/print/templates/reports/supplier-campaign-metrics/supplier-campaign-metrics.js +++ b/print/templates/reports/supplier-campaign-metrics/supplier-campaign-metrics.js @@ -49,6 +49,7 @@ module.exports = { }, props: { recipientId: { + type: [Number, String], required: true }, from: { diff --git a/print/templates/reports/zone/zone.js b/print/templates/reports/zone/zone.js index 61c6cddfe..d611e1e53 100755 --- a/print/templates/reports/zone/zone.js +++ b/print/templates/reports/zone/zone.js @@ -13,6 +13,7 @@ module.exports = { }, props: { routeId: { + type: [Number, String], required: true } } diff --git a/storage/pdfs/invoice/.keep b/storage/pdfs/invoice/.keep deleted file mode 100644 index e69de29bb..000000000