From 18ac0a0b61f7680d9b8e3598caeb0d7cd455a6a0 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 16 Sep 2022 23:13:37 +0200 Subject: [PATCH 01/53] Export Email and Report classes --- loopback/server/boot/print.js | 4 +- .../back/methods/ticket/deliveryNote.js | 47 ++++++++++++++++ modules/ticket/back/models/ticket.js | 1 + .../report-footer/assets/css/import.js | 13 +++-- .../report-header/assets/css/import.js | 11 ++-- print/core/database.js | 39 +++++--------- print/core/stylesheet.js | 4 +- print/index.js | 53 +++++++++++++++++++ .../delivery-note/assets/css/import.js | 13 +++-- .../reports/delivery-note/delivery-note.js | 4 +- 10 files changed, 143 insertions(+), 46 deletions(-) create mode 100644 modules/ticket/back/methods/ticket/deliveryNote.js create mode 100644 print/index.js diff --git a/loopback/server/boot/print.js b/loopback/server/boot/print.js index 0f6af4d56..c2ef243b7 100644 --- a/loopback/server/boot/print.js +++ b/loopback/server/boot/print.js @@ -1,3 +1,3 @@ module.exports = function(app) { - require('../../../print/boot.js')(app); -}; + require('vn-print').boot(app); +}; \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/deliveryNote.js b/modules/ticket/back/methods/ticket/deliveryNote.js new file mode 100644 index 000000000..b4049b4c6 --- /dev/null +++ b/modules/ticket/back/methods/ticket/deliveryNote.js @@ -0,0 +1,47 @@ +const {Report, smtp} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethod('deliveryNote', { + description: '', + accepts: [ + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/delivery-note', + verb: 'GET' + } + }); + + Self.deliveryNote = async() => { + const params = {ticketId: 1}; + const rpt = new Report('delivery-note', params, { + module: 'ticket', + lang: 'es' + }); + + const stream = await rpt.render(); + + // await smtp.send({ + // from: 'joan@verdnatura.es', + // to: 'joan@verdnatura.es', + // subject: 'test123', + // body: rptTpl + // }); + + return [stream, 'text/html', `filename="test.pdf"`]; + }; +}; diff --git a/modules/ticket/back/models/ticket.js b/modules/ticket/back/models/ticket.js index 47d105824..85f7be12b 100644 --- a/modules/ticket/back/models/ticket.js +++ b/modules/ticket/back/models/ticket.js @@ -28,6 +28,7 @@ module.exports = Self => { require('../methods/ticket/freightCost')(Self); require('../methods/ticket/getComponentsSum')(Self); require('../methods/ticket/refund')(Self); + require('../methods/ticket/deliveryNote')(Self); Self.observe('before save', async function(ctx) { const loopBackContext = LoopBackContext.getCurrentContext(); diff --git a/print/core/components/report-footer/assets/css/import.js b/print/core/components/report-footer/assets/css/import.js index a2a9334cb..71fa00f4b 100644 --- a/print/core/components/report-footer/assets/css/import.js +++ b/print/core/components/report-footer/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, - `${appPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, + `${vnPrintPath}/common/css/misc.css`, `${__dirname}/style.css`]) - .mergeStyles(); + .mergeStyles(); \ No newline at end of file diff --git a/print/core/components/report-header/assets/css/import.js b/print/core/components/report-header/assets/css/import.js index a2a9334cb..e21d3821a 100644 --- a/print/core/components/report-header/assets/css/import.js +++ b/print/core/components/report-header/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, - `${appPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, + `${vnPrintPath}/common/css/misc.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/core/database.js b/print/core/database.js index 6c690afc6..f442cd4ed 100644 --- a/print/core/database.js +++ b/print/core/database.js @@ -1,16 +1,17 @@ const mysql = require('mysql2'); const config = require('./config.js'); const fs = require('fs-extra'); +const path = require('path'); const PoolConnection = mysql.PoolConnection; module.exports = { - init() { + init(pool) { if (!this.pool) { - const datasources = config.datasources; - const pool = mysql.createPoolCluster(); + // const datasources = config.datasources; + // const pool = mysql.createPoolCluster(); - for (let datasource of datasources) - pool.add(datasource.name, datasource.options); + // for (let datasource of datasources) + // pool.add(datasource.name, datasource.options); this.pool = pool; } @@ -43,29 +44,12 @@ module.exports = { * * @return {Object} - Result promise */ - rawSql(query, params, connection) { - let pool = this.pool; - if (params instanceof PoolConnection) - connection = params; - if (connection) pool = connection; - + rawSql(query, params) { return new Promise((resolve, reject) => { - if (!connection) { - pool.getConnection('default', function(error, conn) { - if (error) return reject(error); - - conn.query(query, params, (error, rows) => { - if (error) return reject(error); - conn.release(); - resolve(rows); - }); - }); - } else { - connection.query(query, params, (error, rows) => { - if (error) return reject(error); - resolve(rows); - }); - } + this.pool.query(query, params, (error, rows) => { + if (error) return reject(error); + resolve(rows); + }); }); }, @@ -102,6 +86,7 @@ module.exports = { * @return {Object} - Result promise */ findOneFromDef(queryName, params) { + console.log(path.resolve('queryName')); return this.rawSqlFromDef(queryName, params) .then(([row]) => row); }, diff --git a/print/core/stylesheet.js b/print/core/stylesheet.js index 42a44fb57..195044f02 100644 --- a/print/core/stylesheet.js +++ b/print/core/stylesheet.js @@ -1,4 +1,5 @@ const fs = require('fs-extra'); +const path = require('path'); class Stylesheet { constructor(files) { @@ -7,8 +8,9 @@ class Stylesheet { } mergeStyles() { - for (const file of this.files) + for (const file of this.files) { this.css.push(fs.readFileSync(file)); + } return this.css.join('\n'); } diff --git a/print/index.js b/print/index.js new file mode 100644 index 000000000..c25df6ae1 --- /dev/null +++ b/print/index.js @@ -0,0 +1,53 @@ +const express = require('express'); +const path = require('path'); +const fs = require('fs'); + +const templatesPath = path.resolve(__dirname, './templates'); +const componentsPath = path.resolve(__dirname, './core/components'); + +module.exports = { + async boot(app) { + // Init database instance + const conn = app.dataSources.vn.connector.client; + conn.query('SELECT 1', function(error, rows) { + if (error) return error; + console.log(rows); + }); + // console.log(app.dataSource.vn.connector.executeStmt('SELECT 1')); + require('./core/database').init(conn); + require('./core/smtp').init(); + require('./core/mixins'); + require('./core/filters'); + require('./core/directives'); + + const componentsDir = fs.readdirSync(componentsPath); + componentsDir.forEach(componentName => { + const componentDir = path.join(componentsPath, '/', componentName); + const assetsDir = `${componentDir}/assets`; + + app.use(`/api/${componentName}/assets`, express.static(assetsDir)); + }); + + /** + * Serve static files + */ + const templatesDir = fs.readdirSync(templatesPath); + templatesDir.forEach(directory => { + const templateTypeDir = path.join(templatesPath, '/', directory); + const templates = fs.readdirSync(templateTypeDir); + + templates.forEach(templateName => { + const templateDir = path.join(templatesPath, '/', directory, '/', templateName); + const assetsDir = `${templateDir}/assets`; + + app.use(`/api/${templateName}/assets`, express.static(assetsDir)); + }); + }); + + return true; + }, + smtp: require('./core/smtp'), + db: require('./core/database'), + Email: require('./core/email'), + Report: require('./core/report') +}; diff --git a/print/templates/reports/delivery-note/assets/css/import.js b/print/templates/reports/delivery-note/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/delivery-note/assets/css/import.js +++ b/print/templates/reports/delivery-note/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/delivery-note/delivery-note.js b/print/templates/reports/delivery-note/delivery-note.js index f9dba0578..a5ff69560 100755 --- a/print/templates/reports/delivery-note/delivery-note.js +++ b/print/templates/reports/delivery-note/delivery-note.js @@ -1,5 +1,5 @@ -const config = require(`${appPath}/core/config`); -const Component = require(`${appPath}/core/component`); +const config = require(`vn-print/core/config`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); const md5 = require('md5'); From 09bdee8b3449f9e13c4c9410d5133a42288fa4e0 Mon Sep 17 00:00:00 2001 From: joan Date: Mon, 19 Sep 2022 12:59:32 +0200 Subject: [PATCH 02/53] View & send PDF from loopback endpoint --- front/core/services/email.js | 4 +- front/core/services/report.js | 6 +- loopback/locale/en.json | 3 +- loopback/locale/es.json | 3 +- .../back/methods/ticket/deliveryNote.js | 47 -------------- .../back/methods/ticket/deliveryNoteEmail.js | 63 +++++++++++++++++++ .../back/methods/ticket/deliveryNotePdf.js | 61 ++++++++++++++++++ modules/ticket/back/models/ticket.js | 3 +- modules/ticket/front/descriptor-menu/index.js | 26 ++++---- print/core/component.js | 10 +-- .../email-footer/assets/css/import.js | 15 +++-- .../email-header/assets/css/import.js | 15 +++-- print/core/email.js | 3 +- .../email/delivery-note/assets/css/import.js | 15 +++-- .../email/delivery-note/delivery-note.js | 2 +- 15 files changed, 181 insertions(+), 95 deletions(-) delete mode 100644 modules/ticket/back/methods/ticket/deliveryNote.js create mode 100644 modules/ticket/back/methods/ticket/deliveryNoteEmail.js create mode 100644 modules/ticket/back/methods/ticket/deliveryNotePdf.js diff --git a/front/core/services/email.js b/front/core/services/email.js index 633b13a26..500b10f54 100644 --- a/front/core/services/email.js +++ b/front/core/services/email.js @@ -14,8 +14,8 @@ class Email { * @param {Object} params The email parameters * @return {Promise} Promise resolved when it's sent */ - send(template, params) { - return this.$http.get(`email/${template}`, {params}) + send(url, params) { + return this.$http.post(url, params) .then(() => this.vnApp.showMessage(this.$t('Notification sent!'))); } diff --git a/front/core/services/report.js b/front/core/services/report.js index c58a0ee0e..1b21a84d2 100644 --- a/front/core/services/report.js +++ b/front/core/services/report.js @@ -13,12 +13,12 @@ class Report { * @param {String} report The report name * @param {Object} params The report parameters */ - show(report, params) { + show(url, params) { params = Object.assign({ - authorization: this.vnToken.token + access_token: this.vnToken.token }, params); const serializedParams = this.$httpParamSerializer(params); - window.open(`api/report/${report}?${serializedParams}`); + window.open(`api/${url}?${serializedParams}`); } /** diff --git a/loopback/locale/en.json b/loopback/locale/en.json index ccf16cce0..58660b404 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -130,5 +130,6 @@ "Descanso diario 12h.": "Daily rest 12h.", "Fichadas impares": "Odd signs", "Descanso diario 9h.": "Daily rest 9h.", - "Descanso semanal 36h. / 72h.": "Weekly rest 36h. / 72h." + "Descanso semanal 36h. / 72h.": "Weekly rest 36h. / 72h.", + "deliveryNote": "deliveryNote-{{ticketId}}" } \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 07a00024a..01861490b 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -232,5 +232,6 @@ "Fichadas impares": "Fichadas impares", "Descanso diario 12h.": "Descanso diario 12h.", "Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.", - "Dirección incorrecta": "Dirección incorrecta" + "Dirección incorrecta": "Dirección incorrecta", + "deliveryNote": "albaran-{{ticketId}}" } \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/deliveryNote.js b/modules/ticket/back/methods/ticket/deliveryNote.js deleted file mode 100644 index b4049b4c6..000000000 --- a/modules/ticket/back/methods/ticket/deliveryNote.js +++ /dev/null @@ -1,47 +0,0 @@ -const {Report, smtp} = require('vn-print'); - -module.exports = Self => { - Self.remoteMethod('deliveryNote', { - description: '', - accepts: [ - ], - returns: [ - { - arg: 'body', - type: 'file', - root: true - }, { - arg: 'Content-Type', - type: 'String', - http: {target: 'header'} - }, { - arg: 'Content-Disposition', - type: 'String', - http: {target: 'header'} - } - ], - http: { - path: '/delivery-note', - verb: 'GET' - } - }); - - Self.deliveryNote = async() => { - const params = {ticketId: 1}; - const rpt = new Report('delivery-note', params, { - module: 'ticket', - lang: 'es' - }); - - const stream = await rpt.render(); - - // await smtp.send({ - // from: 'joan@verdnatura.es', - // to: 'joan@verdnatura.es', - // subject: 'test123', - // body: rptTpl - // }); - - return [stream, 'text/html', `filename="test.pdf"`]; - }; -}; diff --git a/modules/ticket/back/methods/ticket/deliveryNoteEmail.js b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js new file mode 100644 index 000000000..ecb4556a0 --- /dev/null +++ b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js @@ -0,0 +1,63 @@ +const {Report, Email, smtp} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('deliveryNoteEmail', { + description: '', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The ticket id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + }, + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/delivery-note-email', + verb: 'POST' + } + }); + + Self.deliveryNoteEmail = async(ctx, id) => { + const args = ctx.args; + + const params = { + ticketId: id, + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + if (args.recipientId) + params.recipientId = args.recipientId; + + if (args.replyTo) + params.replyTo = args.replyTo; + + const email = new Email('delivery-note', params); + await email.send(); + + return true; + }; +}; diff --git a/modules/ticket/back/methods/ticket/deliveryNotePdf.js b/modules/ticket/back/methods/ticket/deliveryNotePdf.js new file mode 100644 index 000000000..5b34a7265 --- /dev/null +++ b/modules/ticket/back/methods/ticket/deliveryNotePdf.js @@ -0,0 +1,61 @@ +const {Report, Email, smtp} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('deliveryNotePdf', { + description: '', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The ticket id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The client id', + required: false + }, + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/delivery-note-pdf', + verb: 'GET' + } + }); + + Self.deliveryNotePdf = async(ctx, id) => { + const args = ctx.args; + const $t = ctx.req.__; + + const params = { + ticketId: id, + lang: ctx.req.getLocale() + }; + + if (args.recipientId) + params.recipientId = args.recipientId; + + const report = new Report('delivery-note', params); + const stream = await report.toPdfStream(); + + const fileName = $t('deliveryNote', {ticketId: id}); + + return [stream, 'application/pdf', `filename="${fileName}.pdf"`]; + }; +}; diff --git a/modules/ticket/back/models/ticket.js b/modules/ticket/back/models/ticket.js index 85f7be12b..2ccdbb0bf 100644 --- a/modules/ticket/back/models/ticket.js +++ b/modules/ticket/back/models/ticket.js @@ -28,7 +28,8 @@ module.exports = Self => { require('../methods/ticket/freightCost')(Self); require('../methods/ticket/getComponentsSum')(Self); require('../methods/ticket/refund')(Self); - require('../methods/ticket/deliveryNote')(Self); + require('../methods/ticket/deliveryNotePdf')(Self); + require('../methods/ticket/deliveryNoteEmail')(Self); Self.observe('before save', async function(ctx) { const loopBackContext = LoopBackContext.getCurrentContext(); diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js index 379942cdd..05860cf88 100644 --- a/modules/ticket/front/descriptor-menu/index.js +++ b/modules/ticket/front/descriptor-menu/index.js @@ -116,14 +116,6 @@ class Controller extends Section { }); } - showPdfDeliveryNote(type) { - this.vnReport.show('delivery-note', { - recipientId: this.ticket.client.id, - ticketId: this.id, - type: type - }); - } - hasDocuware() { const params = { fileCabinet: 'deliveryClient', @@ -133,18 +125,24 @@ class Controller extends Section { .then(res => this.hasDocuwareFile = res.data); } - showCsvDeliveryNote() { - this.vnReport.showCsv('delivery-note', { + showPdfDeliveryNote(type) { + this.vnReport.show(`tickets/${this.id}/delivery-note-pdf`, { recipientId: this.ticket.client.id, - ticketId: this.id, + type: type }); } sendPdfDeliveryNote($data) { - return this.vnEmail.send('delivery-note', { + return this.vnEmail.send(`tickets/${this.id}/delivery-note-email`, { recipientId: this.ticket.client.id, - recipient: $data.email, - ticketId: this.id + recipient: $data.email + }); + } + + showCsvDeliveryNote() { + this.vnReport.showCsv('delivery-note', { + recipientId: this.ticket.client.id, + ticketId: this.id, }); } diff --git a/print/core/component.js b/print/core/component.js index 37656c240..06ef3033a 100644 --- a/print/core/component.js +++ b/print/core/component.js @@ -53,21 +53,21 @@ class Component { } async getUserLocale() { - let locale = this.args.auth.locale; + let lang = this.args.lang; // Fetches user locale from mixing method getLocale() if (this.args.recipientId) { const component = await this.component(); - locale = await component.getLocale(this.args.recipientId); + lang = await component.getLocale(this.args.recipientId); } const messages = this.locale.messages; - const userTranslations = messages[locale]; + const userTranslations = messages[lang]; if (!userTranslations) { - const fallbackLocale = config.i18n.fallbackLocale; + const fallbackLang = config.i18n.fallbackLocale; - return messages[fallbackLocale]; + return messages[fallbackLang]; } return userTranslations; diff --git a/print/core/components/email-footer/assets/css/import.js b/print/core/components/email-footer/assets/css/import.js index c742fdf90..4f6f631f7 100644 --- a/print/core/components/email-footer/assets/css/import.js +++ b/print/core/components/email-footer/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`, `${__dirname}/style.css`]) - .mergeStyles(); + .mergeStyles(); \ No newline at end of file diff --git a/print/core/components/email-header/assets/css/import.js b/print/core/components/email-header/assets/css/import.js index c742fdf90..4f6f631f7 100644 --- a/print/core/components/email-header/assets/css/import.js +++ b/print/core/components/email-header/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`, `${__dirname}/style.css`]) - .mergeStyles(); + .mergeStyles(); \ No newline at end of file diff --git a/print/core/email.js b/print/core/email.js index bc8345cab..353b70367 100644 --- a/print/core/email.js +++ b/print/core/email.js @@ -73,10 +73,9 @@ class Email extends Component { } const localeSubject = await this.getSubject(); - const replyTo = this.args.replyTo || this.args.auth.email; const mailOptions = { to: this.args.recipient, - replyTo: replyTo, + replyTo: this.args.replyTo || '', subject: localeSubject, html: rendered, attachments: attachments diff --git a/print/templates/email/delivery-note/assets/css/import.js b/print/templates/email/delivery-note/assets/css/import.js index b44d6bd37..89b2afaa5 100644 --- a/print/templates/email/delivery-note/assets/css/import.js +++ b/print/templates/email/delivery-note/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) - .mergeStyles(); + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) + .mergeStyles(); \ No newline at end of file diff --git a/print/templates/email/delivery-note/delivery-note.js b/print/templates/email/delivery-note/delivery-note.js index ffd2fe202..a6d1547de 100755 --- a/print/templates/email/delivery-note/delivery-note.js +++ b/print/templates/email/delivery-note/delivery-note.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); From 5a43bdb6c9ffea4b959f93f145ab5a01c31a6a14 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 21 Sep 2022 13:18:32 +0200 Subject: [PATCH 03/53] Delivery note --- .../back/methods/ticket/deliveryNoteEmail.js | 14 +++++++++++--- .../ticket/back/methods/ticket/deliveryNotePdf.js | 11 ++++++++++- .../reports/delivery-note/delivery-note.html | 4 ++-- .../reports/delivery-note/delivery-note.js | 11 +++++------ 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/modules/ticket/back/methods/ticket/deliveryNoteEmail.js b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js index ecb4556a0..1e7ef43b9 100644 --- a/modules/ticket/back/methods/ticket/deliveryNoteEmail.js +++ b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js @@ -29,6 +29,12 @@ module.exports = Self => { description: 'The recipient id to send to the recipient preferred language', required: false }, + { + arg: 'type', + type: 'string', + description: 'The delivery note type [ deliveryNote, proforma, withoutPrices ]', + required: false + }, ], returns: { type: ['object'], @@ -55,9 +61,11 @@ module.exports = Self => { if (args.replyTo) params.replyTo = args.replyTo; - const email = new Email('delivery-note', params); - await email.send(); + if (args.type) + params.type = args.type; - return true; + const email = new Email('delivery-note', params); + + return email.send(); }; }; diff --git a/modules/ticket/back/methods/ticket/deliveryNotePdf.js b/modules/ticket/back/methods/ticket/deliveryNotePdf.js index 5b34a7265..d1e288a98 100644 --- a/modules/ticket/back/methods/ticket/deliveryNotePdf.js +++ b/modules/ticket/back/methods/ticket/deliveryNotePdf.js @@ -2,7 +2,7 @@ const {Report, Email, smtp} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('deliveryNotePdf', { - description: '', + description: 'Returns the delivery note pdf', accepts: [ { arg: 'id', @@ -17,6 +17,12 @@ module.exports = Self => { description: 'The client id', required: false }, + { + arg: 'type', + type: 'string', + description: 'The delivery note type [ deliveryNote, proforma, withoutPrices ]', + required: false + }, ], returns: [ { @@ -51,6 +57,9 @@ module.exports = Self => { if (args.recipientId) params.recipientId = args.recipientId; + if (args.type) + params.type = args.type; + const report = new Report('delivery-note', params); const stream = await report.toPdfStream(); diff --git a/print/templates/reports/delivery-note/delivery-note.html b/print/templates/reports/delivery-note/delivery-note.html index 35f9a2960..d166f3307 100644 --- a/print/templates/reports/delivery-note/delivery-note.html +++ b/print/templates/reports/delivery-note/delivery-note.html @@ -15,7 +15,7 @@
-

{{$t(type)}}

+

{{$t(deliverNoteType)}}

@@ -23,7 +23,7 @@ - + diff --git a/print/templates/reports/delivery-note/delivery-note.js b/print/templates/reports/delivery-note/delivery-note.js index a5ff69560..e33b10765 100755 --- a/print/templates/reports/delivery-note/delivery-note.js +++ b/print/templates/reports/delivery-note/delivery-note.js @@ -7,10 +7,6 @@ const fs = require('fs-extra'); module.exports = { name: 'delivery-note', - created() { - if (!this.type) - this.type = 'deliveryNote'; - }, async serverPrefetch() { this.client = await this.fetchClient(this.ticketId); this.ticket = await this.fetchTicket(this.ticketId); @@ -41,6 +37,9 @@ module.exports = { return `data:image/png;base64, ${base64}`; }, + deliverNoteType() { + return this.type ? this.type : 'deliveryNote'; + }, serviceTotal() { let total = 0.00; this.services.forEach(service => { @@ -50,10 +49,10 @@ module.exports = { return total; }, showPrices() { - return this.type != 'withoutPrices'; + return this.deliverNoteType != 'withoutPrices'; }, footerType() { - const translatedType = this.$t(this.type); + const translatedType = this.$t(this.deliverNoteType); return `${translatedType} ${this.ticketId}`; } }, From 8105c12a18605aa329bd58e76b30c9938c240a68 Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 22 Sep 2022 08:48:29 +0200 Subject: [PATCH 04/53] Campaign metrics --- db/changes/10490-august/00-ACL.sql | 6 ++ front/core/services/email.js | 4 +- front/core/services/report.js | 4 +- loopback/locale/es.json | 3 +- .../methods/client/campaignMetricsEmail.js | 68 +++++++++++++++++++ .../back/methods/client/campaignMetricsPdf.js | 65 ++++++++++++++++++ modules/client/back/models/client.js | 2 + modules/client/front/consumption/index.js | 6 +- .../back/methods/ticket/deliveryNoteEmail.js | 19 ++---- .../back/methods/ticket/deliveryNotePdf.js | 21 ++---- .../campaign-metrics/assets/css/import.js | 15 ++-- .../campaign-metrics/campaign-metrics.js | 4 +- .../email/delivery-note/delivery-note.html | 2 +- .../email/delivery-note/delivery-note.js | 2 +- .../campaign-metrics/assets/css/import.js | 13 ++-- .../campaign-metrics/campaign-metrics.js | 16 ++--- .../reports/delivery-note/delivery-note.js | 52 +++++++------- 17 files changed, 217 insertions(+), 85 deletions(-) create mode 100644 db/changes/10490-august/00-ACL.sql create mode 100644 modules/client/back/methods/client/campaignMetricsEmail.js create mode 100644 modules/client/back/methods/client/campaignMetricsPdf.js diff --git a/db/changes/10490-august/00-ACL.sql b/db/changes/10490-august/00-ACL.sql new file mode 100644 index 000000000..f7d984e37 --- /dev/null +++ b/db/changes/10490-august/00-ACL.sql @@ -0,0 +1,6 @@ +INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) + VALUES + ('Ticket', 'deliveryNotePdf', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Ticket', 'deliveryNoteEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'campaignMetricsPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'campaignMetricsEmail', 'READ', 'ALLOW', 'ROLE', 'employee'); \ No newline at end of file diff --git a/front/core/services/email.js b/front/core/services/email.js index 500b10f54..b39627573 100644 --- a/front/core/services/email.js +++ b/front/core/services/email.js @@ -14,8 +14,8 @@ class Email { * @param {Object} params The email parameters * @return {Promise} Promise resolved when it's sent */ - send(url, params) { - return this.$http.post(url, params) + send(path, params) { + return this.$http.post(path, params) .then(() => this.vnApp.showMessage(this.$t('Notification sent!'))); } diff --git a/front/core/services/report.js b/front/core/services/report.js index 1b21a84d2..d28959d47 100644 --- a/front/core/services/report.js +++ b/front/core/services/report.js @@ -13,12 +13,12 @@ class Report { * @param {String} report The report name * @param {Object} params The report parameters */ - show(url, params) { + show(path, params) { params = Object.assign({ access_token: this.vnToken.token }, params); const serializedParams = this.$httpParamSerializer(params); - window.open(`api/${url}?${serializedParams}`); + window.open(`api/${path}?${serializedParams}`); } /** diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 01861490b..07a00024a 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -232,6 +232,5 @@ "Fichadas impares": "Fichadas impares", "Descanso diario 12h.": "Descanso diario 12h.", "Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.", - "Dirección incorrecta": "Dirección incorrecta", - "deliveryNote": "albaran-{{ticketId}}" + "Dirección incorrecta": "Dirección incorrecta" } \ No newline at end of file diff --git a/modules/client/back/methods/client/campaignMetricsEmail.js b/modules/client/back/methods/client/campaignMetricsEmail.js new file mode 100644 index 000000000..6bbff0a6c --- /dev/null +++ b/modules/client/back/methods/client/campaignMetricsEmail.js @@ -0,0 +1,68 @@ +const {Report, Email, smtp} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('campaignMetricsEmail', { + description: 'Sends the campaign metrics email with an attached PDF', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + }, + { + arg: 'from', + type: 'string', + required: true + }, + { + arg: 'to', + type: 'string', + required: true + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/campaign-metrics-email', + verb: 'POST' + } + }); + + Self.campaignMetricsEmail = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('campaign-metrics', params); + + return email.send(); + }; +}; diff --git a/modules/client/back/methods/client/campaignMetricsPdf.js b/modules/client/back/methods/client/campaignMetricsPdf.js new file mode 100644 index 000000000..994fce254 --- /dev/null +++ b/modules/client/back/methods/client/campaignMetricsPdf.js @@ -0,0 +1,65 @@ +const { Report } = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('campaignMetricsPdf', { + description: 'Returns the delivery note pdf', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + }, + { + arg: 'from', + type: 'string', + required: true + }, + { + arg: 'to', + type: 'string', + required: true + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/campaign-metrics-pdf', + verb: 'GET' + } + }); + + Self.campaignMetricsPdf = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('campaign-metrics', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 746261626..84997e204 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -34,6 +34,8 @@ module.exports = Self => { require('../methods/client/updatePortfolio')(Self); require('../methods/client/updateUser')(Self); require('../methods/client/uploadFile')(Self); + require('../methods/client/campaignMetricsPdf')(Self); + require('../methods/client/campaignMetricsEmail')(Self); // Validations diff --git a/modules/client/front/consumption/index.js b/modules/client/front/consumption/index.js index 7017fed41..d9b657318 100644 --- a/modules/client/front/consumption/index.js +++ b/modules/client/front/consumption/index.js @@ -45,11 +45,13 @@ class Controller extends Section { } showReport() { - this.vnReport.show('campaign-metrics', this.reportParams); + const path = `Clients/${this.client.id}/campaign-metrics-pdf`; + this.vnReport.show(path, this.reportParams); } sendEmail() { - this.vnEmail.send('campaign-metrics', this.reportParams); + const path = `Clients/${this.client.id}/campaign-metrics-email`; + this.vnEmail.send(path, this.reportParams); } changeGrouped(value) { diff --git a/modules/ticket/back/methods/ticket/deliveryNoteEmail.js b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js index 1e7ef43b9..5926fba58 100644 --- a/modules/ticket/back/methods/ticket/deliveryNoteEmail.js +++ b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js @@ -1,8 +1,8 @@ -const {Report, Email, smtp} = require('vn-print'); +const { Email } = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('deliveryNoteEmail', { - description: '', + description: 'Sends the delivery note email with an attached PDF', accepts: [ { arg: 'id', @@ -47,22 +47,15 @@ module.exports = Self => { }); Self.deliveryNoteEmail = async(ctx, id) => { - const args = ctx.args; - + const args = Object.assign({}, ctx.args); const params = { - ticketId: id, recipient: args.recipient, lang: ctx.req.getLocale() }; - if (args.recipientId) - params.recipientId = args.recipientId; - - if (args.replyTo) - params.replyTo = args.replyTo; - - if (args.type) - params.type = args.type; + delete args.ctx; + for (const param in args) + params[param] = args[param]; const email = new Email('delivery-note', params); diff --git a/modules/ticket/back/methods/ticket/deliveryNotePdf.js b/modules/ticket/back/methods/ticket/deliveryNotePdf.js index d1e288a98..373d96d1f 100644 --- a/modules/ticket/back/methods/ticket/deliveryNotePdf.js +++ b/modules/ticket/back/methods/ticket/deliveryNotePdf.js @@ -46,25 +46,16 @@ module.exports = Self => { }); Self.deliveryNotePdf = async(ctx, id) => { - const args = ctx.args; - const $t = ctx.req.__; + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; - const params = { - ticketId: id, - lang: ctx.req.getLocale() - }; - - if (args.recipientId) - params.recipientId = args.recipientId; - - if (args.type) - params.type = args.type; + delete args.ctx; + for (const param in args) + params[param] = args[param]; const report = new Report('delivery-note', params); const stream = await report.toPdfStream(); - const fileName = $t('deliveryNote', {ticketId: id}); - - return [stream, 'application/pdf', `filename="${fileName}.pdf"`]; + return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; }; }; diff --git a/print/templates/email/campaign-metrics/assets/css/import.js b/print/templates/email/campaign-metrics/assets/css/import.js index b44d6bd37..89b2afaa5 100644 --- a/print/templates/email/campaign-metrics/assets/css/import.js +++ b/print/templates/email/campaign-metrics/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) - .mergeStyles(); + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) + .mergeStyles(); \ No newline at end of file diff --git a/print/templates/email/campaign-metrics/campaign-metrics.js b/print/templates/email/campaign-metrics/campaign-metrics.js index 2bd93b725..0c3a01991 100755 --- a/print/templates/email/campaign-metrics/campaign-metrics.js +++ b/print/templates/email/campaign-metrics/campaign-metrics.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); @@ -20,7 +20,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true }, diff --git a/print/templates/email/delivery-note/delivery-note.html b/print/templates/email/delivery-note/delivery-note.html index 96c53b1d7..eaa154336 100644 --- a/print/templates/email/delivery-note/delivery-note.html +++ b/print/templates/email/delivery-note/delivery-note.html @@ -25,7 +25,7 @@

{{ $t('title') }}

{{$t('dear')}},

-

+

diff --git a/print/templates/email/delivery-note/delivery-note.js b/print/templates/email/delivery-note/delivery-note.js index a6d1547de..ba3d44001 100755 --- a/print/templates/email/delivery-note/delivery-note.js +++ b/print/templates/email/delivery-note/delivery-note.js @@ -9,7 +9,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - ticketId: { + id: { type: [Number, String], required: true } diff --git a/print/templates/reports/campaign-metrics/assets/css/import.js b/print/templates/reports/campaign-metrics/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/campaign-metrics/assets/css/import.js +++ b/print/templates/reports/campaign-metrics/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/campaign-metrics/campaign-metrics.js b/print/templates/reports/campaign-metrics/campaign-metrics.js index 6669ce067..da7cdd9ae 100755 --- a/print/templates/reports/campaign-metrics/campaign-metrics.js +++ b/print/templates/reports/campaign-metrics/campaign-metrics.js @@ -1,22 +1,22 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); module.exports = { name: 'campaign-metrics', async serverPrefetch() { - this.client = await this.fetchClient(this.recipientId); - this.sales = await this.fetchSales(this.recipientId, this.from, this.to); + this.client = await this.fetchClient(this.id); + this.sales = await this.fetchSales(this.id, this.from, this.to); if (!this.client) throw new Error('Something went wrong'); }, methods: { - fetchClient(clientId) { - return this.findOneFromDef('client', [clientId]); + fetchClient(id) { + return this.findOneFromDef('client', [id]); }, - fetchSales(clientId, from, to) { - return this.rawSqlFromDef('sales', [clientId, from, to]); + fetchSales(id, from, to) { + return this.rawSqlFromDef('sales', [id, from, to]); }, }, components: { @@ -24,7 +24,7 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true }, diff --git a/print/templates/reports/delivery-note/delivery-note.js b/print/templates/reports/delivery-note/delivery-note.js index e33b10765..d92329ac8 100755 --- a/print/templates/reports/delivery-note/delivery-note.js +++ b/print/templates/reports/delivery-note/delivery-note.js @@ -8,14 +8,14 @@ const fs = require('fs-extra'); module.exports = { name: 'delivery-note', async serverPrefetch() { - this.client = await this.fetchClient(this.ticketId); - this.ticket = await this.fetchTicket(this.ticketId); - this.sales = await this.fetchSales(this.ticketId); - this.address = await this.fetchAddress(this.ticketId); - this.services = await this.fetchServices(this.ticketId); - this.taxes = await this.fetchTaxes(this.ticketId); - this.packagings = await this.fetchPackagings(this.ticketId); - this.signature = await this.fetchSignature(this.ticketId); + this.client = await this.fetchClient(this.id); + this.ticket = await this.fetchTicket(this.id); + this.sales = await this.fetchSales(this.id); + this.address = await this.fetchAddress(this.id); + this.services = await this.fetchServices(this.id); + this.taxes = await this.fetchTaxes(this.id); + this.packagings = await this.fetchPackagings(this.id); + this.signature = await this.fetchSignature(this.id); if (!this.ticket) throw new Error('Something went wrong'); @@ -53,33 +53,33 @@ module.exports = { }, footerType() { const translatedType = this.$t(this.deliverNoteType); - return `${translatedType} ${this.ticketId}`; + return `${translatedType} ${this.id}`; } }, methods: { - fetchClient(ticketId) { - return this.findOneFromDef('client', [ticketId]); + fetchClient(id) { + return this.findOneFromDef('client', [id]); }, - fetchTicket(ticketId) { - return this.findOneFromDef('ticket', [ticketId]); + fetchTicket(id) { + return this.findOneFromDef('ticket', [id]); }, - fetchAddress(ticketId) { - return this.findOneFromDef(`address`, [ticketId]); + fetchAddress(id) { + return this.findOneFromDef(`address`, [id]); }, - fetchSignature(ticketId) { - return this.findOneFromDef('signature', [ticketId]); + fetchSignature(id) { + return this.findOneFromDef('signature', [id]); }, - fetchTaxes(ticketId) { - return this.findOneFromDef(`taxes`, [ticketId]); + fetchTaxes(id) { + return this.findOneFromDef(`taxes`, [id]); }, - fetchSales(ticketId) { - return this.rawSqlFromDef('sales', [ticketId]); + fetchSales(id) { + return this.rawSqlFromDef('sales', [id]); }, - fetchPackagings(ticketId) { - return this.rawSqlFromDef('packagings', [ticketId]); + fetchPackagings(id) { + return this.rawSqlFromDef('packagings', [id]); }, - fetchServices(ticketId) { - return this.rawSqlFromDef('services', [ticketId]); + fetchServices(id) { + return this.rawSqlFromDef('services', [id]); }, getSubTotal() { @@ -126,7 +126,7 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - ticketId: { + id: { type: [Number, String], required: true }, From 68f35444773ed17b82e8b3f7601eda5a4a6d144f Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 22 Sep 2022 09:17:14 +0200 Subject: [PATCH 05/53] Claim pickup order --- db/dump/fixtures.sql | 5 ++ .../back/methods/claim/claimPickupEmail.js | 58 +++++++++++++++++++ .../back/methods/claim/claimPickupPdf.js | 55 ++++++++++++++++++ modules/claim/back/models/claim.js | 2 + modules/claim/front/descriptor/index.html | 4 ++ modules/claim/front/descriptor/index.js | 10 ++-- .../back/methods/client/campaignMetricsPdf.js | 2 +- .../claim-pickup-order/assets/css/import.js | 15 +++-- .../claim-pickup-order/claim-pickup-order.js | 4 +- .../claim-pickup-order/assets/css/import.js | 13 +++-- .../claim-pickup-order/claim-pickup-order.js | 16 ++--- 11 files changed, 156 insertions(+), 28 deletions(-) create mode 100644 modules/claim/back/methods/claim/claimPickupEmail.js create mode 100644 modules/claim/back/methods/claim/claimPickupPdf.js diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index e6c7cb3d3..7835b32c4 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1783,6 +1783,11 @@ INSERT INTO `vn`.`claimEnd`(`id`, `saleFk`, `claimFk`, `workerFk`, `claimDestina (1, 31, 4, 21, 2), (2, 32, 3, 21, 3); +INSERT INTO `vn`.`claimConfig`(`id`, `pickupContact`, `maxResponsibility`) + VALUES + (1, 'Contact description', 50), + (2, 'Contact description', 30); + INSERT INTO `hedera`.`tpvMerchant`(`id`, `description`, `companyFk`, `bankFk`, `secretKey`) VALUES (1, 'Arkham Bank', 442, 1, 'h12387193H10238'), diff --git a/modules/claim/back/methods/claim/claimPickupEmail.js b/modules/claim/back/methods/claim/claimPickupEmail.js new file mode 100644 index 000000000..b946353d6 --- /dev/null +++ b/modules/claim/back/methods/claim/claimPickupEmail.js @@ -0,0 +1,58 @@ +const {Report, Email, smtp} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('claimPickupEmail', { + description: 'Sends the the claim pickup order email with an attached PDF', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/claim-pickup-email', + verb: 'POST' + } + }); + + Self.claimPickupEmail = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('claim-pickup-order', params); + + return email.send(); + }; +}; diff --git a/modules/claim/back/methods/claim/claimPickupPdf.js b/modules/claim/back/methods/claim/claimPickupPdf.js new file mode 100644 index 000000000..0e3abe908 --- /dev/null +++ b/modules/claim/back/methods/claim/claimPickupPdf.js @@ -0,0 +1,55 @@ +const { Report } = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('claimPickupPdf', { + description: 'Returns the claim pickup order pdf', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The claim id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/claim-pickup-pdf', + verb: 'GET' + } + }); + + Self.claimPickupPdf = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('claim-pickup-order', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; + }; +}; diff --git a/modules/claim/back/models/claim.js b/modules/claim/back/models/claim.js index e6dc50073..c9d7ee7d4 100644 --- a/modules/claim/back/models/claim.js +++ b/modules/claim/back/models/claim.js @@ -9,4 +9,6 @@ module.exports = Self => { require('../methods/claim/isEditable')(Self); require('../methods/claim/updateClaimDestination')(Self); require('../methods/claim/downloadFile')(Self); + require('../methods/claim/claimPickupPdf')(Self); + require('../methods/claim/claimPickupEmail')(Self); }; diff --git a/modules/claim/front/descriptor/index.html b/modules/claim/front/descriptor/index.html index 56fd0bb35..96d0882e6 100644 --- a/modules/claim/front/descriptor/index.html +++ b/modules/claim/front/descriptor/index.html @@ -5,11 +5,15 @@ Show Pickup order Send Pickup order diff --git a/modules/claim/front/descriptor/index.js b/modules/claim/front/descriptor/index.js index 674ac91e1..0dddadbe1 100644 --- a/modules/claim/front/descriptor/index.js +++ b/modules/claim/front/descriptor/index.js @@ -11,17 +11,15 @@ class Controller extends Descriptor { } showPickupOrder() { - this.vnReport.show('claim-pickup-order', { - recipientId: this.claim.clientFk, - claimId: this.claim.id + this.vnReport.show(`Claims/${this.claim.id}/claim-pickup-pdf`, { + recipientId: this.claim.clientFk }); } sendPickupOrder() { - return this.vnEmail.send('claim-pickup-order', { + return this.vnEmail.send(`Claims/${this.claim.id}/claim-pickup-email`, { recipient: this.claim.client.email, - recipientId: this.claim.clientFk, - claimId: this.claim.id + recipientId: this.claim.clientFk }); } diff --git a/modules/client/back/methods/client/campaignMetricsPdf.js b/modules/client/back/methods/client/campaignMetricsPdf.js index 994fce254..6d0a803a5 100644 --- a/modules/client/back/methods/client/campaignMetricsPdf.js +++ b/modules/client/back/methods/client/campaignMetricsPdf.js @@ -2,7 +2,7 @@ const { Report } = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('campaignMetricsPdf', { - description: 'Returns the delivery note pdf', + description: 'Returns the campaign metrics note pdf', accepts: [ { arg: 'id', diff --git a/print/templates/email/claim-pickup-order/assets/css/import.js b/print/templates/email/claim-pickup-order/assets/css/import.js index b44d6bd37..89b2afaa5 100644 --- a/print/templates/email/claim-pickup-order/assets/css/import.js +++ b/print/templates/email/claim-pickup-order/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) - .mergeStyles(); + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) + .mergeStyles(); \ No newline at end of file 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 cf4ba7d12..d3836db39 100755 --- a/print/templates/email/claim-pickup-order/claim-pickup-order.js +++ b/print/templates/email/claim-pickup-order/claim-pickup-order.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); @@ -9,7 +9,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - claimId: { + id: { type: [Number, String], required: true } diff --git a/print/templates/reports/claim-pickup-order/assets/css/import.js b/print/templates/reports/claim-pickup-order/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/claim-pickup-order/assets/css/import.js +++ b/print/templates/reports/claim-pickup-order/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); 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 bf975e9f2..de56c2079 100755 --- a/print/templates/reports/claim-pickup-order/claim-pickup-order.js +++ b/print/templates/reports/claim-pickup-order/claim-pickup-order.js @@ -1,12 +1,12 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); module.exports = { name: 'claim-pickup-order', async serverPrefetch() { - this.client = await this.fetchClient(this.claimId); - this.sales = await this.fetchSales(this.claimId); + this.client = await this.fetchClient(this.id); + this.sales = await this.fetchSales(this.id); this.claimConfig = await this.fetchClaimConfig(); if (!this.client) @@ -20,11 +20,11 @@ module.exports = { } }, methods: { - fetchClient(claimId) { - return this.findOneFromDef('client', [claimId]); + fetchClient(id) { + return this.findOneFromDef('client', [id]); }, - fetchSales(claimId) { - return this.rawSqlFromDef('sales', [claimId]); + fetchSales(id) { + return this.rawSqlFromDef('sales', [id]); }, fetchClaimConfig() { return this.findOneFromDef('claimConfig'); @@ -35,7 +35,7 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - claimId: { + id: { type: [Number, String], required: true } From 92a476bd056e5bae015b00fbd6b738d200933994 Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 22 Sep 2022 09:42:04 +0200 Subject: [PATCH 06/53] credit request --- .../assets/css/import.js | 15 +++++++----- .../client-debt-statement.js | 4 ++-- .../email/credit-request/assets/css/import.js | 15 +++++++----- .../email/credit-request/credit-request.js | 2 +- .../assets/css/import.js | 13 ++++++---- .../client-debt-statement.js | 24 +++++++++---------- .../credit-request/assets/css/import.js | 13 ++++++---- .../reports/credit-request/credit-request.js | 2 +- 8 files changed, 50 insertions(+), 38 deletions(-) diff --git a/print/templates/email/client-debt-statement/assets/css/import.js b/print/templates/email/client-debt-statement/assets/css/import.js index b44d6bd37..89b2afaa5 100644 --- a/print/templates/email/client-debt-statement/assets/css/import.js +++ b/print/templates/email/client-debt-statement/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) - .mergeStyles(); + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) + .mergeStyles(); \ No newline at end of file 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 f32f9e239..4d5499960 100755 --- a/print/templates/email/client-debt-statement/client-debt-statement.js +++ b/print/templates/email/client-debt-statement/client-debt-statement.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); @@ -15,7 +15,7 @@ module.exports = { return {attachments}; }, props: { - recipientId: { + id: { type: [Number, String], required: true }, diff --git a/print/templates/email/credit-request/assets/css/import.js b/print/templates/email/credit-request/assets/css/import.js index b44d6bd37..89b2afaa5 100644 --- a/print/templates/email/credit-request/assets/css/import.js +++ b/print/templates/email/credit-request/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) - .mergeStyles(); + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) + .mergeStyles(); \ No newline at end of file diff --git a/print/templates/email/credit-request/credit-request.js b/print/templates/email/credit-request/credit-request.js index 69463f43a..79c33ba0c 100755 --- a/print/templates/email/credit-request/credit-request.js +++ b/print/templates/email/credit-request/credit-request.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); diff --git a/print/templates/reports/client-debt-statement/assets/css/import.js b/print/templates/reports/client-debt-statement/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/client-debt-statement/assets/css/import.js +++ b/print/templates/reports/client-debt-statement/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); 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 f006b0a92..dd8a30ff9 100755 --- a/print/templates/reports/client-debt-statement/client-debt-statement.js +++ b/print/templates/reports/client-debt-statement/client-debt-statement.js @@ -1,12 +1,12 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); module.exports = { name: 'client-debt-statement', async serverPrefetch() { - this.client = await this.fetchClient(this.recipientId); - this.sales = await this.fetchSales(this.recipientId, this.from); + this.client = await this.fetchClient(this.id); + this.sales = await this.fetchSales(this.id, this.from); if (!this.client) throw new Error('Something went wrong'); @@ -22,21 +22,21 @@ module.exports = { return {totalBalance: 0.00}; }, methods: { - fetchClient(clientId) { - return this.findOneFromDef('client', [clientId]); + fetchClient(id) { + return this.findOneFromDef('client', [id]); }, - fetchSales(clientId, from) { + fetchSales(id, from) { return this.rawSqlFromDef('sales', [ from, - clientId, + id, from, - clientId, + id, from, - clientId, + id, from, - clientId, + id, from, - clientId + id ]); }, getBalance(sale) { @@ -68,7 +68,7 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true }, diff --git a/print/templates/reports/credit-request/assets/css/import.js b/print/templates/reports/credit-request/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/credit-request/assets/css/import.js +++ b/print/templates/reports/credit-request/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/credit-request/credit-request.js b/print/templates/reports/credit-request/credit-request.js index d04106493..7de1060ca 100755 --- a/print/templates/reports/credit-request/credit-request.js +++ b/print/templates/reports/credit-request/credit-request.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); From 664fd444cc33420756e0f2d729bf09f9fc9da67b Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 22 Sep 2022 15:44:35 +0200 Subject: [PATCH 07/53] Sample refactor --- db/changes/10490-august/00-sample.sql | 17 +++ modules/client/back/models/sample.json | 6 + modules/client/front/sample/create/index.html | 3 +- modules/client/front/sample/create/index.js | 105 +++++++++++------- 4 files changed, 92 insertions(+), 39 deletions(-) create mode 100644 db/changes/10490-august/00-sample.sql diff --git a/db/changes/10490-august/00-sample.sql b/db/changes/10490-august/00-sample.sql new file mode 100644 index 000000000..e70d1fd13 --- /dev/null +++ b/db/changes/10490-august/00-sample.sql @@ -0,0 +1,17 @@ +alter table `vn`.`sample` + add model VARCHAR(25) null comment 'Model name in plural'; + +alter table `vn`.`sample` + add property VARCHAR(25) null comment 'Remote method property name'; + + +UPDATE vn.sample t + SET t.model = 'Clients', + t.property = 'printerSetup' + WHERE t.id = 13; + +UPDATE vn.sample t +SET t.model = 'Clients', + t.property = 'clientWelcome' +WHERE t.id = 12; + diff --git a/modules/client/back/models/sample.json b/modules/client/back/models/sample.json index cfb127ab2..fcb33a593 100644 --- a/modules/client/back/models/sample.json +++ b/modules/client/back/models/sample.json @@ -29,6 +29,12 @@ }, "datepickerEnabled": { "type": "boolean" + }, + "model": { + "type": "string" + }, + "property": { + "type": "string" } }, "scopes": { diff --git a/modules/client/front/sample/create/index.html b/modules/client/front/sample/create/index.html index 2d0f3d29c..ac6cc312e 100644 --- a/modules/client/front/sample/create/index.html +++ b/modules/client/front/sample/create/index.html @@ -31,6 +31,7 @@ ng-model="$ctrl.clientSample.typeFk" model="ClientSample.typeFk" data="samplesVisible" + fields="['id', 'description', 'model']" show-field="description" label="Sample" required="true"> @@ -77,7 +78,7 @@ + ng-click="$ctrl.preview()"> { - this.$.showPreview.show(); - const dialog = document.body.querySelector('div.vn-dialog'); - const body = dialog.querySelector('tpl-body'); - const scroll = dialog.querySelector('div:first-child'); + // showPreview() { + // this.send(true, res => { + // this.$.showPreview.show(); + // const dialog = document.body.querySelector('div.vn-dialog'); + // const body = dialog.querySelector('tpl-body'); + // const scroll = dialog.querySelector('div:first-child'); - body.innerHTML = res.data; - scroll.scrollTop = 0; - }); - } + // body.innerHTML = res.data; + // scroll.scrollTop = 0; + // }); + // } - sendSample() { - this.send(false, () => { - this.vnApp.showSuccess(this.$t('Notification sent!')); - this.$state.go('client.card.sample.index'); - }); - } + // sendSample() { + // this.send(false, () => { + // this.vnApp.showSuccess(this.$t('Notification sent!')); + // this.$state.go('client.card.sample.index'); + // }); + // } - send(isPreview, cb) { + // send(isPreview, cb) { + // const sampleType = this.$.sampleType.selection; + // const params = { + // recipientId: this.$params.id, + // recipient: this.clientSample.recipient, + // replyTo: this.clientSample.replyTo + // }; + + // if (!params.recipient) + // return this.vnApp.showError(this.$t('Email cannot be blank')); + + // if (!sampleType) + // return this.vnApp.showError(this.$t('Choose a sample')); + + // if (sampleType.hasCompany && !this.clientSample.companyFk) + // return this.vnApp.showError(this.$t('Choose a company')); + + // if (sampleType.hasCompany) + // params.companyId = this.clientSample.companyFk; + + // if (sampleType.datepickerEnabled && !this.clientSample.from) + // return this.vnApp.showError(this.$t('Choose a date')); + + // if (sampleType.datepickerEnabled) + // params.from = this.clientSample.from; + + // let query = `email/${sampleType.code}`; + // if (isPreview) + // query = `email/${sampleType.code}/preview`; + + // this.$http.get(query, {params}).then(cb); + // } + + preview() { const sampleType = this.$.sampleType.selection; + const params = { recipientId: this.$params.id, recipient: this.clientSample.recipient, replyTo: this.clientSample.replyTo }; - if (!params.recipient) - return this.vnApp.showError(this.$t('Email cannot be blank')); + const path = `${sampleType.model}/${this.$params.id}/${sampleType.property}Html`; + this.$http.get(path, {params}) + .then(response => { + this.$.showPreview.show(); + const dialog = document.body.querySelector('div.vn-dialog'); + const body = dialog.querySelector('tpl-body'); + const scroll = dialog.querySelector('div:first-child'); - if (!sampleType) - return this.vnApp.showError(this.$t('Choose a sample')); + body.innerHTML = response.data; + scroll.scrollTop = 0; + }); + } - if (sampleType.hasCompany && !this.clientSample.companyFk) - return this.vnApp.showError(this.$t('Choose a company')); - - if (sampleType.hasCompany) - params.companyId = this.clientSample.companyFk; - - if (sampleType.datepickerEnabled && !this.clientSample.from) - return this.vnApp.showError(this.$t('Choose a date')); - - if (sampleType.datepickerEnabled) - params.from = this.clientSample.from; - - let query = `email/${sampleType.code}`; - if (isPreview) - query = `email/${sampleType.code}/preview`; - - this.$http.get(query, {params}).then(cb); + send() { + this.vnEmail.send(`tickets/${this.id}/credit-request-email`, { + recipientId: this.ticket.client.id, + recipient: $data.email + }); } getWorkerEmail() { From 85698410db8b42c0dac82ef80f2b1d9b0fa59511 Mon Sep 17 00:00:00 2001 From: joan Date: Mon, 26 Sep 2022 08:07:45 +0200 Subject: [PATCH 08/53] Templates refactor --- db/changes/10490-august/00-ACL.sql | 13 +++- db/changes/10490-august/00-sample.sql | 31 ++++++--- .../methods/client/campaignMetricsEmail.js | 4 +- .../back/methods/client/campaignMetricsPdf.js | 6 +- .../client/clientDebtStatementEmail.js | 63 ++++++++++++++++++ .../methods/client/clientDebtStatementHtml.js | 62 ++++++++++++++++++ .../back/methods/client/clientWelcomeEmail.js | 58 +++++++++++++++++ .../back/methods/client/clientWelcomeHtml.js | 57 +++++++++++++++++ .../back/methods/client/creditRequestEmail.js | 58 +++++++++++++++++ .../back/methods/client/creditRequestHtml.js | 57 +++++++++++++++++ .../methods/client/letterDebtorNdEmail.js | 64 +++++++++++++++++++ .../back/methods/client/letterDebtorNdHtml.js | 63 ++++++++++++++++++ .../methods/client/letterDebtorStEmail.js | 64 +++++++++++++++++++ .../back/methods/client/letterDebtorStHtml.js | 63 ++++++++++++++++++ .../back/methods/client/printerSetupEmail.js | 58 +++++++++++++++++ .../back/methods/client/printerSetupHtml.js | 57 +++++++++++++++++ .../back/methods/client/sepaCoreEmail.js | 64 +++++++++++++++++++ modules/client/back/models/client-methods.js | 43 +++++++++++++ modules/client/back/models/client.js | 29 +-------- modules/client/front/sample/create/index.html | 10 ++- modules/client/front/sample/create/index.js | 55 ++++++++++++---- modules/item/front/index/style.scss | 8 --- .../back/methods/route/driverRouteEmail.js | 58 +++++++++++++++++ .../back/methods/route/driverRoutePdf.js | 55 ++++++++++++++++ modules/route/back/models/route.js | 2 + .../route/front/agency-term/index/index.js | 1 - .../route/front/agency-term/index/style.scss | 32 ---------- modules/route/front/descriptor/index.js | 8 +-- .../back/methods/ticket/deliveryNoteEmail.js | 4 +- .../back/methods/ticket/deliveryNotePdf.js | 4 +- .../attachment/assets/css/import.js | 13 ++-- .../claim-pickup-order/assets/css/import.js | 3 +- .../assets/css/import.js | 2 +- .../email/client-welcome/assets/css/import.js | 13 ++-- .../email/client-welcome/client-welcome.js | 10 +-- .../delivery-note-link/assets/css/import.js | 13 ++-- .../delivery-note-link/delivery-note-link.js | 4 +- .../email/delivery-note/assets/css/import.js | 2 +- .../email/driver-route/assets/css/import.js | 13 ++-- .../email/driver-route/driver-route.js | 4 +- .../assets/css/import.js | 13 ++-- .../incoterms-authorization.js | 4 +- .../letter-debtor-nd/assets/css/import.js | 13 ++-- .../letter-debtor-nd/letter-debtor-nd.js | 13 ++-- .../email/letter-debtor-nd/sql/client.sql | 3 +- .../letter-debtor-st/assets/css/import.js | 13 ++-- .../letter-debtor-st/letter-debtor-st.js | 10 +-- .../email/letter-debtor-st/sql/client.sql | 3 +- .../email/printer-setup/assets/css/import.js | 13 ++-- .../email/printer-setup/printer-setup.js | 10 +-- .../email/sepa-core/assets/css/import.js | 14 ++-- print/templates/email/sepa-core/sepa-core.js | 4 +- .../reports/driver-route/assets/css/import.js | 13 ++-- .../reports/driver-route/driver-route.html | 2 +- .../reports/driver-route/driver-route.js | 23 ++++--- .../assets/css/import.js | 12 ++-- .../incoterms-authorization.js | 6 +- .../letter-debtor/assets/css/import.js | 13 ++-- .../reports/letter-debtor/letter-debtor.js | 16 ++--- .../reports/sepa-core/assets/css/import.js | 13 ++-- .../templates/reports/sepa-core/sepa-core.js | 16 ++--- 61 files changed, 1220 insertions(+), 235 deletions(-) create mode 100644 modules/client/back/methods/client/clientDebtStatementEmail.js create mode 100644 modules/client/back/methods/client/clientDebtStatementHtml.js create mode 100644 modules/client/back/methods/client/clientWelcomeEmail.js create mode 100644 modules/client/back/methods/client/clientWelcomeHtml.js create mode 100644 modules/client/back/methods/client/creditRequestEmail.js create mode 100644 modules/client/back/methods/client/creditRequestHtml.js create mode 100644 modules/client/back/methods/client/letterDebtorNdEmail.js create mode 100644 modules/client/back/methods/client/letterDebtorNdHtml.js create mode 100644 modules/client/back/methods/client/letterDebtorStEmail.js create mode 100644 modules/client/back/methods/client/letterDebtorStHtml.js create mode 100644 modules/client/back/methods/client/printerSetupEmail.js create mode 100644 modules/client/back/methods/client/printerSetupHtml.js create mode 100644 modules/client/back/methods/client/sepaCoreEmail.js create mode 100644 modules/client/back/models/client-methods.js create mode 100644 modules/route/back/methods/route/driverRouteEmail.js create mode 100644 modules/route/back/methods/route/driverRoutePdf.js delete mode 100644 modules/route/front/agency-term/index/style.scss diff --git a/db/changes/10490-august/00-ACL.sql b/db/changes/10490-august/00-ACL.sql index f7d984e37..633495ed2 100644 --- a/db/changes/10490-august/00-ACL.sql +++ b/db/changes/10490-august/00-ACL.sql @@ -3,4 +3,15 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp ('Ticket', 'deliveryNotePdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Ticket', 'deliveryNoteEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'campaignMetricsPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Client', 'campaignMetricsEmail', 'READ', 'ALLOW', 'ROLE', 'employee'); \ No newline at end of file + ('Client', 'campaignMetricsEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientWelcomeHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientWelcomeEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'printerSetupHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'printerSetupEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'sepaCoreEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorStHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorStEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorNdHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorNdEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientDebtStatementHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientDebtStatementEmail', 'READ', 'ALLOW', 'ROLE', 'employee'); \ No newline at end of file diff --git a/db/changes/10490-august/00-sample.sql b/db/changes/10490-august/00-sample.sql index e70d1fd13..8678d5e18 100644 --- a/db/changes/10490-august/00-sample.sql +++ b/db/changes/10490-august/00-sample.sql @@ -1,17 +1,32 @@ alter table `vn`.`sample` add model VARCHAR(25) null comment 'Model name in plural'; -alter table `vn`.`sample` - add property VARCHAR(25) null comment 'Remote method property name'; - - UPDATE vn.sample t - SET t.model = 'Clients', - t.property = 'printerSetup' + SET t.model = 'Clients' WHERE t.id = 13; UPDATE vn.sample t -SET t.model = 'Clients', - t.property = 'clientWelcome' +SET t.model = 'Clients' WHERE t.id = 12; +UPDATE vn.sample t +SET t.model = 'Clients' +WHERE t.id = 14; + +UPDATE vn.sample t +SET t.model = 'Clients' +WHERE t.id = 15; + +UPDATE vn.sample t +SET t.model = 'Clients' +WHERE t.id = 18; + +UPDATE vn.sample t +SET t.model = 'Clients' +WHERE t.id = 19; + +UPDATE vn.sample t +SET t.model = 'Clients' +WHERE t.id = 16; + + diff --git a/modules/client/back/methods/client/campaignMetricsEmail.js b/modules/client/back/methods/client/campaignMetricsEmail.js index 6bbff0a6c..fab90fbe0 100644 --- a/modules/client/back/methods/client/campaignMetricsEmail.js +++ b/modules/client/back/methods/client/campaignMetricsEmail.js @@ -1,4 +1,4 @@ -const {Report, Email, smtp} = require('vn-print'); +const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('campaignMetricsEmail', { @@ -50,7 +50,7 @@ module.exports = Self => { } }); - Self.campaignMetricsEmail = async(ctx, id) => { + Self.campaignMetricsEmail = async ctx => { const args = Object.assign({}, ctx.args); const params = { recipient: args.recipient, diff --git a/modules/client/back/methods/client/campaignMetricsPdf.js b/modules/client/back/methods/client/campaignMetricsPdf.js index 6d0a803a5..a6afa95a3 100644 --- a/modules/client/back/methods/client/campaignMetricsPdf.js +++ b/modules/client/back/methods/client/campaignMetricsPdf.js @@ -1,8 +1,8 @@ -const { Report } = require('vn-print'); +const {Report} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('campaignMetricsPdf', { - description: 'Returns the campaign metrics note pdf', + description: 'Returns the campaign metrics pdf', accepts: [ { arg: 'id', @@ -49,7 +49,7 @@ module.exports = Self => { } }); - Self.campaignMetricsPdf = async(ctx, id) => { + Self.campaignMetricsPdf = async(ctx, id) => { const args = Object.assign({}, ctx.args); const params = {lang: ctx.req.getLocale()}; diff --git a/modules/client/back/methods/client/clientDebtStatementEmail.js b/modules/client/back/methods/client/clientDebtStatementEmail.js new file mode 100644 index 000000000..0b34598b7 --- /dev/null +++ b/modules/client/back/methods/client/clientDebtStatementEmail.js @@ -0,0 +1,63 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('clientDebtStatementEmail', { + description: 'Sends the client debt statement email with an attached PDF', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + }, + { + arg: 'from', + type: 'string', + required: true + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/client-debt-statement-email', + verb: 'POST' + } + }); + + Self.clientDebtStatementEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('client-debt-statement', params); + + return email.send(); + }; +}; diff --git a/modules/client/back/methods/client/clientDebtStatementHtml.js b/modules/client/back/methods/client/clientDebtStatementHtml.js new file mode 100644 index 000000000..79455f4c4 --- /dev/null +++ b/modules/client/back/methods/client/clientDebtStatementHtml.js @@ -0,0 +1,62 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('clientDebtStatementHtml', { + description: 'Returns the client debt statement email preview', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + }, + { + arg: 'from', + type: 'string', + required: true + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/client-debt-statement-html', + verb: 'GET' + } + }); + + Self.clientDebtStatementHtml = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + params.isPreview = true; + + const report = new Email('client-debt-statement', params); + const html = await report.render(); + + return [html, 'text/html', `filename="mail-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/methods/client/clientWelcomeEmail.js b/modules/client/back/methods/client/clientWelcomeEmail.js new file mode 100644 index 000000000..aee4f9296 --- /dev/null +++ b/modules/client/back/methods/client/clientWelcomeEmail.js @@ -0,0 +1,58 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('clientWelcomeEmail', { + description: 'Sends the client welcome email with an attached PDF', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/client-welcome-email', + verb: 'POST' + } + }); + + Self.clientWelcomeEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('client-welcome', params); + + return email.send(); + }; +}; diff --git a/modules/client/back/methods/client/clientWelcomeHtml.js b/modules/client/back/methods/client/clientWelcomeHtml.js new file mode 100644 index 000000000..a54857e57 --- /dev/null +++ b/modules/client/back/methods/client/clientWelcomeHtml.js @@ -0,0 +1,57 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('clientWelcomeHtml', { + description: 'Returns the client welcome email preview', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/client-welcome-html', + verb: 'GET' + } + }); + + Self.clientWelcomeHtml = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + params.isPreview = true; + + const report = new Email('client-welcome', params); + const html = await report.render(); + + return [html, 'text/html', `filename="mail-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/methods/client/creditRequestEmail.js b/modules/client/back/methods/client/creditRequestEmail.js new file mode 100644 index 000000000..d6e6e69ea --- /dev/null +++ b/modules/client/back/methods/client/creditRequestEmail.js @@ -0,0 +1,58 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('clientCreditEmail', { + description: 'Sends the credit request email with an attached PDF', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/credit-request-email', + verb: 'POST' + } + }); + + Self.clientCreditEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('credit-request', params); + + return email.send(); + }; +}; diff --git a/modules/client/back/methods/client/creditRequestHtml.js b/modules/client/back/methods/client/creditRequestHtml.js new file mode 100644 index 000000000..2a7820c14 --- /dev/null +++ b/modules/client/back/methods/client/creditRequestHtml.js @@ -0,0 +1,57 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('creditRequestHtml', { + description: 'Returns the credit request email preview', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/credit-request-html', + verb: 'GET' + } + }); + + Self.creditRequestHtml = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + params.isPreview = true; + + const report = new Email('credit-request', params); + const html = await report.render(); + + return [html, 'text/html', `filename="mail-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/methods/client/letterDebtorNdEmail.js b/modules/client/back/methods/client/letterDebtorNdEmail.js new file mode 100644 index 000000000..3d03a8ab0 --- /dev/null +++ b/modules/client/back/methods/client/letterDebtorNdEmail.js @@ -0,0 +1,64 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('letterDebtorNdEmail', { + description: 'Sends the second debtor letter email with an attached PDF', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + }, + { + arg: 'companyId', + type: 'number', + description: 'The company id', + required: true + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/letter-debtor-nd-email', + verb: 'POST' + } + }); + + Self.letterDebtorNdEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('letter-debtor-nd', params); + + return email.send(); + }; +}; diff --git a/modules/client/back/methods/client/letterDebtorNdHtml.js b/modules/client/back/methods/client/letterDebtorNdHtml.js new file mode 100644 index 000000000..d57e8edc5 --- /dev/null +++ b/modules/client/back/methods/client/letterDebtorNdHtml.js @@ -0,0 +1,63 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('letterDebtorNdHtml', { + description: 'Returns the second letter debtor email preview', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + }, + { + arg: 'companyId', + type: 'number', + description: 'The company id', + required: true + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/letter-debtor-nd-html', + verb: 'GET' + } + }); + + Self.letterDebtorNdHtml = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + params.isPreview = true; + + const report = new Email('letter-debtor-nd', params); + const html = await report.render(); + + return [html, 'text/html', `filename="mail-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/methods/client/letterDebtorStEmail.js b/modules/client/back/methods/client/letterDebtorStEmail.js new file mode 100644 index 000000000..bec260cb0 --- /dev/null +++ b/modules/client/back/methods/client/letterDebtorStEmail.js @@ -0,0 +1,64 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('letterDebtorStEmail', { + description: 'Sends the printer setup email with an attached PDF', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + }, + { + arg: 'companyId', + type: 'number', + description: 'The company id', + required: true + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/letter-debtor-st-email', + verb: 'POST' + } + }); + + Self.letterDebtorStEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('letter-debtor-st', params); + + return email.send(); + }; +}; diff --git a/modules/client/back/methods/client/letterDebtorStHtml.js b/modules/client/back/methods/client/letterDebtorStHtml.js new file mode 100644 index 000000000..68f8f5056 --- /dev/null +++ b/modules/client/back/methods/client/letterDebtorStHtml.js @@ -0,0 +1,63 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('letterDebtorStHtml', { + description: 'Returns the letter debtor email preview', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + }, + { + arg: 'companyId', + type: 'number', + description: 'The company id', + required: true + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/letter-debtor-st-html', + verb: 'GET' + } + }); + + Self.letterDebtorStHtml = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + params.isPreview = true; + + const report = new Email('letter-debtor-st', params); + const html = await report.render(); + + return [html, 'text/html', `filename="mail-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/methods/client/printerSetupEmail.js b/modules/client/back/methods/client/printerSetupEmail.js new file mode 100644 index 000000000..df4864dda --- /dev/null +++ b/modules/client/back/methods/client/printerSetupEmail.js @@ -0,0 +1,58 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('printerSetupEmail', { + description: 'Sends the printer setup email with an attached PDF', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/printer-setup-email', + verb: 'POST' + } + }); + + Self.printerSetupEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('printer-setup', params); + + return email.send(); + }; +}; diff --git a/modules/client/back/methods/client/printerSetupHtml.js b/modules/client/back/methods/client/printerSetupHtml.js new file mode 100644 index 000000000..37e318723 --- /dev/null +++ b/modules/client/back/methods/client/printerSetupHtml.js @@ -0,0 +1,57 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('printerSetupHtml', { + description: 'Returns the printer setup email preview', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/printer-setup-html', + verb: 'GET' + } + }); + + Self.printerSetupHtml = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + params.isPreview = true; + + const report = new Email('printer-setup', params); + const html = await report.render(); + + return [html, 'text/html', `filename="mail-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/methods/client/sepaCoreEmail.js b/modules/client/back/methods/client/sepaCoreEmail.js new file mode 100644 index 000000000..47e0be132 --- /dev/null +++ b/modules/client/back/methods/client/sepaCoreEmail.js @@ -0,0 +1,64 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('sepaCoreEmail', { + description: 'Sends the campaign metrics email with an attached PDF', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + }, + { + arg: 'companyId', + type: 'number', + description: 'The company id', + required: true + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/sepa-core-email', + verb: 'POST' + } + }); + + Self.sepaCoreEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('sepa-core', params); + + return email.send(); + }; +}; diff --git a/modules/client/back/models/client-methods.js b/modules/client/back/models/client-methods.js new file mode 100644 index 000000000..ab7fb2596 --- /dev/null +++ b/modules/client/back/models/client-methods.js @@ -0,0 +1,43 @@ +module.exports = Self => { + require('../methods/client/addressesPropagateRe')(Self); + require('../methods/client/canBeInvoiced')(Self); + require('../methods/client/canCreateTicket')(Self); + require('../methods/client/checkDuplicated')(Self); + require('../methods/client/confirmTransaction')(Self); + require('../methods/client/consumption')(Self); + require('../methods/client/createAddress')(Self); + require('../methods/client/createReceipt')(Self); + require('../methods/client/createWithUser')(Self); + require('../methods/client/extendedListFilter')(Self); + require('../methods/client/getAverageInvoiced')(Self); + require('../methods/client/getCard')(Self); + require('../methods/client/getDebt')(Self); + require('../methods/client/getMana')(Self); + require('../methods/client/getTransactions')(Self); + require('../methods/client/hasCustomerRole')(Self); + require('../methods/client/isValidClient')(Self); + require('../methods/client/lastActiveTickets')(Self); + require('../methods/client/sendSms')(Self); + require('../methods/client/setPassword')(Self); + require('../methods/client/summary')(Self); + require('../methods/client/updateAddress')(Self); + require('../methods/client/updateFiscalData')(Self); + require('../methods/client/updatePortfolio')(Self); + require('../methods/client/updateUser')(Self); + require('../methods/client/uploadFile')(Self); + require('../methods/client/campaignMetricsPdf')(Self); + require('../methods/client/campaignMetricsEmail')(Self); + require('../methods/client/clientWelcomeHtml')(Self); + require('../methods/client/clientWelcomeEmail')(Self); + require('../methods/client/printerSetupHtml')(Self); + require('../methods/client/printerSetupEmail')(Self); + require('../methods/client/sepaCoreEmail')(Self); + require('../methods/client/letterDebtorStHtml')(Self); + require('../methods/client/letterDebtorStEmail')(Self); + require('../methods/client/letterDebtorNdHtml')(Self); + require('../methods/client/letterDebtorNdEmail')(Self); + require('../methods/client/clientDebtStatementHtml')(Self); + require('../methods/client/clientDebtStatementEmail')(Self); + require('../methods/client/creditRequestHtml')(Self); + require('../methods/client/creditRequestEmail')(Self); +}; diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 84997e204..d640356ec 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -8,34 +8,7 @@ const LoopBackContext = require('loopback-context'); module.exports = Self => { // Methods - require('../methods/client/addressesPropagateRe')(Self); - require('../methods/client/canBeInvoiced')(Self); - require('../methods/client/canCreateTicket')(Self); - require('../methods/client/checkDuplicated')(Self); - require('../methods/client/confirmTransaction')(Self); - require('../methods/client/consumption')(Self); - require('../methods/client/createAddress')(Self); - require('../methods/client/createReceipt')(Self); - require('../methods/client/createWithUser')(Self); - require('../methods/client/extendedListFilter')(Self); - require('../methods/client/getAverageInvoiced')(Self); - require('../methods/client/getCard')(Self); - require('../methods/client/getDebt')(Self); - require('../methods/client/getMana')(Self); - require('../methods/client/getTransactions')(Self); - require('../methods/client/hasCustomerRole')(Self); - require('../methods/client/isValidClient')(Self); - require('../methods/client/lastActiveTickets')(Self); - require('../methods/client/sendSms')(Self); - require('../methods/client/setPassword')(Self); - require('../methods/client/summary')(Self); - require('../methods/client/updateAddress')(Self); - require('../methods/client/updateFiscalData')(Self); - require('../methods/client/updatePortfolio')(Self); - require('../methods/client/updateUser')(Self); - require('../methods/client/uploadFile')(Self); - require('../methods/client/campaignMetricsPdf')(Self); - require('../methods/client/campaignMetricsEmail')(Self); + require('./client-methods')(Self); // Validations diff --git a/modules/client/front/sample/create/index.html b/modules/client/front/sample/create/index.html index ac6cc312e..5df2b29ef 100644 --- a/modules/client/front/sample/create/index.html +++ b/modules/client/front/sample/create/index.html @@ -7,6 +7,15 @@ @@ -31,7 +40,6 @@ ng-model="$ctrl.clientSample.typeFk" model="ClientSample.typeFk" data="samplesVisible" - fields="['id', 'description', 'model']" show-field="description" label="Sample" required="true"> diff --git a/modules/client/front/sample/create/index.js b/modules/client/front/sample/create/index.js index 3bc341460..df0211d06 100644 --- a/modules/client/front/sample/create/index.js +++ b/modules/client/front/sample/create/index.js @@ -3,12 +3,13 @@ import Section from 'salix/components/section'; import './style.scss'; class Controller extends Section { - constructor($element, $) { + constructor($element, $, vnEmail) { super($element, $); this.clientSample = { clientFk: this.$params.id, companyId: this.vnConfig.companyFk }; + this.vnEmail = vnEmail; } get client() { @@ -36,9 +37,7 @@ class Controller extends Section { onSubmit() { this.$.watcher.check(); - this.$.watcher.realSubmit().then(() => - this.sendSample() - ); + this.$.watcher.realSubmit().then(() => this.send()); } // showPreview() { @@ -93,16 +92,39 @@ class Controller extends Section { // this.$http.get(query, {params}).then(cb); // } + validateParams(params) { + const sampleType = this.$.sampleType.selection; + + if (!params.recipient) + return this.vnApp.showError(this.$t('Email cannot be blank')); + + if (!sampleType) + return this.vnApp.showError(this.$t('Choose a sample')); + + if (sampleType.hasCompany && !this.clientSample.companyFk) + return this.vnApp.showError(this.$t('Choose a company')); + + if (sampleType.hasCompany) + params.companyId = this.clientSample.companyFk; + + if (sampleType.datepickerEnabled && !this.clientSample.from) + return this.vnApp.showError(this.$t('Choose a date')); + + if (sampleType.datepickerEnabled) + params.from = this.clientSample.from; + } + preview() { const sampleType = this.$.sampleType.selection; const params = { recipientId: this.$params.id, - recipient: this.clientSample.recipient, - replyTo: this.clientSample.replyTo + recipient: this.clientSample.recipient }; - const path = `${sampleType.model}/${this.$params.id}/${sampleType.property}Html`; + this.validateParams(params); + + const path = `${sampleType.model}/${this.$params.id}/${sampleType.code}-html`; this.$http.get(path, {params}) .then(response => { this.$.showPreview.show(); @@ -116,10 +138,19 @@ class Controller extends Section { } send() { - this.vnEmail.send(`tickets/${this.id}/credit-request-email`, { - recipientId: this.ticket.client.id, - recipient: $data.email - }); + const sampleType = this.$.sampleType.selection; + + const params = { + recipientId: this.client.id, + recipient: this.clientSample.recipient, + replyTo: this.clientSample.replyTo + }; + + this.validateParams(params); + + const path = `${sampleType.model}/${this.$params.id}/${sampleType.code}-email`; + this.vnEmail.send(path, params) + .then(() => this.$state.go('client.card.sample.index')); } getWorkerEmail() { @@ -132,7 +163,7 @@ class Controller extends Section { } } -Controller.$inject = ['$element', '$scope']; +Controller.$inject = ['$element', '$scope', 'vnEmail']; ngModule.vnComponent('vnClientSampleCreate', { template: require('./index.html'), diff --git a/modules/item/front/index/style.scss b/modules/item/front/index/style.scss index eaa1a16ed..451dd09ae 100644 --- a/modules/item/front/index/style.scss +++ b/modules/item/front/index/style.scss @@ -21,12 +21,4 @@ vn-item-product { vn-label-value:first-of-type section{ margin-top: 9px; } -} - -table { - img { - border-radius: 50%; - width: 50px; - height: 50px; - } } \ No newline at end of file diff --git a/modules/route/back/methods/route/driverRouteEmail.js b/modules/route/back/methods/route/driverRouteEmail.js new file mode 100644 index 000000000..81d770360 --- /dev/null +++ b/modules/route/back/methods/route/driverRouteEmail.js @@ -0,0 +1,58 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('driverRouteEmail', { + description: 'Sends the driver route email with an attached PDF', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/driver-route-email', + verb: 'POST' + } + }); + + Self.driverRouteEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('driver-route', params); + + return email.send(); + }; +}; diff --git a/modules/route/back/methods/route/driverRoutePdf.js b/modules/route/back/methods/route/driverRoutePdf.js new file mode 100644 index 000000000..161eb71af --- /dev/null +++ b/modules/route/back/methods/route/driverRoutePdf.js @@ -0,0 +1,55 @@ +const {Report} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('driverRoutePdf', { + description: 'Returns the driver route pdf', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/driver-route-pdf', + verb: 'GET' + } + }); + + Self.driverRoutePdf = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('driver-route', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; + }; +}; diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js index 4050e62fe..f5406728a 100644 --- a/modules/route/back/models/route.js +++ b/modules/route/back/models/route.js @@ -10,6 +10,8 @@ module.exports = Self => { require('../methods/route/getSuggestedTickets')(Self); require('../methods/route/unlink')(Self); require('../methods/route/updateWorkCenter')(Self); + require('../methods/route/driverRoutePdf')(Self); + require('../methods/route/driverRouteEmail')(Self); Self.validate('kmStart', validateDistance, { message: 'Distance must be lesser than 1000' diff --git a/modules/route/front/agency-term/index/index.js b/modules/route/front/agency-term/index/index.js index f73095e7a..6c3bafc9a 100644 --- a/modules/route/front/agency-term/index/index.js +++ b/modules/route/front/agency-term/index/index.js @@ -1,6 +1,5 @@ import ngModule from '../../module'; import Section from 'salix/components/section'; -import './style.scss'; class Controller extends Section { constructor($element, $) { diff --git a/modules/route/front/agency-term/index/style.scss b/modules/route/front/agency-term/index/style.scss deleted file mode 100644 index eaa1a16ed..000000000 --- a/modules/route/front/agency-term/index/style.scss +++ /dev/null @@ -1,32 +0,0 @@ -@import "variables"; - -vn-item-product { - display: block; - - .id { - background-color: $color-main; - color: $color-font-dark; - margin-bottom: 0; - } - .image { - height: 112px; - width: 112px; - - & > img { - max-height: 100%; - max-width: 100%; - border-radius: 3px; - } - } - vn-label-value:first-of-type section{ - margin-top: 9px; - } -} - -table { - img { - border-radius: 50%; - width: 50px; - height: 50px; - } -} \ No newline at end of file diff --git a/modules/route/front/descriptor/index.js b/modules/route/front/descriptor/index.js index 32411aa58..0573201bf 100644 --- a/modules/route/front/descriptor/index.js +++ b/modules/route/front/descriptor/index.js @@ -11,16 +11,16 @@ class Controller extends Descriptor { } showRouteReport() { - this.vnReport.show('driver-route', { - routeId: this.id + this.vnReport.show(`Routes/${this.id}/driver-route-pdf`, { + id: this.id }); } sendRouteReport() { const workerUser = this.route.worker.user; - this.vnEmail.send('driver-route', { + this.vnEmail.send(`Routes/${this.id}/driver-route-email`, { recipient: workerUser.emailUser.email, - routeId: this.id + id: this.id }); } diff --git a/modules/ticket/back/methods/ticket/deliveryNoteEmail.js b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js index 5926fba58..b15783e1b 100644 --- a/modules/ticket/back/methods/ticket/deliveryNoteEmail.js +++ b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js @@ -1,4 +1,4 @@ -const { Email } = require('vn-print'); +const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('deliveryNoteEmail', { @@ -46,7 +46,7 @@ module.exports = Self => { } }); - Self.deliveryNoteEmail = async(ctx, id) => { + Self.deliveryNoteEmail = async ctx => { const args = Object.assign({}, ctx.args); const params = { recipient: args.recipient, diff --git a/modules/ticket/back/methods/ticket/deliveryNotePdf.js b/modules/ticket/back/methods/ticket/deliveryNotePdf.js index 373d96d1f..3f6af8359 100644 --- a/modules/ticket/back/methods/ticket/deliveryNotePdf.js +++ b/modules/ticket/back/methods/ticket/deliveryNotePdf.js @@ -1,4 +1,4 @@ -const {Report, Email, smtp} = require('vn-print'); +const {Report} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('deliveryNotePdf', { @@ -45,7 +45,7 @@ module.exports = Self => { } }); - Self.deliveryNotePdf = async(ctx, id) => { + Self.deliveryNotePdf = async(ctx, id) => { const args = Object.assign({}, ctx.args); const params = {lang: ctx.req.getLocale()}; diff --git a/print/core/components/attachment/assets/css/import.js b/print/core/components/attachment/assets/css/import.js index c742fdf90..fec23d870 100644 --- a/print/core/components/attachment/assets/css/import.js +++ b/print/core/components/attachment/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/email/claim-pickup-order/assets/css/import.js b/print/templates/email/claim-pickup-order/assets/css/import.js index 89b2afaa5..1582b82c5 100644 --- a/print/templates/email/claim-pickup-order/assets/css/import.js +++ b/print/templates/email/claim-pickup-order/assets/css/import.js @@ -8,4 +8,5 @@ module.exports = new Stylesheet([ `${vnPrintPath}/common/css/misc.css`, `${vnPrintPath}/common/css/layout.css`, `${vnPrintPath}/common/css/email.css`]) - .mergeStyles(); \ No newline at end of file + .mergeStyles(); + diff --git a/print/templates/email/client-debt-statement/assets/css/import.js b/print/templates/email/client-debt-statement/assets/css/import.js index 89b2afaa5..4b4bb7086 100644 --- a/print/templates/email/client-debt-statement/assets/css/import.js +++ b/print/templates/email/client-debt-statement/assets/css/import.js @@ -8,4 +8,4 @@ module.exports = new Stylesheet([ `${vnPrintPath}/common/css/misc.css`, `${vnPrintPath}/common/css/layout.css`, `${vnPrintPath}/common/css/email.css`]) - .mergeStyles(); \ No newline at end of file + .mergeStyles(); diff --git a/print/templates/email/client-welcome/assets/css/import.js b/print/templates/email/client-welcome/assets/css/import.js index b44d6bd37..4b4bb7086 100644 --- a/print/templates/email/client-welcome/assets/css/import.js +++ b/print/templates/email/client-welcome/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) .mergeStyles(); diff --git a/print/templates/email/client-welcome/client-welcome.js b/print/templates/email/client-welcome/client-welcome.js index eeb11bb78..380837877 100755 --- a/print/templates/email/client-welcome/client-welcome.js +++ b/print/templates/email/client-welcome/client-welcome.js @@ -1,15 +1,15 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); module.exports = { name: 'client-welcome', async serverPrefetch() { - this.client = await this.fetchClient(this.recipientId); + this.client = await this.fetchClient(this.id); }, methods: { - fetchClient(clientId) { - return this.findOneFromDef('client', [clientId]); + fetchClient(id) { + return this.findOneFromDef('client', [id]); }, }, components: { @@ -17,7 +17,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true } diff --git a/print/templates/email/delivery-note-link/assets/css/import.js b/print/templates/email/delivery-note-link/assets/css/import.js index c742fdf90..fec23d870 100644 --- a/print/templates/email/delivery-note-link/assets/css/import.js +++ b/print/templates/email/delivery-note-link/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`, `${__dirname}/style.css`]) .mergeStyles(); 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 471b370d9..1804bf144 100755 --- a/print/templates/email/delivery-note-link/delivery-note-link.js +++ b/print/templates/email/delivery-note-link/delivery-note-link.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); @@ -9,7 +9,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - ticketId: { + id: { type: [Number, String], required: true } diff --git a/print/templates/email/delivery-note/assets/css/import.js b/print/templates/email/delivery-note/assets/css/import.js index 89b2afaa5..4b4bb7086 100644 --- a/print/templates/email/delivery-note/assets/css/import.js +++ b/print/templates/email/delivery-note/assets/css/import.js @@ -8,4 +8,4 @@ module.exports = new Stylesheet([ `${vnPrintPath}/common/css/misc.css`, `${vnPrintPath}/common/css/layout.css`, `${vnPrintPath}/common/css/email.css`]) - .mergeStyles(); \ No newline at end of file + .mergeStyles(); diff --git a/print/templates/email/driver-route/assets/css/import.js b/print/templates/email/driver-route/assets/css/import.js index b44d6bd37..4b4bb7086 100644 --- a/print/templates/email/driver-route/assets/css/import.js +++ b/print/templates/email/driver-route/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) .mergeStyles(); diff --git a/print/templates/email/driver-route/driver-route.js b/print/templates/email/driver-route/driver-route.js index 378cd82ce..0895ccc8c 100755 --- a/print/templates/email/driver-route/driver-route.js +++ b/print/templates/email/driver-route/driver-route.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); @@ -9,7 +9,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - routeId: { + id: { type: [Number, String], required: true } diff --git a/print/templates/email/incoterms-authorization/assets/css/import.js b/print/templates/email/incoterms-authorization/assets/css/import.js index b44d6bd37..4b4bb7086 100644 --- a/print/templates/email/incoterms-authorization/assets/css/import.js +++ b/print/templates/email/incoterms-authorization/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) .mergeStyles(); diff --git a/print/templates/email/incoterms-authorization/incoterms-authorization.js b/print/templates/email/incoterms-authorization/incoterms-authorization.js index bac40d331..051ff554b 100755 --- a/print/templates/email/incoterms-authorization/incoterms-authorization.js +++ b/print/templates/email/incoterms-authorization/incoterms-authorization.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-report/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); @@ -15,7 +15,7 @@ module.exports = { 'attachment': attachment.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true }, diff --git a/print/templates/email/letter-debtor-nd/assets/css/import.js b/print/templates/email/letter-debtor-nd/assets/css/import.js index 624404a6c..1582b82c5 100644 --- a/print/templates/email/letter-debtor-nd/assets/css/import.js +++ b/print/templates/email/letter-debtor-nd/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) .mergeStyles(); 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 5e010d1ba..a51797fa1 100755 --- a/print/templates/email/letter-debtor-nd/letter-debtor-nd.js +++ b/print/templates/email/letter-debtor-nd/letter-debtor-nd.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); @@ -7,7 +7,7 @@ const attachments = require('./attachments.json'); module.exports = { name: 'letter-debtor-nd', async serverPrefetch() { - this.debtor = await this.fetchDebtor(this.recipientId, this.companyId); + this.debtor = await this.fetchDebtor(this.id, this.companyId); if (!this.debtor) throw new Error('Something went wrong'); @@ -16,8 +16,8 @@ module.exports = { return {attachments}; }, methods: { - fetchDebtor(clientId, companyId) { - return this.findOneFromDef('client', [clientId, companyId]); + fetchDebtor(id, companyId) { + return this.findOneFromDef('client', [id, companyId]); } }, components: { @@ -26,10 +26,7 @@ module.exports = { 'attachment': attachment.build() }, props: { - authorization: { - required: true - }, - recipientId: { + id: { type: [Number, String], required: true }, diff --git a/print/templates/email/letter-debtor-nd/sql/client.sql b/print/templates/email/letter-debtor-nd/sql/client.sql index 479bfac5e..d5da5d0d5 100644 --- a/print/templates/email/letter-debtor-nd/sql/client.sql +++ b/print/templates/email/letter-debtor-nd/sql/client.sql @@ -5,7 +5,6 @@ SELECT be.name AS bankName FROM client c JOIN company AS cny - JOIN supplierAccount AS sa ON - IF (ct.code = 'PT', sa.id = 907, sa.id = cny.supplierAccountFk) + JOIN supplierAccount AS sa ON sa.id = cny.supplierAccountFk JOIN bankEntity be ON be.id = sa.bankEntityFk WHERE c.id = ? AND cny.id = ? \ No newline at end of file diff --git a/print/templates/email/letter-debtor-st/assets/css/import.js b/print/templates/email/letter-debtor-st/assets/css/import.js index 624404a6c..1582b82c5 100644 --- a/print/templates/email/letter-debtor-st/assets/css/import.js +++ b/print/templates/email/letter-debtor-st/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) .mergeStyles(); 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 a514097cf..9f357e6de 100755 --- a/print/templates/email/letter-debtor-st/letter-debtor-st.js +++ b/print/templates/email/letter-debtor-st/letter-debtor-st.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); @@ -7,7 +7,7 @@ const attachments = require('./attachments.json'); module.exports = { name: 'letter-debtor-st', async serverPrefetch() { - this.debtor = await this.fetchDebtor(this.recipientId, this.companyId); + this.debtor = await this.fetchDebtor(this.id, this.companyId); if (!this.debtor) throw new Error('Something went wrong'); @@ -16,8 +16,8 @@ module.exports = { return {attachments}; }, methods: { - fetchDebtor(clientId, companyId) { - return this.findOneFromDef('client', [clientId, companyId]); + fetchDebtor(id, companyId) { + return this.findOneFromDef('client', [id, companyId]); } }, components: { @@ -26,7 +26,7 @@ module.exports = { 'attachment': attachment.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true }, diff --git a/print/templates/email/letter-debtor-st/sql/client.sql b/print/templates/email/letter-debtor-st/sql/client.sql index 479bfac5e..d5da5d0d5 100644 --- a/print/templates/email/letter-debtor-st/sql/client.sql +++ b/print/templates/email/letter-debtor-st/sql/client.sql @@ -5,7 +5,6 @@ SELECT be.name AS bankName FROM client c JOIN company AS cny - JOIN supplierAccount AS sa ON - IF (ct.code = 'PT', sa.id = 907, sa.id = cny.supplierAccountFk) + JOIN supplierAccount AS sa ON sa.id = cny.supplierAccountFk JOIN bankEntity be ON be.id = sa.bankEntityFk WHERE c.id = ? AND cny.id = ? \ No newline at end of file diff --git a/print/templates/email/printer-setup/assets/css/import.js b/print/templates/email/printer-setup/assets/css/import.js index b44d6bd37..4b4bb7086 100644 --- a/print/templates/email/printer-setup/assets/css/import.js +++ b/print/templates/email/printer-setup/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) .mergeStyles(); diff --git a/print/templates/email/printer-setup/printer-setup.js b/print/templates/email/printer-setup/printer-setup.js index 95dff8ebb..a7d3c40bf 100755 --- a/print/templates/email/printer-setup/printer-setup.js +++ b/print/templates/email/printer-setup/printer-setup.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); @@ -7,14 +7,14 @@ const attachments = require('./attachments.json'); module.exports = { name: 'printer-setup', async serverPrefetch() { - this.client = await this.fetchClient(this.recipientId); + this.client = await this.fetchClient(this.id); }, data() { return {attachments}; }, methods: { - fetchClient(clientId) { - return this.findOneFromDef('client', [clientId]); + fetchClient(id) { + return this.findOneFromDef('client', [id]); } }, components: { @@ -23,7 +23,7 @@ module.exports = { 'attachment': attachment.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true } diff --git a/print/templates/email/sepa-core/assets/css/import.js b/print/templates/email/sepa-core/assets/css/import.js index b44d6bd37..1582b82c5 100644 --- a/print/templates/email/sepa-core/assets/css/import.js +++ b/print/templates/email/sepa-core/assets/css/import.js @@ -1,8 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) .mergeStyles(); + diff --git a/print/templates/email/sepa-core/sepa-core.js b/print/templates/email/sepa-core/sepa-core.js index 743c6719c..00cc527dc 100755 --- a/print/templates/email/sepa-core/sepa-core.js +++ b/print/templates/email/sepa-core/sepa-core.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); @@ -15,7 +15,7 @@ module.exports = { 'attachment': attachment.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true }, diff --git a/print/templates/reports/driver-route/assets/css/import.js b/print/templates/reports/driver-route/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/driver-route/assets/css/import.js +++ b/print/templates/reports/driver-route/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/driver-route/driver-route.html b/print/templates/reports/driver-route/driver-route.html index 600c49970..987c51369 100644 --- a/print/templates/reports/driver-route/driver-route.html +++ b/print/templates/reports/driver-route/driver-route.html @@ -141,7 +141,7 @@
{{client.id}}
{{$t(type)}}{{$t(deliverNoteType)}} {{ticket.id}}
-
+

{{ticket.description}}

diff --git a/print/templates/reports/driver-route/driver-route.js b/print/templates/reports/driver-route/driver-route.js index c34de37cc..41aa9f811 100755 --- a/print/templates/reports/driver-route/driver-route.js +++ b/print/templates/reports/driver-route/driver-route.js @@ -1,13 +1,18 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); module.exports = { name: 'driver-route', async serverPrefetch() { - const routesId = this.routeId.split(','); - const routes = await this.fetchRoutes(routesId); - const tickets = await this.fetchTickets(routesId); + let ids = this.id; + + const hasMultipleRoutes = String(this.id).includes(','); + if (hasMultipleRoutes) + ids = this.id.split(','); + + const routes = await this.fetchRoutes(ids); + const tickets = await this.fetchTickets(ids); const map = new Map(); @@ -26,11 +31,11 @@ module.exports = { throw new Error('Something went wrong'); }, methods: { - fetchRoutes(routesId) { - return this.rawSqlFromDef('routes', [routesId]); + fetchRoutes(ids) { + return this.rawSqlFromDef('routes', [ids]); }, - fetchTickets(routesId) { - return this.rawSqlFromDef('tickets', [routesId, routesId]); + fetchTickets(ids) { + return this.rawSqlFromDef('tickets', [ids, ids]); } }, components: { @@ -38,7 +43,7 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - routeId: { + id: { type: [Number, String], required: true } diff --git a/print/templates/reports/incoterms-authorization/assets/css/import.js b/print/templates/reports/incoterms-authorization/assets/css/import.js index a2a9334cb..37a98dfdd 100644 --- a/print/templates/reports/incoterms-authorization/assets/css/import.js +++ b/print/templates/reports/incoterms-authorization/assets/css/import.js @@ -1,8 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, - `${appPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/incoterms-authorization/incoterms-authorization.js b/print/templates/reports/incoterms-authorization/incoterms-authorization.js index 656a9d7b0..54f34136b 100755 --- a/print/templates/reports/incoterms-authorization/incoterms-authorization.js +++ b/print/templates/reports/incoterms-authorization/incoterms-authorization.js @@ -1,11 +1,11 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); module.exports = { name: 'incoterms-authorization', async serverPrefetch() { - this.client = await this.findOneFromDef('client', [this.recipientId]); + this.client = await this.findOneFromDef('client', [this.id]); this.company = await this.findOneFromDef('company', [this.companyId]); if (!this.client) throw new Error('Something went wrong'); @@ -20,7 +20,7 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true }, diff --git a/print/templates/reports/letter-debtor/assets/css/import.js b/print/templates/reports/letter-debtor/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/letter-debtor/assets/css/import.js +++ b/print/templates/reports/letter-debtor/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/letter-debtor/letter-debtor.js b/print/templates/reports/letter-debtor/letter-debtor.js index 354b1d8d8..626596297 100755 --- a/print/templates/reports/letter-debtor/letter-debtor.js +++ b/print/templates/reports/letter-debtor/letter-debtor.js @@ -1,12 +1,12 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); module.exports = { name: 'letter-debtor', async serverPrefetch() { - this.client = await this.fetchClient(this.recipientId); - this.sales = await this.fetchSales(this.recipientId, this.companyId); + this.client = await this.fetchClient(this.id); + this.sales = await this.fetchSales(this.id, this.companyId); if (!this.client) throw new Error('Something went wrong'); @@ -22,12 +22,12 @@ module.exports = { return {totalBalance: 0.00}; }, methods: { - fetchClient(clientId) { - return this.findOneFromDef('client', [clientId]); + fetchClient(id) { + return this.findOneFromDef('client', [id]); }, - fetchSales(clientId, companyId) { + fetchSales(id, companyId) { return this.findOneFromDef('sales', [ - clientId, + id, companyId ]); }, @@ -62,7 +62,7 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true }, diff --git a/print/templates/reports/sepa-core/assets/css/import.js b/print/templates/reports/sepa-core/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/sepa-core/assets/css/import.js +++ b/print/templates/reports/sepa-core/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/sepa-core/sepa-core.js b/print/templates/reports/sepa-core/sepa-core.js index 7e3dd3566..1537a265a 100755 --- a/print/templates/reports/sepa-core/sepa-core.js +++ b/print/templates/reports/sepa-core/sepa-core.js @@ -1,12 +1,12 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); const rptSepaCore = { name: 'sepa-core', async serverPrefetch() { - this.client = await this.fetchClient(this.recipientId, this.companyId); - this.supplier = await this.fetchSupplier(this.recipientId, this.companyId); + this.client = await this.fetchClient(this.id, this.companyId); + this.supplier = await this.fetchSupplier(this.id, this.companyId); if (!this.client) throw new Error('Something went wrong'); @@ -19,18 +19,18 @@ const rptSepaCore = { } }, methods: { - fetchClient(clientId, companyId) { + fetchClient(id, companyId) { return this.findOneFromDef('client', [ companyId, companyId, - clientId + id ]); }, - fetchSupplier(clientId, companyId) { + fetchSupplier(id, companyId) { return this.findOneFromDef('supplier', [ companyId, companyId, - clientId + id ]); } }, @@ -39,7 +39,7 @@ const rptSepaCore = { 'report-footer': reportFooter.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true }, From 7f78286d6b6e50a9f99f5bcd15f70d5ebcd8f155 Mon Sep 17 00:00:00 2001 From: joan Date: Mon, 26 Sep 2022 13:33:27 +0200 Subject: [PATCH 09/53] Reports refactor --- db/changes/10490-august/00-ACL.sql | 11 ++- db/changes/10490-august/00-sample.sql | 30 +----- db/dump/fixtures.sql | 5 - .../client/incotermsAuthorizationEmail.js | 65 +++++++++++++ .../client/incotermsAuthorizationHtml.js | 64 +++++++++++++ modules/client/back/models/client-methods.js | 2 + modules/client/back/models/client-sample.js | 17 ++-- modules/client/back/models/sample.json | 3 - .../entry/back/methods/entry/entryOrderPdf.js | 54 +++++++++++ modules/entry/back/models/entry.js | 1 + modules/entry/front/descriptor/index.js | 4 +- .../back/methods/invoiceOut/exportationPdf.js | 54 +++++++++++ .../back/methods/invoiceOut/invoiceEmail.js | 58 ++++++++++++ modules/invoiceOut/back/models/invoice-out.js | 2 + .../invoiceOut/front/descriptor-menu/index.js | 7 +- .../methods/supplier/campaignMetricsEmail.js | 68 ++++++++++++++ .../methods/supplier/campaignMetricsPdf.js | 65 +++++++++++++ modules/supplier/back/models/supplier.js | 2 + modules/supplier/front/consumption/index.js | 7 +- .../methods/travel/extraCommunityEmail.js | 92 +++++++++++++++++++ .../back/methods/travel/extraCommunityPdf.js | 89 ++++++++++++++++++ modules/travel/back/models/travel.js | 2 + modules/travel/front/extra-community/index.js | 2 +- .../incoterms-authorization.js | 2 +- .../email/invoice/assets/css/import.js | 13 ++- print/templates/email/invoice/invoice.js | 10 +- .../assets/css/import.js | 13 ++- .../supplier-campaign-metrics.js | 4 +- .../campaign-metrics/campaign-metrics.js | 3 +- .../claim-pickup-order/claim-pickup-order.js | 3 +- .../client-debt-statement.js | 3 +- .../reports/delivery-note/delivery-note.js | 3 +- .../reports/driver-route/driver-route.js | 3 +- .../reports/entry-order/assets/css/import.js | 13 ++- .../reports/entry-order/entry-order.js | 25 ++--- .../reports/exportation/assets/css/import.js | 12 ++- .../reports/exportation/exportation.html | 6 +- .../reports/exportation/exportation.js | 15 +-- .../reports/exportation/locale/es.yml | 1 + .../reports/exportation/sql/company.sql | 9 ++ .../reports/exportation/sql/invoice.sql | 3 +- .../extra-community/assets/css/import.js | 13 ++- .../extra-community/extra-community.js | 14 ++- .../incoterms-authorization.js | 3 +- .../invoice-incoterms/assets/css/import.js | 13 ++- .../invoice-incoterms/invoice-incoterms.js | 25 ++--- .../reports/invoice/assets/css/import.js | 13 ++- print/templates/reports/invoice/invoice.js | 57 ++++++------ .../reports/item-label/assets/css/import.js | 13 ++- .../reports/item-label/item-label.js | 21 +++-- .../reports/letter-debtor/letter-debtor.js | 3 +- .../reports/receipt/assets/css/import.js | 12 ++- print/templates/reports/receipt/receipt.js | 19 ++-- .../templates/reports/sepa-core/sepa-core.js | 3 +- .../assets/css/import.js | 13 ++- .../supplier-campaign-metrics.js | 11 ++- .../reports/zone/assets/css/import.js | 12 ++- print/templates/reports/zone/zone.js | 11 ++- 58 files changed, 883 insertions(+), 218 deletions(-) create mode 100644 modules/client/back/methods/client/incotermsAuthorizationEmail.js create mode 100644 modules/client/back/methods/client/incotermsAuthorizationHtml.js create mode 100644 modules/entry/back/methods/entry/entryOrderPdf.js create mode 100644 modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js create mode 100644 modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js create mode 100644 modules/supplier/back/methods/supplier/campaignMetricsEmail.js create mode 100644 modules/supplier/back/methods/supplier/campaignMetricsPdf.js create mode 100644 modules/travel/back/methods/travel/extraCommunityEmail.js create mode 100644 modules/travel/back/methods/travel/extraCommunityPdf.js create mode 100644 print/templates/reports/exportation/sql/company.sql diff --git a/db/changes/10490-august/00-ACL.sql b/db/changes/10490-august/00-ACL.sql index 633495ed2..871305709 100644 --- a/db/changes/10490-august/00-ACL.sql +++ b/db/changes/10490-august/00-ACL.sql @@ -14,4 +14,13 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp ('Client', 'letterDebtorNdHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'letterDebtorNdEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'clientDebtStatementHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Client', 'clientDebtStatementEmail', 'READ', 'ALLOW', 'ROLE', 'employee'); \ No newline at end of file + ('Client', 'clientDebtStatementEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'incotermsAuthorizationHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'incotermsAuthorizationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), + ('InvoiceOut', 'invoiceEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), + ('InvoiceOut', 'exportationPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Supplier', 'campaignMetricsPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Supplier', 'campaignMetricsEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), + ('Travel', 'extraCommunityPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Travel', 'extraCommunityEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), + ('Entry', 'entryOrderPdf', 'READ', 'ALLOW', 'ROLE', 'employee'); \ No newline at end of file diff --git a/db/changes/10490-august/00-sample.sql b/db/changes/10490-august/00-sample.sql index 8678d5e18..e9dd9e9a0 100644 --- a/db/changes/10490-august/00-sample.sql +++ b/db/changes/10490-august/00-sample.sql @@ -2,31 +2,5 @@ alter table `vn`.`sample` add model VARCHAR(25) null comment 'Model name in plural'; UPDATE vn.sample t - SET t.model = 'Clients' - WHERE t.id = 13; - -UPDATE vn.sample t -SET t.model = 'Clients' -WHERE t.id = 12; - -UPDATE vn.sample t -SET t.model = 'Clients' -WHERE t.id = 14; - -UPDATE vn.sample t -SET t.model = 'Clients' -WHERE t.id = 15; - -UPDATE vn.sample t -SET t.model = 'Clients' -WHERE t.id = 18; - -UPDATE vn.sample t -SET t.model = 'Clients' -WHERE t.id = 19; - -UPDATE vn.sample t -SET t.model = 'Clients' -WHERE t.id = 16; - - + SET t.model = 'Clients' + WHERE t.id IN(13, 14, 15, 16, 18, 19, 20); \ No newline at end of file diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 7835b32c4..997ebf92f 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1765,11 +1765,6 @@ INSERT INTO `vn`.`claimDestination`(`id`, `description`, `addressFk`) (4, 'Reclam.PRAG', 12), (5, 'Corregido', 11); -INSERT INTO `vn`.`claimResponsible`(`id`, `description`, `responsability`) - VALUES - (1, 'Buyers', 0), - (7, 'Quality', 0); - INSERT INTO `vn`.`claimDevelopment`(`id`, `claimFk`, `claimResponsibleFk`, `workerFk`, `claimReasonFk`, `claimResultFk`, `claimRedeliveryFk`, `claimDestinationFk`) VALUES (1, 1, 1, 21, 1, 1, 2, 5), diff --git a/modules/client/back/methods/client/incotermsAuthorizationEmail.js b/modules/client/back/methods/client/incotermsAuthorizationEmail.js new file mode 100644 index 000000000..2a4fe593a --- /dev/null +++ b/modules/client/back/methods/client/incotermsAuthorizationEmail.js @@ -0,0 +1,65 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('incotermsAuthorizationEmail', { + description: 'Sends the incoterms authorization email with an attached PDF', + accessType: 'WRITE', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + }, + { + arg: 'companyId', + type: 'number', + description: 'The company id', + required: true + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/incoterms-authorization-email', + verb: 'POST' + } + }); + + Self.incotermsAuthorizationEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('incoterms-authorization', params); + + return email.send(); + }; +}; diff --git a/modules/client/back/methods/client/incotermsAuthorizationHtml.js b/modules/client/back/methods/client/incotermsAuthorizationHtml.js new file mode 100644 index 000000000..f8c3e6e60 --- /dev/null +++ b/modules/client/back/methods/client/incotermsAuthorizationHtml.js @@ -0,0 +1,64 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('incotermsAuthorizationHtml', { + description: 'Returns the incoterms authorization email preview', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + }, + { + arg: 'companyId', + type: 'number', + description: 'The company id', + required: true + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/incoterms-authorization-html', + verb: 'GET' + } + }); + + Self.incotermsAuthorizationHtml = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + params.isPreview = true; + + const report = new Email('incoterms-authorization', params); + const html = await report.render(); + + return [html, 'text/html', `filename="mail-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/models/client-methods.js b/modules/client/back/models/client-methods.js index ab7fb2596..c8b6389c6 100644 --- a/modules/client/back/models/client-methods.js +++ b/modules/client/back/models/client-methods.js @@ -40,4 +40,6 @@ module.exports = Self => { require('../methods/client/clientDebtStatementEmail')(Self); require('../methods/client/creditRequestHtml')(Self); require('../methods/client/creditRequestEmail')(Self); + require('../methods/client/incotermsAuthorizationHtml')(Self); + require('../methods/client/incotermsAuthorizationEmail')(Self); }; diff --git a/modules/client/back/models/client-sample.js b/modules/client/back/models/client-sample.js index c7cda2412..787cc2ad8 100644 --- a/modules/client/back/models/client-sample.js +++ b/modules/client/back/models/client-sample.js @@ -1,4 +1,5 @@ const UserError = require('vn-loopback/util/user-error'); +const LoopBackContext = require('loopback-context'); module.exports = Self => { Self.validatesPresenceOf('typeFk', { @@ -6,10 +7,10 @@ module.exports = Self => { }); Self.observe('before save', async function(ctx) { - let models = Self.app.models; - let changes = ctx.data || ctx.instance; + const models = Self.app.models; + const changes = ctx.data || ctx.instance; - let sample = await models.Sample.findById(changes.typeFk); + const sample = await models.Sample.findById(changes.typeFk); if (sample.hasCompany && !changes.companyFk) throw new UserError('Choose a company'); @@ -25,11 +26,11 @@ module.exports = Self => { // Renew mandate if (mandate) { - let mandateType = await models.MandateType.findOne({ + const mandateType = await models.MandateType.findOne({ where: {name: mandate.type} }); - let oldMandate = await models.Mandate.findOne({ + const oldMandate = await models.Mandate.findOne({ where: { clientFk: changes.clientFk, companyFk: changes.companyFk, @@ -50,10 +51,8 @@ module.exports = Self => { }); } - // Apply workerFk - let filter = {where: {userFk: ctx.options.accessToken.userId}}; - let worker = await Self.app.models.Worker.findOne(filter); + const loopBackContext = LoopBackContext.getCurrentContext(); - changes.workerFk = worker.id; + changes.userFk = loopBackContext.active.accessToken.userId; }); }; diff --git a/modules/client/back/models/sample.json b/modules/client/back/models/sample.json index fcb33a593..011e8bf24 100644 --- a/modules/client/back/models/sample.json +++ b/modules/client/back/models/sample.json @@ -32,9 +32,6 @@ }, "model": { "type": "string" - }, - "property": { - "type": "string" } }, "scopes": { diff --git a/modules/entry/back/methods/entry/entryOrderPdf.js b/modules/entry/back/methods/entry/entryOrderPdf.js new file mode 100644 index 000000000..e6d37fdb6 --- /dev/null +++ b/modules/entry/back/methods/entry/entryOrderPdf.js @@ -0,0 +1,54 @@ +const {Report} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('entryOrderPdf', { + description: 'Returns the entry order pdf', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/entry-order-pdf', + verb: 'GET' + } + }); + + Self.entryOrderPdf = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('entry-order', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; + }; +}; diff --git a/modules/entry/back/models/entry.js b/modules/entry/back/models/entry.js index 573e5b1cb..4854bc3d3 100644 --- a/modules/entry/back/models/entry.js +++ b/modules/entry/back/models/entry.js @@ -6,4 +6,5 @@ module.exports = Self => { require('../methods/entry/importBuys')(Self); require('../methods/entry/importBuysPreview')(Self); require('../methods/entry/lastItemBuys')(Self); + require('../methods/entry/entryOrderPdf')(Self); }; diff --git a/modules/entry/front/descriptor/index.js b/modules/entry/front/descriptor/index.js index 34aa162f9..3452a6d34 100644 --- a/modules/entry/front/descriptor/index.js +++ b/modules/entry/front/descriptor/index.js @@ -86,9 +86,7 @@ class Controller extends Descriptor { } showEntryReport() { - this.vnReport.show('entry-order', { - entryId: this.entry.id - }); + this.vnReport.show(`Entries/${this.id}/entry-order-pdf`); } } diff --git a/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js b/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js new file mode 100644 index 000000000..adcee72e9 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js @@ -0,0 +1,54 @@ +const {Report} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('exportationPdf', { + description: 'Returns the exportation pdf', + accepts: [ + { + arg: 'ref', + type: 'string', + required: true, + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:ref/exportation-pdf', + verb: 'GET' + } + }); + + Self.exportationPdf = async(ctx, ref) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('exportation', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${ref}.pdf"`]; + }; +}; diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js new file mode 100644 index 000000000..0f8b6de7d --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js @@ -0,0 +1,58 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('invoiceEmail', { + description: 'Sends the invoice email with an attached PDF', + accessType: 'WRITE', + accepts: [ + { + arg: 'ref', + type: 'string', + required: true, + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:ref/invoice-email', + verb: 'POST' + } + }); + + Self.invoiceEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('invoice', params); + + return email.send(); + }; +}; diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index c8c97702f..8e9e5bc7a 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -9,4 +9,6 @@ module.exports = Self => { require('../methods/invoiceOut/createManualInvoice')(Self); require('../methods/invoiceOut/globalInvoicing')(Self); require('../methods/invoiceOut/refund')(Self); + require('../methods/invoiceOut/invoiceEmail')(Self); + require('../methods/invoiceOut/exportationPdf')(Self); }; diff --git a/modules/invoiceOut/front/descriptor-menu/index.js b/modules/invoiceOut/front/descriptor-menu/index.js index 2b6d90ebf..78b2cb56e 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.js +++ b/modules/invoiceOut/front/descriptor-menu/index.js @@ -92,10 +92,9 @@ class Controller extends Section { if (!$data.email) return this.vnApp.showError(this.$t(`The email can't be empty`)); - return this.vnEmail.send('invoice', { + return this.vnEmail.send(`InvoiceOuts/${this.invoiceOut.ref}/invoice-email`, { recipientId: this.invoiceOut.client.id, - recipient: $data.email, - refFk: this.invoiceOut.ref + recipient: $data.email }); } @@ -111,7 +110,7 @@ class Controller extends Section { } showExportationLetter() { - this.vnReport.show('exportation', { + this.vnReport.show(`InvoiceOuts/${this.invoiceOut.ref}/exportation-pdf`, { recipientId: this.invoiceOut.client.id, refFk: this.invoiceOut.ref }); diff --git a/modules/supplier/back/methods/supplier/campaignMetricsEmail.js b/modules/supplier/back/methods/supplier/campaignMetricsEmail.js new file mode 100644 index 000000000..4a2c843b8 --- /dev/null +++ b/modules/supplier/back/methods/supplier/campaignMetricsEmail.js @@ -0,0 +1,68 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('campaignMetricsEmail', { + description: 'Sends the campaign metrics email with an attached PDF', + accessType: 'WRITE', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + }, + { + arg: 'from', + type: 'string', + required: true + }, + { + arg: 'to', + type: 'string', + required: true + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/campaign-metrics-email', + verb: 'POST' + } + }); + + Self.campaignMetricsEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('supplier-campaign-metrics', params); + + return email.send(); + }; +}; diff --git a/modules/supplier/back/methods/supplier/campaignMetricsPdf.js b/modules/supplier/back/methods/supplier/campaignMetricsPdf.js new file mode 100644 index 000000000..7bd65ffcb --- /dev/null +++ b/modules/supplier/back/methods/supplier/campaignMetricsPdf.js @@ -0,0 +1,65 @@ +const {Report} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('campaignMetricsPdf', { + description: 'Returns the campaign metrics pdf', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + }, + { + arg: 'from', + type: 'string', + required: true + }, + { + arg: 'to', + type: 'string', + required: true + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/campaign-metrics-pdf', + verb: 'GET' + } + }); + + Self.campaignMetricsPdf = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('supplier-campaign-metrics', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; + }; +}; diff --git a/modules/supplier/back/models/supplier.js b/modules/supplier/back/models/supplier.js index c1be3488f..c9af7b297 100644 --- a/modules/supplier/back/models/supplier.js +++ b/modules/supplier/back/models/supplier.js @@ -8,6 +8,8 @@ module.exports = Self => { require('../methods/supplier/updateFiscalData')(Self); require('../methods/supplier/consumption')(Self); require('../methods/supplier/freeAgencies')(Self); + require('../methods/supplier/campaignMetricsPdf')(Self); + require('../methods/supplier/campaignMetricsEmail')(Self); Self.validatesPresenceOf('name', { message: 'The social name cannot be empty' diff --git a/modules/supplier/front/consumption/index.js b/modules/supplier/front/consumption/index.js index 21a30929d..8de6a1e71 100644 --- a/modules/supplier/front/consumption/index.js +++ b/modules/supplier/front/consumption/index.js @@ -33,7 +33,8 @@ class Controller extends Section { } showReport() { - this.vnReport.show('supplier-campaign-metrics', this.reportParams); + const path = `Suppliers/${this.supplier.id}/campaign-metrics-pdf`; + this.vnReport.show(path, this.reportParams); } sendEmail() { @@ -52,7 +53,9 @@ class Controller extends Section { const params = Object.assign({ recipient: contact.email }, this.reportParams); - this.vnEmail.send('supplier-campaign-metrics', params); + + const path = `Suppliers/${this.supplier.id}/campaign-metrics-email`; + this.vnEmail.send(path, params); } else { const message = this.$t(`This supplier doesn't have a contact with an email address`); this.vnApp.showError(message); diff --git a/modules/travel/back/methods/travel/extraCommunityEmail.js b/modules/travel/back/methods/travel/extraCommunityEmail.js new file mode 100644 index 000000000..251e64746 --- /dev/null +++ b/modules/travel/back/methods/travel/extraCommunityEmail.js @@ -0,0 +1,92 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('extraCommunityEmail', { + description: 'Sends the extra community email with an attached PDF', + accessType: 'WRITE', + accepts: [ + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + }, + { + arg: 'landedTo', + type: 'date' + }, + { + arg: 'shippedFrom', + type: 'date' + }, + { + arg: 'continent', + type: 'string' + }, + { + arg: 'ref', + type: 'string' + }, + { + arg: 'id', + type: 'number' + }, + { + arg: 'agencyModeFk', + type: 'number' + }, + { + arg: 'warehouseOutFk', + type: 'number' + }, + { + arg: 'warehouseInFk', + type: 'number' + }, + { + arg: 'totalEntries', + type: 'number' + }, + { + arg: 'cargoSupplierFk', + type: 'number' + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/extra-community-email', + verb: 'POST' + } + }); + + Self.extraCommunityEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('extra-community', params); + + return email.send(); + }; +}; diff --git a/modules/travel/back/methods/travel/extraCommunityPdf.js b/modules/travel/back/methods/travel/extraCommunityPdf.js new file mode 100644 index 000000000..61a99344d --- /dev/null +++ b/modules/travel/back/methods/travel/extraCommunityPdf.js @@ -0,0 +1,89 @@ +const {Report} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('extraCommunityPdf', { + description: 'Returns the extra community pdf', + accessType: 'READ', + accepts: [ + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + }, + { + arg: 'landedTo', + type: 'date' + }, + { + arg: 'shippedFrom', + type: 'date' + }, + { + arg: 'continent', + type: 'string' + }, + { + arg: 'ref', + type: 'string' + }, + { + arg: 'id', + type: 'number' + }, + { + arg: 'agencyModeFk', + type: 'number' + }, + { + arg: 'warehouseOutFk', + type: 'number' + }, + { + arg: 'warehouseInFk', + type: 'number' + }, + { + arg: 'totalEntries', + type: 'number' + }, + { + arg: 'cargoSupplierFk', + type: 'number' + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/extra-community-pdf', + verb: 'GET' + } + }); + + Self.extraCommunityPdf = async ctx => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('extra-community', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="extra-community.pdf"`]; + }; +}; diff --git a/modules/travel/back/models/travel.js b/modules/travel/back/models/travel.js index 046153ee2..4bcf7b31d 100644 --- a/modules/travel/back/models/travel.js +++ b/modules/travel/back/models/travel.js @@ -10,6 +10,8 @@ module.exports = Self => { require('../methods/travel/extraCommunityFilter')(Self); require('../methods/travel/getAverageDays')(Self); require('../methods/travel/cloneWithEntries')(Self); + require('../methods/travel/extraCommunityPdf')(Self); + require('../methods/travel/extraCommunityEmail')(Self); Self.rewriteDbError(function(err) { if (err.code === 'ER_DUP_ENTRY') diff --git a/modules/travel/front/extra-community/index.js b/modules/travel/front/extra-community/index.js index 461712e9c..a4ac487e6 100644 --- a/modules/travel/front/extra-community/index.js +++ b/modules/travel/front/extra-community/index.js @@ -157,7 +157,7 @@ class Controller extends Section { } showReport() { - this.vnReport.show('extra-community', this.reportParams); + this.vnReport.show(`Travels/extra-community-pdf`, this.reportParams); } } diff --git a/print/templates/email/incoterms-authorization/incoterms-authorization.js b/print/templates/email/incoterms-authorization/incoterms-authorization.js index 051ff554b..977e62101 100755 --- a/print/templates/email/incoterms-authorization/incoterms-authorization.js +++ b/print/templates/email/incoterms-authorization/incoterms-authorization.js @@ -1,4 +1,4 @@ -const Component = require(`vn-report/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); diff --git a/print/templates/email/invoice/assets/css/import.js b/print/templates/email/invoice/assets/css/import.js index b44d6bd37..4b4bb7086 100644 --- a/print/templates/email/invoice/assets/css/import.js +++ b/print/templates/email/invoice/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) .mergeStyles(); diff --git a/print/templates/email/invoice/invoice.js b/print/templates/email/invoice/invoice.js index 6f6ea8683..1d6b9ed7c 100755 --- a/print/templates/email/invoice/invoice.js +++ b/print/templates/email/invoice/invoice.js @@ -1,15 +1,15 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); module.exports = { name: 'invoice', async serverPrefetch() { - this.invoice = await this.fetchInvoice(this.refFk); + this.invoice = await this.fetchInvoice(this.ref); }, methods: { - fetchInvoice(refFk) { - return this.findOneFromDef('invoice', [refFk]); + fetchInvoice(ref) { + return this.findOneFromDef('invoice', [ref]); }, }, components: { @@ -17,7 +17,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - refFk: { + ref: { type: [Number, String], required: true } diff --git a/print/templates/email/supplier-campaign-metrics/assets/css/import.js b/print/templates/email/supplier-campaign-metrics/assets/css/import.js index b44d6bd37..4b4bb7086 100644 --- a/print/templates/email/supplier-campaign-metrics/assets/css/import.js +++ b/print/templates/email/supplier-campaign-metrics/assets/css/import.js @@ -1,8 +1,11 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) .mergeStyles(); 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 3cf290e4d..9cb9210ef 100755 --- a/print/templates/email/supplier-campaign-metrics/supplier-campaign-metrics.js +++ b/print/templates/email/supplier-campaign-metrics/supplier-campaign-metrics.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); @@ -20,7 +20,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - recipientId: { + id: { type: [Number, String], required: true }, diff --git a/print/templates/reports/campaign-metrics/campaign-metrics.js b/print/templates/reports/campaign-metrics/campaign-metrics.js index da7cdd9ae..b60a2b7eb 100755 --- a/print/templates/reports/campaign-metrics/campaign-metrics.js +++ b/print/templates/reports/campaign-metrics/campaign-metrics.js @@ -26,7 +26,8 @@ module.exports = { props: { id: { type: [Number, String], - required: true + required: true, + description: 'The client id' }, from: { required: true 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 de56c2079..f7d21a2d3 100755 --- a/print/templates/reports/claim-pickup-order/claim-pickup-order.js +++ b/print/templates/reports/claim-pickup-order/claim-pickup-order.js @@ -37,7 +37,8 @@ module.exports = { props: { id: { type: [Number, String], - required: true + required: true, + description: 'The claim id' } } }; 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 dd8a30ff9..80c83b494 100755 --- a/print/templates/reports/client-debt-statement/client-debt-statement.js +++ b/print/templates/reports/client-debt-statement/client-debt-statement.js @@ -70,7 +70,8 @@ module.exports = { props: { id: { type: [Number, String], - required: true + required: true, + description: 'The client id' }, from: { required: true diff --git a/print/templates/reports/delivery-note/delivery-note.js b/print/templates/reports/delivery-note/delivery-note.js index d92329ac8..1037e5129 100755 --- a/print/templates/reports/delivery-note/delivery-note.js +++ b/print/templates/reports/delivery-note/delivery-note.js @@ -128,7 +128,8 @@ module.exports = { props: { id: { type: [Number, String], - required: true + required: true, + description: 'The ticket id' }, type: { type: String, diff --git a/print/templates/reports/driver-route/driver-route.js b/print/templates/reports/driver-route/driver-route.js index 41aa9f811..2de3d5192 100755 --- a/print/templates/reports/driver-route/driver-route.js +++ b/print/templates/reports/driver-route/driver-route.js @@ -45,7 +45,8 @@ module.exports = { props: { id: { type: [Number, String], - required: true + required: true, + description: 'The route id' } } }; diff --git a/print/templates/reports/entry-order/assets/css/import.js b/print/templates/reports/entry-order/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/entry-order/assets/css/import.js +++ b/print/templates/reports/entry-order/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/entry-order/entry-order.js b/print/templates/reports/entry-order/entry-order.js index 52a56bf03..ff4a65e0c 100755 --- a/print/templates/reports/entry-order/entry-order.js +++ b/print/templates/reports/entry-order/entry-order.js @@ -1,13 +1,13 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); module.exports = { name: 'entry-order', async serverPrefetch() { - this.supplier = await this.fetchSupplier(this.entryId); - this.entry = await this.fetchEntry(this.entryId); - this.buys = await this.fetchBuys(this.entryId); + this.supplier = await this.fetchSupplier(this.id); + this.entry = await this.fetchEntry(this.id); + this.buys = await this.fetchBuys(this.id); if (!this.entry) throw new Error('Something went wrong'); @@ -16,14 +16,14 @@ module.exports = { return {totalBalance: 0.00}; }, methods: { - fetchSupplier(entryId) { - return this.findOneFromDef('supplier', [entryId]); + fetchSupplier(id) { + return this.findOneFromDef('supplier', [id]); }, - fetchEntry(entryId) { - return this.findOneFromDef('entry', [entryId]); + fetchEntry(id) { + return this.findOneFromDef('entry', [id]); }, - fetchBuys(entryId) { - return this.rawSqlFromDef('buys', [entryId]); + fetchBuys(id) { + return this.rawSqlFromDef('buys', [id]); }, getTotal() { let total = 0.00; @@ -39,9 +39,10 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - entryId: { + id: { type: [Number, String], - required: true + required: true, + description: 'The entry id' } } }; diff --git a/print/templates/reports/exportation/assets/css/import.js b/print/templates/reports/exportation/assets/css/import.js index a2a9334cb..37a98dfdd 100644 --- a/print/templates/reports/exportation/assets/css/import.js +++ b/print/templates/reports/exportation/assets/css/import.js @@ -1,8 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, - `${appPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/exportation/exportation.html b/print/templates/reports/exportation/exportation.html index f08af2cdb..252999467 100644 --- a/print/templates/reports/exportation/exportation.html +++ b/print/templates/reports/exportation/exportation.html @@ -31,9 +31,9 @@

({{$t('signature')}})

-

{{$t('signer.name')}}: JUAN VICENTE FERRER ROIG
-
{{$t('signer.ID')}}: 73943586N
-
{{$t('signer.position')}}: ADMINISTRADOR
+
{{$t('signer.name')}}: {{company.manager}}
+
{{$t('signer.ID')}}: {{company.managerFi}}
+
{{$t('signer.position')}}: {{$t('manager')}}

diff --git a/print/templates/reports/exportation/exportation.js b/print/templates/reports/exportation/exportation.js index a7e018c48..511b719f3 100755 --- a/print/templates/reports/exportation/exportation.js +++ b/print/templates/reports/exportation/exportation.js @@ -1,18 +1,20 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); module.exports = { name: 'exportation', async serverPrefetch() { - this.invoice = await this.fetchInvoice(this.refFk); + this.invoice = await this.fetchInvoice(this.ref); if (!this.invoice) throw new Error('Something went wrong'); + + this.company = await this.findOneFromDef('company', [this.invoice.companyFk]); }, methods: { - fetchInvoice(refFk) { - return this.findOneFromDef('invoice', [refFk]); + fetchInvoice(ref) { + return this.findOneFromDef('invoice', [ref]); } }, computed: { @@ -27,9 +29,10 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - refFk: { + ref: { type: [Number, String], - required: true + required: true, + description: 'The invoice ref' } } }; diff --git a/print/templates/reports/exportation/locale/es.yml b/print/templates/reports/exportation/locale/es.yml index a689e245b..230263cb9 100644 --- a/print/templates/reports/exportation/locale/es.yml +++ b/print/templates/reports/exportation/locale/es.yml @@ -36,6 +36,7 @@ signer: name: Nombre del firmante ID: DNI del firmante position: Cargo del firmante +manager: Gerente months: - 'Enero' - 'Febrero' diff --git a/print/templates/reports/exportation/sql/company.sql b/print/templates/reports/exportation/sql/company.sql new file mode 100644 index 000000000..3ecef2071 --- /dev/null +++ b/print/templates/reports/exportation/sql/company.sql @@ -0,0 +1,9 @@ +SELECT + s.name, + s.city, + cl.name AS manager, + cl.fi AS managerFi +FROM company c + JOIN supplier s ON s.id = c.id + JOIN client cl ON cl.id = c.workerManagerFk +WHERE c.id = ? \ No newline at end of file diff --git a/print/templates/reports/exportation/sql/invoice.sql b/print/templates/reports/exportation/sql/invoice.sql index 7ea55e481..14e1568e2 100644 --- a/print/templates/reports/exportation/sql/invoice.sql +++ b/print/templates/reports/exportation/sql/invoice.sql @@ -1,7 +1,8 @@ SELECT io.id, io.ref, - io.issued + io.issued, + io.companyFk FROM invoiceOut io LEFT JOIN ticket t ON t.refFk = io.ref WHERE t.refFk = ? \ No newline at end of file diff --git a/print/templates/reports/extra-community/assets/css/import.js b/print/templates/reports/extra-community/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/extra-community/assets/css/import.js +++ b/print/templates/reports/extra-community/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/extra-community/extra-community.js b/print/templates/reports/extra-community/extra-community.js index 4dad5dfff..9f009c234 100755 --- a/print/templates/reports/extra-community/extra-community.js +++ b/print/templates/reports/extra-community/extra-community.js @@ -1,7 +1,7 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); -const db = require(`${appPath}/core/database`); +const db = require(`vn-print/core/database`); module.exports = { name: 'extra-community', @@ -82,7 +82,15 @@ module.exports = { let query = this.getSqlFromDef('travels'); query = db.merge(query, where); query = db.merge(query, 'GROUP BY t.id'); - query = db.merge(query, 'ORDER BY `shipped` ASC, `landed` ASC, `travelFk`, `loadPriority`, `agencyModeFk`, `evaNotes`'); + query = db.merge(query, ` + ORDER BY + shipped ASC, + landed ASC, + travelFk, + loadPriority, + agencyModeFk, + evaNotes + `); return this.rawSql(query); }, diff --git a/print/templates/reports/incoterms-authorization/incoterms-authorization.js b/print/templates/reports/incoterms-authorization/incoterms-authorization.js index 54f34136b..26637b8c2 100755 --- a/print/templates/reports/incoterms-authorization/incoterms-authorization.js +++ b/print/templates/reports/incoterms-authorization/incoterms-authorization.js @@ -22,7 +22,8 @@ module.exports = { props: { id: { type: [Number, String], - required: true + required: true, + description: 'The client id' }, companyId: { type: [Number, String], diff --git a/print/templates/reports/invoice-incoterms/assets/css/import.js b/print/templates/reports/invoice-incoterms/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/invoice-incoterms/assets/css/import.js +++ b/print/templates/reports/invoice-incoterms/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/invoice-incoterms/invoice-incoterms.js b/print/templates/reports/invoice-incoterms/invoice-incoterms.js index 99a4e2e73..9c51bec11 100755 --- a/print/templates/reports/invoice-incoterms/invoice-incoterms.js +++ b/print/templates/reports/invoice-incoterms/invoice-incoterms.js @@ -1,13 +1,13 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); module.exports = { name: 'invoice-incoterms', async serverPrefetch() { - this.invoice = await this.fetchInvoice(this.refFk); - this.client = await this.fetchClient(this.refFk); - this.incoterms = await this.fetchIncoterms(this.refFk); + this.invoice = await this.fetchInvoice(this.ref); + this.client = await this.fetchClient(this.ref); + this.incoterms = await this.fetchIncoterms(this.ref); if (!this.invoice) throw new Error('Something went wrong'); @@ -16,14 +16,14 @@ module.exports = { }, methods: { - fetchInvoice(refFk) { - return this.findOneFromDef('invoice', [refFk]); + fetchInvoice(ref) { + return this.findOneFromDef('invoice', [ref]); }, - fetchClient(refFk) { - return this.findOneFromDef('client', [refFk]); + fetchClient(ref) { + return this.findOneFromDef('client', [ref]); }, - fetchIncoterms(refFk) { - return this.findOneFromDef('incoterms', [refFk, refFk, refFk]); + fetchIncoterms(ref) { + return this.findOneFromDef('incoterms', [ref, ref, ref]); } }, components: { @@ -31,9 +31,10 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - refFk: { + ref: { type: [Number, String], - required: true + required: true, + description: 'The invoice ref' } } }; diff --git a/print/templates/reports/invoice/assets/css/import.js b/print/templates/reports/invoice/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/invoice/assets/css/import.js +++ b/print/templates/reports/invoice/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/invoice/invoice.js b/print/templates/reports/invoice/invoice.js index fd4acd4b5..443d6cef7 100755 --- a/print/templates/reports/invoice/invoice.js +++ b/print/templates/reports/invoice/invoice.js @@ -1,5 +1,5 @@ -const Component = require(`${appPath}/core/component`); -const Report = require(`${appPath}/core/report`); +const Component = require(`vn-print/core/component`); +const Report = require(`vn-print/core/report`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); const invoiceIncoterms = new Report('invoice-incoterms'); @@ -7,15 +7,15 @@ const invoiceIncoterms = new Report('invoice-incoterms'); module.exports = { name: 'invoice', async serverPrefetch() { - this.invoice = await this.fetchInvoice(this.refFk); - this.client = await this.fetchClient(this.refFk); - this.taxes = await this.fetchTaxes(this.refFk); - this.intrastat = await this.fetchIntrastat(this.refFk); - this.rectified = await this.fetchRectified(this.refFk); - this.hasIncoterms = await this.fetchHasIncoterms(this.refFk); + this.invoice = await this.fetchInvoice(this.ref); + this.client = await this.fetchClient(this.ref); + this.taxes = await this.fetchTaxes(this.ref); + this.intrastat = await this.fetchIntrastat(this.ref); + this.rectified = await this.fetchRectified(this.ref); + this.hasIncoterms = await this.fetchHasIncoterms(this.ref); - const tickets = await this.fetchTickets(this.refFk); - const sales = await this.fetchSales(this.refFk); + const tickets = await this.fetchTickets(this.ref); + const sales = await this.fetchSales(this.ref); const map = new Map(); @@ -65,29 +65,29 @@ module.exports = { } }, methods: { - fetchInvoice(refFk) { - return this.findOneFromDef('invoice', [refFk]); + fetchInvoice(ref) { + return this.findOneFromDef('invoice', [ref]); }, - fetchClient(refFk) { - return this.findOneFromDef('client', [refFk]); + fetchClient(ref) { + return this.findOneFromDef('client', [ref]); }, - fetchTickets(refFk) { - return this.rawSqlFromDef('tickets', [refFk]); + fetchTickets(ref) { + return this.rawSqlFromDef('tickets', [ref]); }, - fetchSales(refFk) { - return this.rawSqlFromDef('sales', [refFk, refFk]); + fetchSales(ref) { + return this.rawSqlFromDef('sales', [ref, ref]); }, - fetchTaxes(refFk) { - return this.rawSqlFromDef(`taxes`, [refFk]); + fetchTaxes(ref) { + return this.rawSqlFromDef(`taxes`, [ref]); }, - fetchIntrastat(refFk) { - return this.rawSqlFromDef(`intrastat`, [refFk, refFk, refFk]); + fetchIntrastat(ref) { + return this.rawSqlFromDef(`intrastat`, [ref, ref, ref]); }, - fetchRectified(refFk) { - return this.rawSqlFromDef(`rectified`, [refFk]); + fetchRectified(ref) { + return this.rawSqlFromDef(`rectified`, [ref]); }, - fetchHasIncoterms(refFk) { - return this.findValueFromDef(`hasIncoterms`, [refFk]); + fetchHasIncoterms(ref) { + return this.findValueFromDef(`hasIncoterms`, [ref]); }, saleImport(sale) { const price = sale.quantity * sale.price; @@ -115,8 +115,9 @@ module.exports = { 'invoice-incoterms': invoiceIncoterms.build() }, props: { - refFk: { - type: String + ref: { + type: String, + description: 'The invoice ref' } } }; diff --git a/print/templates/reports/item-label/assets/css/import.js b/print/templates/reports/item-label/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/item-label/assets/css/import.js +++ b/print/templates/reports/item-label/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/item-label/item-label.js b/print/templates/reports/item-label/item-label.js index 730d8ad99..09bc38abc 100755 --- a/print/templates/reports/item-label/item-label.js +++ b/print/templates/reports/item-label/item-label.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); const qrcode = require('qrcode'); @@ -6,9 +6,9 @@ const qrcode = require('qrcode'); module.exports = { name: 'item-label', async serverPrefetch() { - this.item = await this.fetchItem(this.itemId, this.warehouseId); - this.tags = await this.fetchItemTags(this.itemId); - this.barcode = await this.getBarcodeBase64(this.itemId); + this.item = await this.fetchItem(this.id, this.warehouseId); + this.tags = await this.fetchItemTags(this.id); + this.barcode = await this.getBarcodeBase64(this.id); if (!this.item) throw new Error('Something went wrong'); @@ -31,16 +31,16 @@ module.exports = { fetchItem(id, warehouseId) { return this.findOneFromDef('item', [id, warehouseId]); }, - fetchItemTags(itemId) { - return this.rawSqlFromDef('itemTags', [itemId]).then(rows => { + fetchItemTags(id) { + return this.rawSqlFromDef('itemTags', [id]).then(rows => { const tags = {}; rows.forEach(row => tags[row.code] = row.value); return tags; }); }, - getBarcodeBase64(itemId) { - return qrcode.toDataURL(itemId, {margin: 0}); + getBarcodeBase64(id) { + return qrcode.toDataURL(id, {margin: 0}); }, packing() { const stems = this.item.stems ? this.item.stems : 1; @@ -52,8 +52,9 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - itemId: { - required: true + id: { + required: true, + description: 'The item id' }, warehouseId: { required: true diff --git a/print/templates/reports/letter-debtor/letter-debtor.js b/print/templates/reports/letter-debtor/letter-debtor.js index 626596297..80d4cba9b 100755 --- a/print/templates/reports/letter-debtor/letter-debtor.js +++ b/print/templates/reports/letter-debtor/letter-debtor.js @@ -64,7 +64,8 @@ module.exports = { props: { id: { type: [Number, String], - required: true + required: true, + description: 'The client id' }, companyId: { type: [Number, String], diff --git a/print/templates/reports/receipt/assets/css/import.js b/print/templates/reports/receipt/assets/css/import.js index a2a9334cb..37a98dfdd 100644 --- a/print/templates/reports/receipt/assets/css/import.js +++ b/print/templates/reports/receipt/assets/css/import.js @@ -1,8 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, - `${appPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/receipt/receipt.js b/print/templates/reports/receipt/receipt.js index d7f4dd6da..401aa1ef3 100755 --- a/print/templates/reports/receipt/receipt.js +++ b/print/templates/reports/receipt/receipt.js @@ -1,22 +1,22 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); module.exports = { name: 'receipt', async serverPrefetch() { - this.client = await this.fetchClient(this.receiptId); - this.receipt = await this.fetchReceipt(this.receiptId); + this.client = await this.fetchClient(this.id); + this.receipt = await this.fetchReceipt(this.id); if (!this.receipt) throw new Error('Something went wrong'); }, methods: { - fetchClient(receiptId) { - return this.findOneFromDef('client', [receiptId]); + fetchClient(id) { + return this.findOneFromDef('client', [id]); }, - fetchReceipt(receiptId) { - return this.findOneFromDef('receipt', [receiptId]); + fetchReceipt(id) { + return this.findOneFromDef('receipt', [id]); } }, components: { @@ -24,9 +24,10 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - receiptId: { + id: { type: [Number, String], - required: true + required: true, + description: 'Receipt id' } } }; diff --git a/print/templates/reports/sepa-core/sepa-core.js b/print/templates/reports/sepa-core/sepa-core.js index 1537a265a..73e0beaaa 100755 --- a/print/templates/reports/sepa-core/sepa-core.js +++ b/print/templates/reports/sepa-core/sepa-core.js @@ -41,7 +41,8 @@ const rptSepaCore = { props: { id: { type: [Number, String], - required: true + required: true, + description: 'The client id' }, companyId: { type: [Number, String], diff --git a/print/templates/reports/supplier-campaign-metrics/assets/css/import.js b/print/templates/reports/supplier-campaign-metrics/assets/css/import.js index fd8796c2b..37a98dfdd 100644 --- a/print/templates/reports/supplier-campaign-metrics/assets/css/import.js +++ b/print/templates/reports/supplier-campaign-metrics/assets/css/import.js @@ -1,9 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); 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 1a460daa9..6a58cbd0e 100755 --- a/print/templates/reports/supplier-campaign-metrics/supplier-campaign-metrics.js +++ b/print/templates/reports/supplier-campaign-metrics/supplier-campaign-metrics.js @@ -1,12 +1,12 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const reportHeader = new Component('report-header'); const reportFooter = new Component('report-footer'); module.exports = { name: 'supplier-campaign-metrics', async serverPrefetch() { - this.supplier = await this.fetchSupplier(this.recipientId); - let entries = await this.fetchEntries(this.recipientId, this.from, this.to); + this.supplier = await this.fetchSupplier(this.id); + let entries = await this.fetchEntries(this.id, this.from, this.to); const entriesId = []; @@ -48,9 +48,10 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - recipientId: { + id: { type: [Number, String], - required: true + required: true, + description: 'The supplier id' }, from: { required: true diff --git a/print/templates/reports/zone/assets/css/import.js b/print/templates/reports/zone/assets/css/import.js index a2a9334cb..37a98dfdd 100644 --- a/print/templates/reports/zone/assets/css/import.js +++ b/print/templates/reports/zone/assets/css/import.js @@ -1,8 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/report.css`, - `${appPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, `${__dirname}/style.css`]) .mergeStyles(); diff --git a/print/templates/reports/zone/zone.js b/print/templates/reports/zone/zone.js index d611e1e53..bbce9df36 100755 --- a/print/templates/reports/zone/zone.js +++ b/print/templates/reports/zone/zone.js @@ -1,20 +1,21 @@ module.exports = { name: 'zone', async serverPrefetch() { - this.zone = await this.fetchZone(this.routeId); + this.zone = await this.fetchZone(this.id); if (!this.zone) throw new Error('Something went wrong'); }, methods: { - fetchZone(routeId) { - return this.findOneFromDef('zone', [routeId]); + fetchZone(id) { + return this.findOneFromDef('zone', [id]); } }, props: { - routeId: { + id: { type: [Number, String], - required: true + required: true, + description: 'The zone id' } } }; From 410e651eddc05d7fecd6bf982db93e71ac56f69a Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 27 Sep 2022 07:24:45 +0200 Subject: [PATCH 10/53] Buyer waste --- .../back/methods/invoiceOut/exportationPdf.js | 1 + .../item/back/methods/item/buyerWasteEmail.js | 59 +++++++++++++++++++ .../buyer-week-waste/assets/css/import.js | 14 +++-- .../buyer-week-waste/buyer-week-waste.js | 2 +- .../campaign-metrics/assets/css/import.js | 2 +- 5 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 modules/item/back/methods/item/buyerWasteEmail.js diff --git a/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js b/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js index adcee72e9..b93729fcd 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js +++ b/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js @@ -3,6 +3,7 @@ const {Report} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('exportationPdf', { description: 'Returns the exportation pdf', + accessType: 'READ', accepts: [ { arg: 'ref', diff --git a/modules/item/back/methods/item/buyerWasteEmail.js b/modules/item/back/methods/item/buyerWasteEmail.js new file mode 100644 index 000000000..f548b39c0 --- /dev/null +++ b/modules/item/back/methods/item/buyerWasteEmail.js @@ -0,0 +1,59 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('buyerWasteEmail', { + description: 'Sends the buyer waste email', + accessType: 'WRITE', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id to send to the recipient preferred language', + required: false + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/buyer-waste-email', + verb: 'POST' + } + }); + + Self.clientDebtStatementEmail = async ctx => { + const args = Object.assign({}, ctx.args); + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const email = new Email('buyer-week-waste', params); + + return email.send(); + }; +}; diff --git a/print/templates/email/buyer-week-waste/assets/css/import.js b/print/templates/email/buyer-week-waste/assets/css/import.js index c742fdf90..7360587f7 100644 --- a/print/templates/email/buyer-week-waste/assets/css/import.js +++ b/print/templates/email/buyer-week-waste/assets/css/import.js @@ -1,9 +1,13 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`, `${__dirname}/style.css`]) .mergeStyles(); + diff --git a/print/templates/email/buyer-week-waste/buyer-week-waste.js b/print/templates/email/buyer-week-waste/buyer-week-waste.js index 9af477e82..05a80ac6a 100755 --- a/print/templates/email/buyer-week-waste/buyer-week-waste.js +++ b/print/templates/email/buyer-week-waste/buyer-week-waste.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); diff --git a/print/templates/email/campaign-metrics/assets/css/import.js b/print/templates/email/campaign-metrics/assets/css/import.js index 89b2afaa5..4b4bb7086 100644 --- a/print/templates/email/campaign-metrics/assets/css/import.js +++ b/print/templates/email/campaign-metrics/assets/css/import.js @@ -8,4 +8,4 @@ module.exports = new Stylesheet([ `${vnPrintPath}/common/css/misc.css`, `${vnPrintPath}/common/css/layout.css`, `${vnPrintPath}/common/css/email.css`]) - .mergeStyles(); \ No newline at end of file + .mergeStyles(); From 660842ca313fbce49b7856680f3ce579f805d9f8 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 27 Sep 2022 14:20:57 +0200 Subject: [PATCH 11/53] Osticket & waste refactor --- back/methods/osticket/osTicketReportEmail.js | 29 +++++++++ back/model-config.json | 3 + back/models/osticket.js | 3 + back/models/osticket.json | 9 +-- back/models/print-config.json | 29 +++++++++ db/changes/10490-august/00-ACL.sql | 4 +- db/changes/10490-august/00-itemConfig.sql | 5 ++ db/changes/10490-august/00-printConfig.sql | 10 +++ db/dump/fixtures.sql | 4 ++ loopback/server/boot/print.js | 2 +- loopback/server/datasources.json | 12 +++- .../item/back/methods/item/buyerWasteEmail.js | 48 +++----------- modules/item/back/model-config.json | 3 + modules/item/back/models/item-config.json | 21 +++++++ modules/item/back/models/item.js | 1 + print/core/database.js | 62 +++++++++---------- print/index.js | 13 ++-- .../osticket-report/assets/css/import.js | 14 +++-- .../email/osticket-report/osticket-report.js | 2 +- 19 files changed, 177 insertions(+), 97 deletions(-) create mode 100644 back/methods/osticket/osTicketReportEmail.js create mode 100644 back/models/osticket.js create mode 100644 back/models/print-config.json create mode 100644 db/changes/10490-august/00-itemConfig.sql create mode 100644 db/changes/10490-august/00-printConfig.sql create mode 100644 modules/item/back/models/item-config.json diff --git a/back/methods/osticket/osTicketReportEmail.js b/back/methods/osticket/osTicketReportEmail.js new file mode 100644 index 000000000..ebb74c385 --- /dev/null +++ b/back/methods/osticket/osTicketReportEmail.js @@ -0,0 +1,29 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('osTicketReportEmail', { + description: 'Sends the buyer waste email', + accessType: 'WRITE', + accepts: [], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/osticket-report-email', + verb: 'POST' + } + }); + + Self.osTicketReportEmail = async ctx => { + const models = Self.app.models; + const printConfig = await models.PrintConfig.findOne(); + + const email = new Email('osticket-report', { + recipient: printConfig.itRecipient, + lang: ctx.req.getLocale() + }); + + return email.send(); + }; +}; diff --git a/back/model-config.json b/back/model-config.json index 343210383..3297d84e5 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -118,6 +118,9 @@ }, "Edi": { "dataSource": "vn" + }, + "PrintConfig": { + "dataSource": "vn" } } diff --git a/back/models/osticket.js b/back/models/osticket.js new file mode 100644 index 000000000..9b13110bb --- /dev/null +++ b/back/models/osticket.js @@ -0,0 +1,3 @@ +module.exports = Self => { + require('../methods/osticket/osTicketReportEmail')(Self); +}; diff --git a/back/models/osticket.json b/back/models/osticket.json index 0c673d004..6ba80b30e 100644 --- a/back/models/osticket.json +++ b/back/models/osticket.json @@ -1,12 +1,5 @@ { "name": "OsTicket", - "base": "VnModel", - "acls": [{ - "property": "validations", - "accessType": "EXECUTE", - "principalType": "ROLE", - "principalId": "$everyone", - "permission": "ALLOW" - }] + "base": "VnModel" } \ No newline at end of file diff --git a/back/models/print-config.json b/back/models/print-config.json new file mode 100644 index 000000000..badb57083 --- /dev/null +++ b/back/models/print-config.json @@ -0,0 +1,29 @@ +{ + "name": "PrintConfig", + "description": "Print config", + "base": "VnModel", + "options": { + "mysql": { + "table": "salix.printConfig" + } + }, + "properties": { + "id": { + "id": true, + "type": "number", + "description": "Identifier" + }, + "itRecipient": { + "type": "string" + }, + "incidencesEmail": { + "type": "string" + } + }, + "acls": [{ + "accessType": "READ", + "principalType": "ROLE", + "principalId": "$everyone", + "permission": "ALLOW" + }] +} \ No newline at end of file diff --git a/db/changes/10490-august/00-ACL.sql b/db/changes/10490-august/00-ACL.sql index 871305709..1c773da89 100644 --- a/db/changes/10490-august/00-ACL.sql +++ b/db/changes/10490-august/00-ACL.sql @@ -23,4 +23,6 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp ('Supplier', 'campaignMetricsEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Travel', 'extraCommunityPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Travel', 'extraCommunityEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), - ('Entry', 'entryOrderPdf', 'READ', 'ALLOW', 'ROLE', 'employee'); \ No newline at end of file + ('Entry', 'entryOrderPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('OsTicket', 'osTicketReportEmail', 'WRITE', 'ALLOW', 'ROLE', 'system'), + ('Item', 'buyerWasteEmail', 'WRITE', 'ALLOW', 'ROLE', 'system'); \ No newline at end of file diff --git a/db/changes/10490-august/00-itemConfig.sql b/db/changes/10490-august/00-itemConfig.sql new file mode 100644 index 000000000..b148aa094 --- /dev/null +++ b/db/changes/10490-august/00-itemConfig.sql @@ -0,0 +1,5 @@ +ALTER TABLE `vn`.`itemConfig` + ADD id int null PRIMARY KEY first; + +ALTER TABLE `vn`.`itemConfig` + ADD wasteRecipients VARCHAR(50) NOT NULL comment 'Weekly waste report schedule recipients'; diff --git a/db/changes/10490-august/00-printConfig.sql b/db/changes/10490-august/00-printConfig.sql new file mode 100644 index 000000000..c5af09ac9 --- /dev/null +++ b/db/changes/10490-august/00-printConfig.sql @@ -0,0 +1,10 @@ +create table `salix`.`printConfig` +( + id int auto_increment, + itRecipient varchar(50) null comment 'IT recipients for report mailing', + incidencesEmail varchar(50) null comment 'CAU destinatary email', + constraint printConfig_pk + primary key (id) +) + comment 'Print service config'; + diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 997ebf92f..c496a5da0 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -13,6 +13,10 @@ INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`) VALUES ('DEFAULT_TOKEN', '1209600', util.VN_CURDATE(), 66); +INSERT INTO `salix`.`printConfig` (`id`, `itRecipient`, `incidencesEmail`) + VALUES + (1, 'it@gotamcity.com', 'incidences@gotamcity.com'); + INSERT INTO `vn`.`ticketConfig` (`id`, `scopeDays`) VALUES ('1', '6'); diff --git a/loopback/server/boot/print.js b/loopback/server/boot/print.js index c2ef243b7..7558c3ef8 100644 --- a/loopback/server/boot/print.js +++ b/loopback/server/boot/print.js @@ -1,3 +1,3 @@ module.exports = function(app) { require('vn-print').boot(app); -}; \ No newline at end of file +}; diff --git a/loopback/server/datasources.json b/loopback/server/datasources.json index 5dade9c2e..5ca920f2e 100644 --- a/loopback/server/datasources.json +++ b/loopback/server/datasources.json @@ -19,8 +19,16 @@ "waitForConnections": true }, "osticket": { - "connector": "memory", - "timezone": "local" + "connector": "vn-mysql", + "database": "osticket", + "debug": false, + "host": "swarm.verdnatura.es", + "port": "40003", + "username": "osticket", + "password": "gfKmwsHJ2Q5H3Aem", + "connectTimeout": 180000, + "acquireTimeout": 60000, + "waitForConnections": true }, "tempStorage": { "name": "tempStorage", diff --git a/modules/item/back/methods/item/buyerWasteEmail.js b/modules/item/back/methods/item/buyerWasteEmail.js index f548b39c0..7f340de0f 100644 --- a/modules/item/back/methods/item/buyerWasteEmail.js +++ b/modules/item/back/methods/item/buyerWasteEmail.js @@ -4,55 +4,25 @@ module.exports = Self => { Self.remoteMethodCtx('buyerWasteEmail', { description: 'Sends the buyer waste email', accessType: 'WRITE', - accepts: [ - { - arg: 'id', - type: 'number', - required: true, - description: 'The client id', - http: {source: 'path'} - }, - { - arg: 'recipient', - type: 'string', - description: 'The recipient email', - required: true, - }, - { - arg: 'replyTo', - type: 'string', - description: 'The sender email to reply to', - required: false - }, - { - arg: 'recipientId', - type: 'number', - description: 'The recipient id to send to the recipient preferred language', - required: false - } - ], + accepts: [], returns: { type: ['object'], root: true }, http: { - path: '/:id/buyer-waste-email', + path: '/buyer-waste-email', verb: 'POST' } }); - Self.clientDebtStatementEmail = async ctx => { - const args = Object.assign({}, ctx.args); - const params = { - recipient: args.recipient, + Self.buyerWasteEmail = async ctx => { + const models = Self.app.models; + const itemConfig = await models.ItemConfig.findOne(); + + const email = new Email('buyer-week-waste', { + recipient: itemConfig.wasteRecipients, lang: ctx.req.getLocale() - }; - - delete args.ctx; - for (const param in args) - params[param] = args[param]; - - const email = new Email('buyer-week-waste', params); + }); return email.send(); }; diff --git a/modules/item/back/model-config.json b/modules/item/back/model-config.json index c31f472be..9737d26fc 100644 --- a/modules/item/back/model-config.json +++ b/modules/item/back/model-config.json @@ -23,6 +23,9 @@ "ItemCategory": { "dataSource": "vn" }, + "ItemConfig": { + "dataSource": "vn" + }, "ItemFamily": { "dataSource": "vn" }, diff --git a/modules/item/back/models/item-config.json b/modules/item/back/models/item-config.json new file mode 100644 index 000000000..364879986 --- /dev/null +++ b/modules/item/back/models/item-config.json @@ -0,0 +1,21 @@ +{ + "name": "ItemConfig", + "base": "VnModel", + "options": { + "mysql": { + "table": "itemConfig" + } + }, + "properties": { + "isItemTagTriggerDisabled": { + "type": "boolean" + }, + "monthToDeactivate": { + "type": "boolean" + }, + "wasteRecipients": { + "type": "string", + "description": "Buyers waste report recipients" + } + } +} \ No newline at end of file diff --git a/modules/item/back/models/item.js b/modules/item/back/models/item.js index 457cce4f2..381033a1e 100644 --- a/modules/item/back/models/item.js +++ b/modules/item/back/models/item.js @@ -15,6 +15,7 @@ module.exports = Self => { require('../methods/item/getWasteByItem')(Self); require('../methods/item/createIntrastat')(Self); require('../methods/item/activeBuyers')(Self); + require('../methods/item/buyerWasteEmail')(Self); Self.validatesPresenceOf('originFk', {message: 'Cannot be blank'}); diff --git a/print/core/database.js b/print/core/database.js index f442cd4ed..43c271ad7 100644 --- a/print/core/database.js +++ b/print/core/database.js @@ -2,21 +2,22 @@ const mysql = require('mysql2'); const config = require('./config.js'); const fs = require('fs-extra'); const path = require('path'); -const PoolConnection = mysql.PoolConnection; module.exports = { - init(pool) { - if (!this.pool) { - // const datasources = config.datasources; - // const pool = mysql.createPoolCluster(); + defaultDataSource: 'vn', - // for (let datasource of datasources) - // pool.add(datasource.name, datasource.options); + init(dataSource) { + if (!this.connections) { + this.connections = []; - this.pool = pool; + const dataSources = ['vn', 'osticket']; + for (const name of dataSources) + this.connections[name] = dataSource[name].connector.client; + + this.pool = this.connections[this.defaultDataSource]; } - return this.pool; + return this.connections; }, /** @@ -25,15 +26,8 @@ module.exports = { * * @return {Object} - Pool connection */ - getConnection(name = 'default') { - let pool = this.pool; - return new Promise((resolve, reject) => { - pool.getConnection(name, function(error, connection) { - if (error) return reject(error); - - resolve(connection); - }); - }); + getConnection(name = this.defaultDataSource) { + return this.connections[name]; }, /** @@ -44,9 +38,12 @@ module.exports = { * * @return {Object} - Result promise */ - rawSql(query, params) { + rawSql(query, params, connection) { return new Promise((resolve, reject) => { - this.pool.query(query, params, (error, rows) => { + let db = this.getConnection(); + if (connection) db = connection; + + db.query(query, params, (error, rows) => { if (error) return reject(error); resolve(rows); }); @@ -71,23 +68,25 @@ module.exports = { * Returns the first row from a given raw sql * @param {String} query - The raw SQL query * @param {Object} params - Parameterized values + * @param {Object} connection - Optional pool connection * * @return {Object} - Result promise */ - findOne(query, params) { - return this.rawSql(query, params).then(([row]) => row); + findOne(query, params, connection) { + return this.rawSql(query, params, connection) + .then(([row]) => row); }, /** * Returns the first row from a given SQL file * @param {String} queryName - The SQL file name * @param {Object} params - Parameterized values + * @param {Object} connection - Optional pool connection * * @return {Object} - Result promise */ - findOneFromDef(queryName, params) { - console.log(path.resolve('queryName')); - return this.rawSqlFromDef(queryName, params) + findOneFromDef(queryName, params, connection) { + return this.rawSqlFromDef(queryName, params, connection) .then(([row]) => row); }, @@ -95,11 +94,12 @@ module.exports = { * Returns the first property from a given raw sql * @param {String} query - The raw SQL query * @param {Object} params - Parameterized values + * @param {Object} connection - Optional pool connection * * @return {Object} - Result promise */ - findValue(query, params) { - return this.findOne(query, params).then(row => { + findValue(query, params, connection) { + return this.findOne(query, params, connection).then(row => { return Object.values(row)[0]; }); }, @@ -108,13 +108,13 @@ module.exports = { * Returns the first property from a given SQL file * @param {String} queryName - The SQL file name * @param {Object} params - Parameterized values + * @param {Object} connection - Optional pool connection * * @return {Object} - Result promise */ - findValueFromDef(queryName, params) { - return this.findOneFromDef(queryName, params).then(row => { - return Object.values(row)[0]; - }); + findValueFromDef(queryName, params, connection) { + return this.findOneFromDef(queryName, params, connection) + .then(row => Object.values(row)[0]); }, /** diff --git a/print/index.js b/print/index.js index c25df6ae1..89ab33aa4 100644 --- a/print/index.js +++ b/print/index.js @@ -8,13 +8,8 @@ const componentsPath = path.resolve(__dirname, './core/components'); module.exports = { async boot(app) { // Init database instance - const conn = app.dataSources.vn.connector.client; - conn.query('SELECT 1', function(error, rows) { - if (error) return error; - console.log(rows); - }); - // console.log(app.dataSource.vn.connector.executeStmt('SELECT 1')); - require('./core/database').init(conn); + + require('./core/database').init(app.dataSources); require('./core/smtp').init(); require('./core/mixins'); require('./core/filters'); @@ -24,11 +19,11 @@ module.exports = { componentsDir.forEach(componentName => { const componentDir = path.join(componentsPath, '/', componentName); const assetsDir = `${componentDir}/assets`; - + app.use(`/api/${componentName}/assets`, express.static(assetsDir)); }); - /** + /** * Serve static files */ const templatesDir = fs.readdirSync(templatesPath); diff --git a/print/templates/email/osticket-report/assets/css/import.js b/print/templates/email/osticket-report/assets/css/import.js index c742fdf90..7360587f7 100644 --- a/print/templates/email/osticket-report/assets/css/import.js +++ b/print/templates/email/osticket-report/assets/css/import.js @@ -1,9 +1,13 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`, + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`, `${__dirname}/style.css`]) .mergeStyles(); + diff --git a/print/templates/email/osticket-report/osticket-report.js b/print/templates/email/osticket-report/osticket-report.js index 45fadd4f1..48e2202f8 100755 --- a/print/templates/email/osticket-report/osticket-report.js +++ b/print/templates/email/osticket-report/osticket-report.js @@ -1,4 +1,4 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); From d7ab95fcc84f5a9f9de7a07fb20de46a139bce13 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 27 Sep 2022 15:00:12 +0200 Subject: [PATCH 12/53] closure --- .../ticket/back/methods/ticket/closeAll.js | 80 +++++++++++++++++++ print/core/directives/index.js | 2 - print/core/directives/pin.js | 9 --- print/index.js | 1 - 4 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 modules/ticket/back/methods/ticket/closeAll.js delete mode 100644 print/core/directives/index.js delete mode 100644 print/core/directives/pin.js diff --git a/modules/ticket/back/methods/ticket/closeAll.js b/modules/ticket/back/methods/ticket/closeAll.js new file mode 100644 index 000000000..c0d4e6714 --- /dev/null +++ b/modules/ticket/back/methods/ticket/closeAll.js @@ -0,0 +1,80 @@ + +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.remoteMethodCtx('closeAll', { + description: 'Makes the closure process from all warehouses', + accessType: 'WRITE', + accepts: [], + returns: { + type: 'object', + root: true + }, + http: { + path: `/close-all`, + verb: 'POST' + } + }); + + Self.closeAll = async ctx => { + const toDate = new Date(); + toDate.setDate(toDate.getDate() - 1); + + const todayMinDate = new Date(); + minDate.setHours(0, 0, 0, 0); + + const todayMaxDate = new Date(); + maxDate.setHours(23, 59, 59, 59); + + // Prevent closure for current day + if (toDate >= todayMinDate && toDate <= todayMaxDate) + throw new UserError('You cannot close tickets for today'); + + const tickets = await Self.rawSql(` + SELECT + t.id, + t.clientFk, + t.companyFk, + c.name clientName, + c.email recipient, + c.salesPersonFk, + c.isToBeMailed, + c.hasToInvoice, + co.hasDailyInvoice, + eu.email salesPersonEmail + FROM ticket t + JOIN agencyMode am ON am.id = t.agencyModeFk + JOIN warehouse wh ON wh.id = t.warehouseFk AND wh.hasComission + JOIN ticketState ts ON ts.ticketFk = t.id + JOIN alertLevel al ON al.id = ts.alertLevel + JOIN client c ON c.id = t.clientFk + JOIN province p ON p.id = c.provinceFk + JOIN country co ON co.id = p.countryFk + LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk + WHERE al.code = 'PACKED' + AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) + AND util.dayEnd(?) + AND t.refFk IS NULL + GROUP BY t.id`, [toDate, toDate]); + + console.log(tickets); + + // await closure.start(tickets, response.locals); + + // await db.rawSql(` + // UPDATE ticket t + // JOIN ticketState ts ON t.id = ts.ticketFk + // JOIN alertLevel al ON al.id = ts.alertLevel + // JOIN agencyMode am ON am.id = t.agencyModeFk + // JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk + // JOIN zone z ON z.id = t.zoneFk + // SET t.routeFk = NULL + // WHERE DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) + // AND util.dayEnd(?) + // AND al.code NOT IN('DELIVERED','PACKED') + // AND t.routeFk + // AND z.name LIKE '%MADRID%'`, [toDate, toDate]); + + return true; + }; +}; diff --git a/print/core/directives/index.js b/print/core/directives/index.js deleted file mode 100644 index 3ba4d8895..000000000 --- a/print/core/directives/index.js +++ /dev/null @@ -1,2 +0,0 @@ -// Import global directives -require('./pin'); diff --git a/print/core/directives/pin.js b/print/core/directives/pin.js deleted file mode 100644 index bf4bb6e6e..000000000 --- a/print/core/directives/pin.js +++ /dev/null @@ -1,9 +0,0 @@ -// DIRECTIVES NOT WORKING -const Vue = require('vue'); -Vue.directive('pin', { - bind: function(el, binding, vnode) { - el.style.position = 'fixed'; - el.style.top = binding.value + 'px'; - el.style.backgroundColor = 'red'; - } -}); diff --git a/print/index.js b/print/index.js index 89ab33aa4..4323f0e9f 100644 --- a/print/index.js +++ b/print/index.js @@ -13,7 +13,6 @@ module.exports = { require('./core/smtp').init(); require('./core/mixins'); require('./core/filters'); - require('./core/directives'); const componentsDir = fs.readdirSync(componentsPath); componentsDir.forEach(componentName => { From fe5eb3e13d798ab3fac1802e1f440bd9d7e20d1a Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 29 Sep 2022 07:35:20 +0200 Subject: [PATCH 13/53] Changes --- loopback/locale/es.json | 3 +- loopback/server/datasources.json | 12 +- .../back/methods/invoiceOut/createPdf.js | 59 +++--- .../back/methods/invoiceOut/exportationPdf.js | 8 +- .../back/methods/invoiceOut/invoiceEmail.js | 4 +- .../ticket/back/methods/ticket/closeAll.js | 95 +++++----- .../back/methods/ticket/closeByTicket.js | 0 modules/ticket/back/methods/ticket/closure.js | 179 ++++++++++++++++++ modules/ticket/back/models/ticket.js | 1 + .../methods/travel/extraCommunityEmail.js | 2 +- .../methods/travel/extraCommunityFilter.js | 2 +- .../back/methods/travel/extraCommunityPdf.js | 2 +- print/core/database.js | 1 - print/index.js | 7 +- .../delivery-note-link.html | 4 +- .../incoterms-authorization.js | 3 +- print/templates/email/invoice/invoice.js | 8 +- .../reports/exportation/exportation.js | 8 +- .../extra-community/extra-community.js | 2 +- .../invoice-incoterms/invoice-incoterms.js | 20 +- print/templates/reports/invoice/invoice.js | 50 ++--- 21 files changed, 315 insertions(+), 155 deletions(-) create mode 100644 modules/ticket/back/methods/ticket/closeByTicket.js create mode 100644 modules/ticket/back/methods/ticket/closure.js diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 07a00024a..77f6f0b00 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -232,5 +232,6 @@ "Fichadas impares": "Fichadas impares", "Descanso diario 12h.": "Descanso diario 12h.", "Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.", - "Dirección incorrecta": "Dirección incorrecta" + "Dirección incorrecta": "Dirección incorrecta", + "You cannot close tickets for today": "You cannot close tickets for today" } \ No newline at end of file diff --git a/loopback/server/datasources.json b/loopback/server/datasources.json index 5ca920f2e..5dade9c2e 100644 --- a/loopback/server/datasources.json +++ b/loopback/server/datasources.json @@ -19,16 +19,8 @@ "waitForConnections": true }, "osticket": { - "connector": "vn-mysql", - "database": "osticket", - "debug": false, - "host": "swarm.verdnatura.es", - "port": "40003", - "username": "osticket", - "password": "gfKmwsHJ2Q5H3Aem", - "connectTimeout": 180000, - "acquireTimeout": 60000, - "waitForConnections": true + "connector": "memory", + "timezone": "local" }, "tempStorage": { "name": "tempStorage", diff --git a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js index c2fdbcbba..3ab5f526c 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js +++ b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js @@ -1,7 +1,5 @@ const UserError = require('vn-loopback/util/user-error'); -const fs = require('fs-extra'); -const path = require('path'); -const axios = require('axios'); +const {Report, storage} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('createPdf', { @@ -27,9 +25,7 @@ module.exports = Self => { Self.createPdf = async function(ctx, id, options) { const models = Self.app.models; - const headers = ctx.req.headers; - const origin = headers.origin; - const auth = ctx.req.accessToken; + const userId = ctx.req.accessToken.userId; if (process.env.NODE_ENV == 'test') throw new UserError(`Action not allowed on the test environment`); @@ -45,10 +41,9 @@ module.exports = Self => { myOptions.transaction = tx; } - let fileSrc; try { const invoiceOut = await Self.findById(id, null, myOptions); - const hasInvoicing = await models.Account.hasRole(auth.userId, 'invoicing', myOptions); + const hasInvoicing = await models.Account.hasRole(userId, 'invoicing', myOptions); if (invoiceOut.hasPdf && !hasInvoicing) throw new UserError(`You don't have enough privileges`); @@ -57,35 +52,27 @@ module.exports = Self => { hasPdf: true }, myOptions); - return axios.get(`${origin}/api/report/invoice`, { - responseType: 'stream', - params: { - authorization: auth.id, - refFk: invoiceOut.ref - } - }).then(async response => { - 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); - - await fs.mkdir(src, {recursive: true}); - - if (tx) await tx.commit(); - - response.data.pipe(fs.createWriteStream(fileSrc)); - }).catch(async e => { - if (fs.existsSync(fileSrc)) - await fs.unlink(fileSrc); - - throw e; + const invoiceReport = new Report('invoice', { + reference: invoiceOut.ref, + recipientId: invoiceOut.clientFk }); + 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 + }); + + if (tx) await tx.commit(); } catch (e) { if (tx) await tx.rollback(); throw e; diff --git a/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js b/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js index b93729fcd..e947c5144 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js +++ b/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js @@ -6,7 +6,7 @@ module.exports = Self => { accessType: 'READ', accepts: [ { - arg: 'ref', + arg: 'reference', type: 'string', required: true, http: {source: 'path'} @@ -34,12 +34,12 @@ module.exports = Self => { } ], http: { - path: '/:ref/exportation-pdf', + path: '/:reference/exportation-pdf', verb: 'GET' } }); - Self.exportationPdf = async(ctx, ref) => { + Self.exportationPdf = async(ctx, reference) => { const args = Object.assign({}, ctx.args); const params = {lang: ctx.req.getLocale()}; @@ -50,6 +50,6 @@ module.exports = Self => { const report = new Report('exportation', params); const stream = await report.toPdfStream(); - return [stream, 'application/pdf', `filename="doc-${ref}.pdf"`]; + return [stream, 'application/pdf', `filename="doc-${reference}.pdf"`]; }; }; diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js index 0f8b6de7d..83564e3ab 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js @@ -6,7 +6,7 @@ module.exports = Self => { accessType: 'WRITE', accepts: [ { - arg: 'ref', + arg: 'reference', type: 'string', required: true, http: {source: 'path'} @@ -35,7 +35,7 @@ module.exports = Self => { root: true }, http: { - path: '/:ref/invoice-email', + path: '/:reference/invoice-email', verb: 'POST' } }); diff --git a/modules/ticket/back/methods/ticket/closeAll.js b/modules/ticket/back/methods/ticket/closeAll.js index c0d4e6714..7483d657a 100644 --- a/modules/ticket/back/methods/ticket/closeAll.js +++ b/modules/ticket/back/methods/ticket/closeAll.js @@ -1,8 +1,9 @@ const UserError = require('vn-loopback/util/user-error'); +const closure = require('./closure'); module.exports = Self => { - Self.remoteMethodCtx('closeAll', { + Self.remoteMethod('closeAll', { description: 'Makes the closure process from all warehouses', accessType: 'WRITE', accepts: [], @@ -16,64 +17,62 @@ module.exports = Self => { } }); - Self.closeAll = async ctx => { + Self.closeAll = async() => { const toDate = new Date(); - toDate.setDate(toDate.getDate() - 1); + // toDate.setDate(toDate.getDate() - 1); const todayMinDate = new Date(); - minDate.setHours(0, 0, 0, 0); + todayMinDate.setHours(0, 0, 0, 0); const todayMaxDate = new Date(); - maxDate.setHours(23, 59, 59, 59); + todayMaxDate.setHours(23, 59, 59, 59); // Prevent closure for current day - if (toDate >= todayMinDate && toDate <= todayMaxDate) - throw new UserError('You cannot close tickets for today'); + // if (toDate >= todayMinDate && toDate <= todayMaxDate) + // throw new UserError('You cannot close tickets for today'); const tickets = await Self.rawSql(` - SELECT - t.id, - t.clientFk, - t.companyFk, - c.name clientName, - c.email recipient, - c.salesPersonFk, - c.isToBeMailed, - c.hasToInvoice, - co.hasDailyInvoice, - eu.email salesPersonEmail - FROM ticket t - JOIN agencyMode am ON am.id = t.agencyModeFk - JOIN warehouse wh ON wh.id = t.warehouseFk AND wh.hasComission - JOIN ticketState ts ON ts.ticketFk = t.id - JOIN alertLevel al ON al.id = ts.alertLevel - JOIN client c ON c.id = t.clientFk - JOIN province p ON p.id = c.provinceFk - JOIN country co ON co.id = p.countryFk - LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk - WHERE al.code = 'PACKED' - AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) - AND util.dayEnd(?) - AND t.refFk IS NULL - GROUP BY t.id`, [toDate, toDate]); + SELECT + t.id, + t.clientFk, + t.companyFk, + c.name clientName, + c.email recipient, + c.salesPersonFk, + c.isToBeMailed, + c.hasToInvoice, + co.hasDailyInvoice, + eu.email salesPersonEmail + FROM ticket t + JOIN agencyMode am ON am.id = t.agencyModeFk + JOIN warehouse wh ON wh.id = t.warehouseFk AND wh.hasComission + JOIN ticketState ts ON ts.ticketFk = t.id + JOIN alertLevel al ON al.id = ts.alertLevel + JOIN client c ON c.id = t.clientFk + JOIN province p ON p.id = c.provinceFk + JOIN country co ON co.id = p.countryFk + LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk + WHERE al.code = 'PACKED' + AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) + AND util.dayEnd(?) + GROUP BY t.id + `, [toDate, toDate]); - console.log(tickets); + await closure(Self, tickets); - // await closure.start(tickets, response.locals); - - // await db.rawSql(` - // UPDATE ticket t - // JOIN ticketState ts ON t.id = ts.ticketFk - // JOIN alertLevel al ON al.id = ts.alertLevel - // JOIN agencyMode am ON am.id = t.agencyModeFk - // JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk - // JOIN zone z ON z.id = t.zoneFk - // SET t.routeFk = NULL - // WHERE DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) - // AND util.dayEnd(?) - // AND al.code NOT IN('DELIVERED','PACKED') - // AND t.routeFk - // AND z.name LIKE '%MADRID%'`, [toDate, toDate]); + await Self.rawSql(` + UPDATE ticket t + JOIN ticketState ts ON t.id = ts.ticketFk + JOIN alertLevel al ON al.id = ts.alertLevel + JOIN agencyMode am ON am.id = t.agencyModeFk + JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk + JOIN zone z ON z.id = t.zoneFk + SET t.routeFk = NULL + WHERE DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) + AND util.dayEnd(?) + AND al.code NOT IN('DELIVERED','PACKED') + AND t.routeFk + AND z.name LIKE '%MADRID%'`, [toDate, toDate]); return true; }; diff --git a/modules/ticket/back/methods/ticket/closeByTicket.js b/modules/ticket/back/methods/ticket/closeByTicket.js new file mode 100644 index 000000000..e69de29bb diff --git a/modules/ticket/back/methods/ticket/closure.js b/modules/ticket/back/methods/ticket/closure.js new file mode 100644 index 000000000..3cbc85f96 --- /dev/null +++ b/modules/ticket/back/methods/ticket/closure.js @@ -0,0 +1,179 @@ +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(Self, tickets, reqArgs = {}) { + if (tickets.length == 0) return; + + const failedtickets = []; + for (const ticket of tickets) { + try { + await Self.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id]); + + 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]); + + 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 + storage.write(stream, { + type: 'invoice', + path: `${year}/${month}/${day}`, + fileName: fileName + }); + + await Self.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 = { + 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]); + + if (firstOrder == 1) { + const args = { + id: ticket.clientFk, + recipientId: ticket.clientFk, + recipient: ticket.recipient, + replyTo: ticket.salesPersonEmail + }; + + const email = new Email('incoterms-authorization', args); + await email.send(); + + const sample = await Self.rawSql( + `SELECT id + FROM sample + WHERE code = 'incoterms-authorization' + `); + + await Self.rawSql(` + INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?) + `, [ticket.clientFk, sample.id, ticket.companyFk]); + } + } catch (error) { + // Domain not found + if (error.responseCode == 450) + return invalidEmail(ticket); + + // Save tickets on a list of failed ids + failedtickets.push({ + id: ticket.id, + stacktrace: error + }); + } + } + + // Send email with failed tickets + if (failedtickets.length > 0) { + let body = 'This following tickets have failed:

'; + + 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 function invalidEmail(ticket) { + await Self.rawSql(`UPDATE client SET email = NULL WHERE id = ?`, [ + ticket.clientFk + ]); + + const oldInstance = `{"email": "${ticket.recipient}"}`; + const newInstance = `{"email": ""}`; + await Self.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/modules/ticket/back/models/ticket.js b/modules/ticket/back/models/ticket.js index 2ccdbb0bf..3e445294d 100644 --- a/modules/ticket/back/models/ticket.js +++ b/modules/ticket/back/models/ticket.js @@ -30,6 +30,7 @@ module.exports = Self => { require('../methods/ticket/refund')(Self); require('../methods/ticket/deliveryNotePdf')(Self); require('../methods/ticket/deliveryNoteEmail')(Self); + require('../methods/ticket/closeAll')(Self); Self.observe('before save', async function(ctx) { const loopBackContext = LoopBackContext.getCurrentContext(); diff --git a/modules/travel/back/methods/travel/extraCommunityEmail.js b/modules/travel/back/methods/travel/extraCommunityEmail.js index 251e64746..dd93ed905 100644 --- a/modules/travel/back/methods/travel/extraCommunityEmail.js +++ b/modules/travel/back/methods/travel/extraCommunityEmail.js @@ -36,7 +36,7 @@ module.exports = Self => { type: 'string' }, { - arg: 'ref', + arg: 'reference', type: 'string' }, { diff --git a/modules/travel/back/methods/travel/extraCommunityFilter.js b/modules/travel/back/methods/travel/extraCommunityFilter.js index feb16d052..e5433bac8 100644 --- a/modules/travel/back/methods/travel/extraCommunityFilter.js +++ b/modules/travel/back/methods/travel/extraCommunityFilter.js @@ -54,7 +54,7 @@ module.exports = Self => { description: 'The totalEntries filter' }, { - arg: 'ref', + arg: 'reference', type: 'string', description: 'The reference' }, diff --git a/modules/travel/back/methods/travel/extraCommunityPdf.js b/modules/travel/back/methods/travel/extraCommunityPdf.js index 61a99344d..a68e5cd09 100644 --- a/modules/travel/back/methods/travel/extraCommunityPdf.js +++ b/modules/travel/back/methods/travel/extraCommunityPdf.js @@ -24,7 +24,7 @@ module.exports = Self => { type: 'string' }, { - arg: 'ref', + arg: 'reference', type: 'string' }, { diff --git a/print/core/database.js b/print/core/database.js index 43c271ad7..0e81806f2 100644 --- a/print/core/database.js +++ b/print/core/database.js @@ -1,7 +1,6 @@ const mysql = require('mysql2'); const config = require('./config.js'); const fs = require('fs-extra'); -const path = require('path'); module.exports = { defaultDataSource: 'vn', diff --git a/print/index.js b/print/index.js index 4323f0e9f..484aba00e 100644 --- a/print/index.js +++ b/print/index.js @@ -40,8 +40,9 @@ module.exports = { return true; }, - smtp: require('./core/smtp'), - db: require('./core/database'), Email: require('./core/email'), - Report: require('./core/report') + Report: require('./core/report'), + storage: require('./core/storage'), + smtp: require('./core/smtp'), + db: require('./core/database') }; diff --git a/print/templates/email/delivery-note-link/delivery-note-link.html b/print/templates/email/delivery-note-link/delivery-note-link.html index ab58cbb24..1d4906261 100644 --- a/print/templates/email/delivery-note-link/delivery-note-link.html +++ b/print/templates/email/delivery-note-link/delivery-note-link.html @@ -30,7 +30,7 @@

{{ $t('title') }}

{{$t('dear')}}

-

+

@@ -38,7 +38,7 @@

{{$t('copyLink')}}

diff --git a/print/templates/email/incoterms-authorization/incoterms-authorization.js b/print/templates/email/incoterms-authorization/incoterms-authorization.js index 977e62101..f8db74e0e 100755 --- a/print/templates/email/incoterms-authorization/incoterms-authorization.js +++ b/print/templates/email/incoterms-authorization/incoterms-authorization.js @@ -17,7 +17,8 @@ module.exports = { props: { id: { type: [Number, String], - required: true + required: true, + description: 'The client id' }, companyId: { type: [Number, String], diff --git a/print/templates/email/invoice/invoice.js b/print/templates/email/invoice/invoice.js index 1d6b9ed7c..fe66062aa 100755 --- a/print/templates/email/invoice/invoice.js +++ b/print/templates/email/invoice/invoice.js @@ -5,11 +5,11 @@ const emailFooter = new Component('email-footer'); module.exports = { name: 'invoice', async serverPrefetch() { - this.invoice = await this.fetchInvoice(this.ref); + this.invoice = await this.fetchInvoice(this.reference); }, methods: { - fetchInvoice(ref) { - return this.findOneFromDef('invoice', [ref]); + fetchInvoice(reference) { + return this.findOneFromDef('invoice', [reference]); }, }, components: { @@ -17,7 +17,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - ref: { + reference: { type: [Number, String], required: true } diff --git a/print/templates/reports/exportation/exportation.js b/print/templates/reports/exportation/exportation.js index 511b719f3..630baf421 100755 --- a/print/templates/reports/exportation/exportation.js +++ b/print/templates/reports/exportation/exportation.js @@ -5,7 +5,7 @@ const reportFooter = new Component('report-footer'); module.exports = { name: 'exportation', async serverPrefetch() { - this.invoice = await this.fetchInvoice(this.ref); + this.invoice = await this.fetchInvoice(this.reference); if (!this.invoice) throw new Error('Something went wrong'); @@ -13,8 +13,8 @@ module.exports = { this.company = await this.findOneFromDef('company', [this.invoice.companyFk]); }, methods: { - fetchInvoice(ref) { - return this.findOneFromDef('invoice', [ref]); + fetchInvoice(reference) { + return this.findOneFromDef('invoice', [reference]); } }, computed: { @@ -29,7 +29,7 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - ref: { + reference: { type: [Number, String], required: true, description: 'The invoice ref' diff --git a/print/templates/reports/extra-community/extra-community.js b/print/templates/reports/extra-community/extra-community.js index 9f009c234..dec89648a 100755 --- a/print/templates/reports/extra-community/extra-community.js +++ b/print/templates/reports/extra-community/extra-community.js @@ -107,7 +107,7 @@ module.exports = { 'landedTo', 'shippedFrom', 'continent', - 'ref', + 'reference', 'id', 'agencyModeFk', 'warehouseOutFk', diff --git a/print/templates/reports/invoice-incoterms/invoice-incoterms.js b/print/templates/reports/invoice-incoterms/invoice-incoterms.js index 9c51bec11..3dbe76ac3 100755 --- a/print/templates/reports/invoice-incoterms/invoice-incoterms.js +++ b/print/templates/reports/invoice-incoterms/invoice-incoterms.js @@ -5,9 +5,9 @@ const reportFooter = new Component('report-footer'); module.exports = { name: 'invoice-incoterms', async serverPrefetch() { - this.invoice = await this.fetchInvoice(this.ref); - this.client = await this.fetchClient(this.ref); - this.incoterms = await this.fetchIncoterms(this.ref); + this.invoice = await this.fetchInvoice(this.reference); + this.client = await this.fetchClient(this.reference); + this.incoterms = await this.fetchIncoterms(this.reference); if (!this.invoice) throw new Error('Something went wrong'); @@ -16,14 +16,14 @@ module.exports = { }, methods: { - fetchInvoice(ref) { - return this.findOneFromDef('invoice', [ref]); + fetchInvoice(reference) { + return this.findOneFromDef('invoice', [reference]); }, - fetchClient(ref) { - return this.findOneFromDef('client', [ref]); + fetchClient(reference) { + return this.findOneFromDef('client', [reference]); }, - fetchIncoterms(ref) { - return this.findOneFromDef('incoterms', [ref, ref, ref]); + fetchIncoterms(reference) { + return this.findOneFromDef('incoterms', [reference, reference, reference]); } }, components: { @@ -31,7 +31,7 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - ref: { + reference: { type: [Number, String], required: true, description: 'The invoice ref' diff --git a/print/templates/reports/invoice/invoice.js b/print/templates/reports/invoice/invoice.js index 443d6cef7..db94a7a12 100755 --- a/print/templates/reports/invoice/invoice.js +++ b/print/templates/reports/invoice/invoice.js @@ -7,15 +7,15 @@ const invoiceIncoterms = new Report('invoice-incoterms'); module.exports = { name: 'invoice', async serverPrefetch() { - this.invoice = await this.fetchInvoice(this.ref); - this.client = await this.fetchClient(this.ref); - this.taxes = await this.fetchTaxes(this.ref); - this.intrastat = await this.fetchIntrastat(this.ref); - this.rectified = await this.fetchRectified(this.ref); - this.hasIncoterms = await this.fetchHasIncoterms(this.ref); + this.invoice = await this.fetchInvoice(this.reference); + this.client = await this.fetchClient(this.reference); + this.taxes = await this.fetchTaxes(this.reference); + this.intrastat = await this.fetchIntrastat(this.reference); + this.rectified = await this.fetchRectified(this.reference); + this.hasIncoterms = await this.fetchHasIncoterms(this.reference); - const tickets = await this.fetchTickets(this.ref); - const sales = await this.fetchSales(this.ref); + const tickets = await this.fetchTickets(this.reference); + const sales = await this.fetchSales(this.reference); const map = new Map(); @@ -65,29 +65,29 @@ module.exports = { } }, methods: { - fetchInvoice(ref) { - return this.findOneFromDef('invoice', [ref]); + fetchInvoice(reference) { + return this.findOneFromDef('invoice', [reference]); }, - fetchClient(ref) { - return this.findOneFromDef('client', [ref]); + fetchClient(reference) { + return this.findOneFromDef('client', [reference]); }, - fetchTickets(ref) { - return this.rawSqlFromDef('tickets', [ref]); + fetchTickets(reference) { + return this.rawSqlFromDef('tickets', [reference]); }, - fetchSales(ref) { - return this.rawSqlFromDef('sales', [ref, ref]); + fetchSales(reference) { + return this.rawSqlFromDef('sales', [reference, reference]); }, - fetchTaxes(ref) { - return this.rawSqlFromDef(`taxes`, [ref]); + fetchTaxes(reference) { + return this.rawSqlFromDef(`taxes`, [reference]); }, - fetchIntrastat(ref) { - return this.rawSqlFromDef(`intrastat`, [ref, ref, ref]); + fetchIntrastat(reference) { + return this.rawSqlFromDef(`intrastat`, [reference, reference, reference]); }, - fetchRectified(ref) { - return this.rawSqlFromDef(`rectified`, [ref]); + fetchRectified(reference) { + return this.rawSqlFromDef(`rectified`, [reference]); }, - fetchHasIncoterms(ref) { - return this.findValueFromDef(`hasIncoterms`, [ref]); + fetchHasIncoterms(reference) { + return this.findValueFromDef(`hasIncoterms`, [reference]); }, saleImport(sale) { const price = sale.quantity * sale.price; @@ -115,7 +115,7 @@ module.exports = { 'invoice-incoterms': invoiceIncoterms.build() }, props: { - ref: { + reference: { type: String, description: 'The invoice ref' } From 5aec280adbd0fbf357c0720436d2cc94bd2c1c94 Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 29 Sep 2022 09:07:18 +0200 Subject: [PATCH 14/53] Closure migration --- db/dump/fixtures.sql | 23 +++--- .../ticket/back/methods/ticket/closeAll.js | 11 ++- .../back/methods/ticket/closeByAgency.js | 79 +++++++++++++++++++ .../back/methods/ticket/closeByRoute.js | 75 ++++++++++++++++++ .../back/methods/ticket/closeByTicket.js | 60 ++++++++++++++ modules/ticket/back/models/ticket-methods.js | 34 ++++++++ modules/ticket/back/models/ticket.js | 31 +------- .../reports/driver-route/driver-route.html | 2 +- 8 files changed, 271 insertions(+), 44 deletions(-) create mode 100644 modules/ticket/back/methods/ticket/closeByAgency.js create mode 100644 modules/ticket/back/methods/ticket/closeByRoute.js create mode 100644 modules/ticket/back/models/ticket-methods.js diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index c496a5da0..5e4e43924 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -920,16 +920,19 @@ INSERT INTO `vn`.`expeditionStateType`(`id`, `description`, `code`) INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `workerFk`, `externalId`, `packagingFk`, `stateTypeFk`) VALUES - (1, 1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 15, 1, 18, 'UR9000006041', 94, 1), - (2, 1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 16, 2, 18, 'UR9000006041', 94, 1), - (3, 1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), NULL, 3, 18, 'UR9000006041', 94, 2), - (4, 1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), NULL, 4, 18, 'UR9000006041', 94, 2), - (5, 1, 2, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), NULL, 1, 18, NULL, 94, 3), - (6, 7, 3, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), NULL, 1, 18, NULL, 94, 3), - (7, 2, 4, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), NULL, 1, 18, NULL, 94, NULL), - (8, 3, 5, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), NULL, 1, 18, NULL, 94, 1), - (9, 3, 6, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), NULL, 1, 18, NULL, 94, 2), - (10, 7, 7, 71, NOW(), NULL, 1, 18, NULL, 94, 3); + (1, 1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 15, 1, 18, 'UR9000006041', 94, 1), + (2, 1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 16, 2, 18, 'UR9000006041', 94, 1), + (3, 1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), NULL, 3, 18, 'UR9000006041', 94, 2), + (4, 1, 1, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), NULL, 4, 18, 'UR9000006041', 94, 2), + (5, 1, 2, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), NULL, 1, 18, NULL, 94, 3), + (6, 7, 3, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), NULL, 1, 18, NULL, 94, 3), + (7, 2, 4, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -3 MONTH), NULL, 1, 18, NULL, 94, NULL), + (8, 3, 5, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -4 MONTH), NULL, 1, 18, NULL, 94, 1), + (9, 3, 6, 71, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), NULL, 1, 18, NULL, 94, 2), + (10, 7, 7, 71, NOW(), NULL, 1, 18, NULL, 94, 3), + (11, 7, 8, 71, NOW(), NULL, 1, 18, NULL, 94, 3), + (12, 7, 9, 71, NOW(), NULL, 1, 18, NULL, 94, 3), + (13, 1, 10, 71, NOW(), NULL, 1, 18, NULL, 94, 3); INSERT INTO `vn`.`expeditionState`(`id`, `created`, `expeditionFk`, `typeFk`, `userFk`) diff --git a/modules/ticket/back/methods/ticket/closeAll.js b/modules/ticket/back/methods/ticket/closeAll.js index 7483d657a..bcd583b1b 100644 --- a/modules/ticket/back/methods/ticket/closeAll.js +++ b/modules/ticket/back/methods/ticket/closeAll.js @@ -19,7 +19,7 @@ module.exports = Self => { Self.closeAll = async() => { const toDate = new Date(); - // toDate.setDate(toDate.getDate() - 1); + toDate.setDate(toDate.getDate() - 1); const todayMinDate = new Date(); todayMinDate.setHours(0, 0, 0, 0); @@ -28,8 +28,8 @@ module.exports = Self => { todayMaxDate.setHours(23, 59, 59, 59); // Prevent closure for current day - // if (toDate >= todayMinDate && toDate <= todayMaxDate) - // throw new UserError('You cannot close tickets for today'); + if (toDate >= todayMinDate && toDate <= todayMaxDate) + throw new UserError('You cannot close tickets for today'); const tickets = await Self.rawSql(` SELECT @@ -55,6 +55,7 @@ module.exports = Self => { WHERE al.code = 'PACKED' AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) AND util.dayEnd(?) + AND t.refFk IS NULL GROUP BY t.id `, [toDate, toDate]); @@ -74,6 +75,8 @@ module.exports = Self => { AND t.routeFk AND z.name LIKE '%MADRID%'`, [toDate, toDate]); - return true; + return { + message: 'Success' + }; }; }; diff --git a/modules/ticket/back/methods/ticket/closeByAgency.js b/modules/ticket/back/methods/ticket/closeByAgency.js new file mode 100644 index 000000000..eb1aee349 --- /dev/null +++ b/modules/ticket/back/methods/ticket/closeByAgency.js @@ -0,0 +1,79 @@ +const closure = require('./closure'); + +module.exports = Self => { + Self.remoteMethodCtx('closeByAgency', { + description: 'Makes the closure process by agency mode', + accessType: 'WRITE', + accepts: [ + { + arg: 'agencyModeFk', + type: ['number'], + required: true, + description: 'The agencies mode ids', + }, + { + arg: 'warehouseFk', + type: 'number', + description: 'The ticket warehouse id', + required: true + }, + { + arg: 'to', + type: 'date', + description: 'Max closure date', + required: true + } + ], + returns: { + type: 'object', + root: true + }, + http: { + path: `/close-by-agency`, + verb: 'POST' + } + }); + + Self.closeByAgency = async ctx => { + const args = ctx.args; + + const tickets = await Self.rawSql(` + SELECT + t.id, + t.clientFk, + t.companyFk, + c.name clientName, + c.email recipient, + c.salesPersonFk, + c.isToBeMailed, + c.hasToInvoice, + co.hasDailyInvoice, + eu.email salesPersonEmail + FROM expedition e + JOIN ticket t ON t.id = e.ticketFk + JOIN ticketState ts ON ts.ticketFk = t.id + JOIN alertLevel al ON al.id = ts.alertLevel + JOIN client c ON c.id = t.clientFk + JOIN province p ON p.id = c.provinceFk + JOIN country co ON co.id = p.countryFk + LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk + WHERE al.code = 'PACKED' + AND t.agencyModeFk IN(?) + AND t.warehouseFk = ? + AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) + AND util.dayEnd(?) + AND t.refFk IS NULL + GROUP BY e.ticketFk`, [ + args.agencyModeFk, + args.warehouseFk, + args.to, + args.to + ]); + + await closure(Self, tickets); + + return { + message: 'Success' + }; + }; +}; diff --git a/modules/ticket/back/methods/ticket/closeByRoute.js b/modules/ticket/back/methods/ticket/closeByRoute.js new file mode 100644 index 000000000..58e130b8e --- /dev/null +++ b/modules/ticket/back/methods/ticket/closeByRoute.js @@ -0,0 +1,75 @@ +const closure = require('./closure'); +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('closeByRoute', { + description: 'Makes the closure process by route', + accessType: 'WRITE', + accepts: [ + { + arg: 'routeFk', + type: 'number', + required: true, + description: 'The routes ids', + }, + ], + returns: { + type: 'object', + root: true + }, + http: { + path: `/close-by-route`, + verb: 'POST' + } + }); + + Self.closeByRoute = async ctx => { + const args = ctx.args; + + const tickets = await Self.rawSql(` + SELECT + t.id, + t.clientFk, + t.companyFk, + c.name clientName, + c.email recipient, + c.salesPersonFk, + c.isToBeMailed, + c.hasToInvoice, + co.hasDailyInvoice, + eu.email salesPersonEmail + FROM expedition e + JOIN ticket t ON t.id = e.ticketFk + JOIN ticketState ts ON ts.ticketFk = t.id + JOIN alertLevel al ON al.id = ts.alertLevel + JOIN client c ON c.id = t.clientFk + JOIN province p ON p.id = c.provinceFk + JOIN country co ON co.id = p.countryFk + LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk + WHERE al.code = 'PACKED' + AND t.routeFk = ? + AND t.refFk IS NULL + GROUP BY e.ticketFk`, [args.routeFk]); + + await closure(Self, tickets); + + // Send route report to the agency + const [agencyMail] = await Self.rawSql(` + SELECT am.reportMail + FROM route r + JOIN agencyMode am ON am.id = r.agencyModeFk + WHERE r.id = ?`, [args.routeFk]); + + if (agencyMail) { + const email = new Email('driver-route', { + id: args.routeFk, + recipient: agencyMail + }); + await email.send(); + } + + return { + message: 'Success' + }; + }; +}; diff --git a/modules/ticket/back/methods/ticket/closeByTicket.js b/modules/ticket/back/methods/ticket/closeByTicket.js index e69de29bb..8884897c2 100644 --- a/modules/ticket/back/methods/ticket/closeByTicket.js +++ b/modules/ticket/back/methods/ticket/closeByTicket.js @@ -0,0 +1,60 @@ +const closure = require('./closure'); + +module.exports = Self => { + Self.remoteMethodCtx('closeByTicket', { + description: 'Makes the closure process by ticket', + accessType: 'WRITE', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The ticket id', + http: {source: 'path'} + } + ], + returns: { + type: 'object', + root: true + }, + http: { + path: `/:id/close-by-ticket`, + verb: 'POST' + } + }); + + Self.closeByTicket = async ctx => { + const args = ctx.args; + + const tickets = await Self.rawSql(` + SELECT + t.id, + t.clientFk, + t.companyFk, + c.name clientName, + c.email recipient, + c.salesPersonFk, + c.isToBeMailed, + c.hasToInvoice, + co.hasDailyInvoice, + eu.email salesPersonEmail + FROM expedition e + JOIN ticket t ON t.id = e.ticketFk + JOIN ticketState ts ON ts.ticketFk = t.id + JOIN alertLevel al ON al.id = ts.alertLevel + JOIN client c ON c.id = t.clientFk + JOIN province p ON p.id = c.provinceFk + JOIN country co ON co.id = p.countryFk + LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk + WHERE al.code = 'PACKED' + AND t.id = ? + AND t.refFk IS NULL + GROUP BY e.ticketFk`, [args.id]); + + await closure(Self, tickets); + + return { + message: 'Success' + }; + }; +}; diff --git a/modules/ticket/back/models/ticket-methods.js b/modules/ticket/back/models/ticket-methods.js new file mode 100644 index 000000000..8b8f2bea5 --- /dev/null +++ b/modules/ticket/back/models/ticket-methods.js @@ -0,0 +1,34 @@ +module.exports = function(Self) { + require('../methods/ticket/getVolume')(Self); + require('../methods/ticket/getTotalVolume')(Self); + require('../methods/ticket/summary')(Self); + require('../methods/ticket/priceDifference')(Self); + require('../methods/ticket/componentUpdate')(Self); + require('../methods/ticket/new')(Self); + require('../methods/ticket/isEditable')(Self); + require('../methods/ticket/setDeleted')(Self); + require('../methods/ticket/restore')(Self); + require('../methods/ticket/getSales')(Self); + require('../methods/ticket/getSalesPersonMana')(Self); + require('../methods/ticket/filter')(Self); + require('../methods/ticket/canBeInvoiced')(Self); + require('../methods/ticket/makeInvoice')(Self); + require('../methods/ticket/updateEditableTicket')(Self); + require('../methods/ticket/isEmpty')(Self); + require('../methods/ticket/updateDiscount')(Self); + require('../methods/ticket/uploadFile')(Self); + require('../methods/ticket/addSale')(Self); + require('../methods/ticket/transferSales')(Self); + require('../methods/ticket/recalculateComponents')(Self); + require('../methods/ticket/sendSms')(Self); + require('../methods/ticket/isLocked')(Self); + require('../methods/ticket/freightCost')(Self); + require('../methods/ticket/getComponentsSum')(Self); + require('../methods/ticket/refund')(Self); + require('../methods/ticket/deliveryNotePdf')(Self); + require('../methods/ticket/deliveryNoteEmail')(Self); + require('../methods/ticket/closeAll')(Self); + require('../methods/ticket/closeByTicket')(Self); + require('../methods/ticket/closeByAgency')(Self); + require('../methods/ticket/closeByRoute')(Self); +}; diff --git a/modules/ticket/back/models/ticket.js b/modules/ticket/back/models/ticket.js index 3e445294d..c05130552 100644 --- a/modules/ticket/back/models/ticket.js +++ b/modules/ticket/back/models/ticket.js @@ -2,35 +2,8 @@ const LoopBackContext = require('loopback-context'); module.exports = Self => { - require('../methods/ticket/getVolume')(Self); - require('../methods/ticket/getTotalVolume')(Self); - require('../methods/ticket/summary')(Self); - require('../methods/ticket/priceDifference')(Self); - require('../methods/ticket/componentUpdate')(Self); - require('../methods/ticket/new')(Self); - require('../methods/ticket/isEditable')(Self); - require('../methods/ticket/setDeleted')(Self); - require('../methods/ticket/restore')(Self); - require('../methods/ticket/getSales')(Self); - require('../methods/ticket/getSalesPersonMana')(Self); - require('../methods/ticket/filter')(Self); - require('../methods/ticket/canBeInvoiced')(Self); - require('../methods/ticket/makeInvoice')(Self); - require('../methods/ticket/updateEditableTicket')(Self); - require('../methods/ticket/isEmpty')(Self); - require('../methods/ticket/updateDiscount')(Self); - require('../methods/ticket/uploadFile')(Self); - require('../methods/ticket/addSale')(Self); - require('../methods/ticket/transferSales')(Self); - require('../methods/ticket/recalculateComponents')(Self); - require('../methods/ticket/sendSms')(Self); - require('../methods/ticket/isLocked')(Self); - require('../methods/ticket/freightCost')(Self); - require('../methods/ticket/getComponentsSum')(Self); - require('../methods/ticket/refund')(Self); - require('../methods/ticket/deliveryNotePdf')(Self); - require('../methods/ticket/deliveryNoteEmail')(Self); - require('../methods/ticket/closeAll')(Self); + // Methods + require('./ticket-methods')(Self); Self.observe('before save', async function(ctx) { const loopBackContext = LoopBackContext.getCurrentContext(); diff --git a/print/templates/reports/driver-route/driver-route.html b/print/templates/reports/driver-route/driver-route.html index 987c51369..96fb6e957 100644 --- a/print/templates/reports/driver-route/driver-route.html +++ b/print/templates/reports/driver-route/driver-route.html @@ -150,7 +150,7 @@ From 7a7ad6ac5f50869af57e9db0871160e6f1a16726 Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 29 Sep 2022 13:09:44 +0200 Subject: [PATCH 15/53] InvoiceOut_sendQueued --- db/changes/10490-august/00-ACL.sql | 1 + .../back/methods/invoiceOut/sendQueued.js | 133 ++++++++++++++++++ modules/invoiceOut/back/models/invoice-out.js | 1 + 3 files changed, 135 insertions(+) create mode 100644 modules/invoiceOut/back/methods/invoiceOut/sendQueued.js diff --git a/db/changes/10490-august/00-ACL.sql b/db/changes/10490-august/00-ACL.sql index 1c773da89..0a3556a1a 100644 --- a/db/changes/10490-august/00-ACL.sql +++ b/db/changes/10490-august/00-ACL.sql @@ -19,6 +19,7 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp ('Client', 'incotermsAuthorizationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('InvoiceOut', 'invoiceEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('InvoiceOut', 'exportationPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('InvoiceOut', 'sendQueued', 'WRITE', 'ALLOW', 'ROLE', 'system'), ('Supplier', 'campaignMetricsPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Supplier', 'campaignMetricsEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Travel', 'extraCommunityPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), diff --git a/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js b/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js new file mode 100644 index 000000000..846e48c14 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js @@ -0,0 +1,133 @@ +const {Email, Report, storage} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethod('sendQueued', { + description: 'Send all queued invoices', + accessType: 'WRITE', + accepts: [], + returns: { + type: 'object', + root: true + }, + http: { + path: '/send-queued', + verb: 'POST' + } + }); + + Self.sendQueued = async() => { + const invoices = await Self.rawSql(` + SELECT + io.id, + io.clientFk, + io.issued, + io.ref, + c.email recipient, + c.salesPersonFk, + c.isToBeMailed, + c.hasToInvoice, + co.hasDailyInvoice, + eu.email salesPersonEmail + FROM invoiceOut_queue ioq + JOIN invoiceOut io ON io.id = ioq.invoiceFk + JOIN client c ON c.id = io.clientFk + JOIN province p ON p.id = c.provinceFk + JOIN country co ON co.id = p.countryFk + LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk + WHERE status = ''`); + + let invoiceId; + for (const invoiceOut of invoices) { + try { + const tx = await Self.beginTransaction({}); + const myOptions = {transaction: tx}; + + invoiceId = invoiceOut.id; + + const args = { + reference: invoiceOut.ref, + recipientId: invoiceOut.clientFk, + recipient: invoiceOut.recipient, + replyTo: invoiceOut.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 + storage.write(stream, { + type: 'invoice', + path: `${year}/${month}/${day}`, + fileName: fileName + }); + + await Self.rawSql(` + UPDATE invoiceOut + SET hasPdf = true + WHERE id = ?`, + [invoiceOut.id], myOptions); + + const isToBeMailed = invoiceOut.recipient && invoiceOut.salesPersonFk && invoiceOut.isToBeMailed; + + if (isToBeMailed) { + const mailOptions = { + overrideAttachments: true, + attachments: [] + }; + + const invoiceAttachment = { + filename: fileName, + content: stream + }; + + if (invoiceOut.serial == 'E' && invoiceOut.companyCode == 'VNL') { + const exportation = new Report('exportation', args); + const stream = await exportation.toPdfStream(); + const fileName = `CITES-${invoiceOut.ref}.pdf`; + + mailOptions.attachments.push({ + filename: fileName, + content: stream + }); + } + + mailOptions.attachments.push(invoiceAttachment); + + const email = new Email('invoice', args); + await email.send(mailOptions); + } + // Update queue status + const date = new Date(); + await Self.rawSql(` + UPDATE invoiceOut_queue + SET status = "printed", + printed = ? + WHERE invoiceFk = ?`, + [date, invoiceOut.id], myOptions); + + await tx.commit(); + } catch (error) { + await tx.rollback(); + + await Self.rawSql(` + UPDATE invoiceOut_queue + SET status = ? + WHERE invoiceFk = ?`, + [error.message, invoiceId]); + + throw e; + } + } + + return { + message: 'Success' + }; + }; +}; diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index 8e9e5bc7a..f58fe3978 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -11,4 +11,5 @@ module.exports = Self => { require('../methods/invoiceOut/refund')(Self); require('../methods/invoiceOut/invoiceEmail')(Self); require('../methods/invoiceOut/exportationPdf')(Self); + require('../methods/invoiceOut/sendQueued')(Self); }; From 3601881026cabb33242e177cd5f6326085c8a862 Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 29 Sep 2022 14:43:27 +0200 Subject: [PATCH 16/53] Client consumption queue --- db/changes/10490-august/00-ACL.sql | 2 + .../00-clientConsumptionQueue.sql | 9 + .../10490-august/00-invoiceOutQueue.sql | 1 + .../methods/client/consumptionSendQueued.js | 80 ++++++++ modules/client/back/model-config.json | 3 + .../back/models/client-consumption-queue.json | 30 +++ modules/client/back/models/client-methods.js | 1 + modules/client/front/notification/index.js | 12 +- .../back/methods/invoiceOut/sendQueued.js | 2 +- print/methods/closure/closeAll.js | 72 ------- print/methods/closure/closeByAgency.js | 59 ------ print/methods/closure/closeByRoute.js | 62 ------ print/methods/closure/closeByTicket.js | 44 ----- print/methods/closure/closure.js | 181 ------------------ print/methods/closure/index.js | 9 - print/methods/email/email.js | 16 -- print/methods/email/index.js | 7 - print/methods/email/preview.js | 14 -- print/methods/report/document.js | 17 -- print/methods/report/index.js | 7 - print/methods/report/preview.js | 13 -- print/methods/routes.js | 16 -- print/methods/schedule/consumption.js | 58 ------ print/methods/schedule/index.js | 7 - print/methods/schedule/invoice.js | 115 ----------- 25 files changed, 134 insertions(+), 703 deletions(-) create mode 100644 db/changes/10490-august/00-clientConsumptionQueue.sql create mode 100644 db/changes/10490-august/00-invoiceOutQueue.sql create mode 100644 modules/client/back/methods/client/consumptionSendQueued.js create mode 100644 modules/client/back/models/client-consumption-queue.json delete mode 100644 print/methods/closure/closeAll.js delete mode 100644 print/methods/closure/closeByAgency.js delete mode 100644 print/methods/closure/closeByRoute.js delete mode 100644 print/methods/closure/closeByTicket.js delete mode 100644 print/methods/closure/closure.js delete mode 100644 print/methods/closure/index.js delete mode 100644 print/methods/email/email.js delete mode 100644 print/methods/email/index.js delete mode 100644 print/methods/email/preview.js delete mode 100644 print/methods/report/document.js delete mode 100644 print/methods/report/index.js delete mode 100644 print/methods/report/preview.js delete mode 100644 print/methods/schedule/consumption.js delete mode 100644 print/methods/schedule/index.js delete mode 100644 print/methods/schedule/invoice.js diff --git a/db/changes/10490-august/00-ACL.sql b/db/changes/10490-august/00-ACL.sql index 0a3556a1a..d1b7f087c 100644 --- a/db/changes/10490-august/00-ACL.sql +++ b/db/changes/10490-august/00-ACL.sql @@ -1,5 +1,6 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) VALUES + ('ClientConsumptionQueue', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Ticket', 'deliveryNotePdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Ticket', 'deliveryNoteEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'campaignMetricsPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), @@ -17,6 +18,7 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp ('Client', 'clientDebtStatementEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'incotermsAuthorizationHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'incotermsAuthorizationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'consumptionSendQueued', 'WRITE', 'ALLOW', 'ROLE', 'system'), ('InvoiceOut', 'invoiceEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('InvoiceOut', 'exportationPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('InvoiceOut', 'sendQueued', 'WRITE', 'ALLOW', 'ROLE', 'system'), diff --git a/db/changes/10490-august/00-clientConsumptionQueue.sql b/db/changes/10490-august/00-clientConsumptionQueue.sql new file mode 100644 index 000000000..2734d32cc --- /dev/null +++ b/db/changes/10490-august/00-clientConsumptionQueue.sql @@ -0,0 +1,9 @@ +create table `vn`.`clientConsumptionQueue` +( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + params json not null, + queued datetime default current_timestamp() not null, + printed datetime null, + status varchar(50) default '' null +) + comment 'Queue for client consumption PDF mailing'; diff --git a/db/changes/10490-august/00-invoiceOutQueue.sql b/db/changes/10490-august/00-invoiceOutQueue.sql new file mode 100644 index 000000000..52ed4a113 --- /dev/null +++ b/db/changes/10490-august/00-invoiceOutQueue.sql @@ -0,0 +1 @@ +rename table `vn`.`invoiceOut_queue` to `vn`.`invoiceOutQueue`; diff --git a/modules/client/back/methods/client/consumptionSendQueued.js b/modules/client/back/methods/client/consumptionSendQueued.js new file mode 100644 index 000000000..3f551d3d2 --- /dev/null +++ b/modules/client/back/methods/client/consumptionSendQueued.js @@ -0,0 +1,80 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethod('consumptionSendQueued', { + description: 'Send all queued invoices', + accessType: 'WRITE', + accepts: [], + returns: { + type: 'object', + root: true + }, + http: { + path: '/consumption-send-queued', + verb: 'POST' + } + }); + + Self.consumptionSendQueued = async() => { + const queues = await Self.rawSql(` + SELECT + ccq.id, + c.id AS clientFk, + c.email AS clientEmail, + eu.email salesPersonEmail, + REPLACE(json_extract(params, '$.from'), '"', '') AS fromDate, + REPLACE(json_extract(params, '$.to'), '"', '') AS toDate + FROM clientConsumptionQueue ccq + JOIN client c ON ( + JSON_SEARCH( + JSON_ARRAY( + json_extract(params, '$.clients') + ) + , 'all', c.id) IS NOT NULL) + JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk + JOIN ticket t ON t.clientFk = c.id + JOIN sale s ON s.ticketFk = t.id + JOIN item i ON i.id = s.itemFk + JOIN itemType it ON it.id = i.typeFk + WHERE status = '' + AND it.isPackaging = FALSE + AND DATE(t.shipped) BETWEEN + REPLACE(json_extract(params, '$.from'), '"', '') AND + REPLACE(json_extract(params, '$.to'), '"', '') + GROUP BY c.id`); + + for (const queue of queues) { + try { + const args = { + id: queue.clientFk, + recipient: queue.clientEmail, + replyTo: queue.salesPersonEmail, + from: queue.fromDate, + to: queue.toDate + }; + + const email = new Email('campaign-metrics', args); + await email.send(); + + await Self.rawSql(` + UPDATE clientConsumptionQueue + SET status = 'printed', + printed = ? + WHERE id = ?`, + [new Date(), queue.id]); + } catch (error) { + await Self.rawSql(` + UPDATE clientConsumptionQueue + SET status = ? + WHERE id = ?`, + [error.message, queue.id]); + + throw e; + } + } + + return { + message: 'Success' + }; + }; +}; diff --git a/modules/client/back/model-config.json b/modules/client/back/model-config.json index 4feb3b168..b2e600610 100644 --- a/modules/client/back/model-config.json +++ b/modules/client/back/model-config.json @@ -26,6 +26,9 @@ "ClientCreditLimit": { "dataSource": "vn" }, + "ClientConsumptionQueue": { + "dataSource": "vn" + }, "ClientLog": { "dataSource": "vn" }, diff --git a/modules/client/back/models/client-consumption-queue.json b/modules/client/back/models/client-consumption-queue.json new file mode 100644 index 000000000..328af00c5 --- /dev/null +++ b/modules/client/back/models/client-consumption-queue.json @@ -0,0 +1,30 @@ +{ + "name": "ClientConsumptionQueue", + "base": "VnModel", + "options": { + "mysql": { + "table": "clientConsumptionQueue" + } + }, + "properties": { + "params": { + "type": "json" + }, + "queued": { + "type": "date" + }, + "printed": { + "type": "date" + }, + "status": { + "type": "string" + } + }, + "relations": { + "client": { + "type": "belongsTo", + "model": "Client", + "foreignKey": "clientFk" + } + } +} diff --git a/modules/client/back/models/client-methods.js b/modules/client/back/models/client-methods.js index c8b6389c6..bacbea727 100644 --- a/modules/client/back/models/client-methods.js +++ b/modules/client/back/models/client-methods.js @@ -42,4 +42,5 @@ module.exports = Self => { require('../methods/client/creditRequestEmail')(Self); require('../methods/client/incotermsAuthorizationHtml')(Self); require('../methods/client/incotermsAuthorizationEmail')(Self); + require('../methods/client/consumptionSendQueued')(Self); }; diff --git a/modules/client/front/notification/index.js b/modules/client/front/notification/index.js index 336005783..d61c8f771 100644 --- a/modules/client/front/notification/index.js +++ b/modules/client/front/notification/index.js @@ -77,13 +77,15 @@ export default class Controller extends Section { onSendClientConsumption() { const clientIds = this.checked.map(client => client.id); - const params = Object.assign({ - clientIds: clientIds - }, this.campaign); + const params = { + clients: clientIds, + from: this.campaign.from, + to: this.campaign.to + }; - this.$http.post('schedule/consumption', params) + this.$http.post('ClientConsumptionQueues', {params}) .then(() => this.$.filters.hide()) - .then(() => this.vnApp.showSuccess(this.$t('Notifications sent!'))); + .then(() => this.vnApp.showSuccess(this.$t('Notifications queued'))); } exprBuilder(param, value) { diff --git a/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js b/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js index 846e48c14..47bb1db09 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js +++ b/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js @@ -28,7 +28,7 @@ module.exports = Self => { c.hasToInvoice, co.hasDailyInvoice, eu.email salesPersonEmail - FROM invoiceOut_queue ioq + FROM invoiceOutQueue ioq JOIN invoiceOut io ON io.id = ioq.invoiceFk JOIN client c ON c.id = io.clientFk JOIN province p ON p.id = c.provinceFk diff --git a/print/methods/closure/closeAll.js b/print/methods/closure/closeAll.js deleted file mode 100644 index dad8b4569..000000000 --- a/print/methods/closure/closeAll.js +++ /dev/null @@ -1,72 +0,0 @@ -const db = require('vn-print/core/database'); -const closure = require('./closure'); - -module.exports = async function(request, response, next) { - try { - const reqArgs = request.body; - - let toDate = new Date(); - toDate.setDate(toDate.getDate() - 1); - - if (reqArgs.to) toDate = reqArgs.to; - - const todayMinDate = new Date(); - minDate.setHours(0, 0, 0, 0); - - const todayMaxDate = new Date(); - maxDate.setHours(23, 59, 59, 59); - - // Prevent closure for current day - if (toDate >= todayMinDate && toDate <= todayMaxDate) - throw new Error('You cannot close tickets for today'); - - const tickets = await db.rawSql(` - SELECT - t.id, - t.clientFk, - t.companyFk, - c.name clientName, - c.email recipient, - c.salesPersonFk, - c.isToBeMailed, - c.hasToInvoice, - co.hasDailyInvoice, - eu.email salesPersonEmail - FROM ticket t - JOIN agencyMode am ON am.id = t.agencyModeFk - JOIN warehouse wh ON wh.id = t.warehouseFk AND wh.hasComission - JOIN ticketState ts ON ts.ticketFk = t.id - JOIN alertLevel al ON al.id = ts.alertLevel - JOIN client c ON c.id = t.clientFk - JOIN province p ON p.id = c.provinceFk - JOIN country co ON co.id = p.countryFk - LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk - WHERE al.code = 'PACKED' - AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) - AND util.dayEnd(?) - AND t.refFk IS NULL - GROUP BY t.id`, [toDate, toDate]); - - await closure.start(tickets, response.locals); - - await db.rawSql(` - UPDATE ticket t - JOIN ticketState ts ON t.id = ts.ticketFk - JOIN alertLevel al ON al.id = ts.alertLevel - JOIN agencyMode am ON am.id = t.agencyModeFk - JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk - JOIN zone z ON z.id = t.zoneFk - SET t.routeFk = NULL - WHERE DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) - AND util.dayEnd(?) - AND al.code NOT IN('DELIVERED','PACKED') - AND t.routeFk - AND z.name LIKE '%MADRID%'`, [toDate, toDate]); - - response.status(200).json({ - message: 'Success' - }); - } catch (error) { - next(error); - } -}; diff --git a/print/methods/closure/closeByAgency.js b/print/methods/closure/closeByAgency.js deleted file mode 100644 index bbf72f137..000000000 --- a/print/methods/closure/closeByAgency.js +++ /dev/null @@ -1,59 +0,0 @@ -const db = require('vn-print/core/database'); -const closure = require('./closure'); - -module.exports = async function(request, response, next) { - try { - const reqArgs = request.body; - - if (!reqArgs.agencyModeId) - throw new Error('The argument agencyModeId is required'); - - if (!reqArgs.warehouseId) - throw new Error('The argument warehouseId is required'); - - if (!reqArgs.to) - throw new Error('The argument to is required'); - - const agencyIds = reqArgs.agencyModeId.split(','); - const tickets = await db.rawSql(` - SELECT - t.id, - t.clientFk, - t.companyFk, - c.name clientName, - c.email recipient, - c.salesPersonFk, - c.isToBeMailed, - c.hasToInvoice, - co.hasDailyInvoice, - eu.email salesPersonEmail - FROM expedition e - JOIN ticket t ON t.id = e.ticketFk - JOIN ticketState ts ON ts.ticketFk = t.id - JOIN alertLevel al ON al.id = ts.alertLevel - JOIN client c ON c.id = t.clientFk - JOIN province p ON p.id = c.provinceFk - JOIN country co ON co.id = p.countryFk - LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk - WHERE al.code = 'PACKED' - AND t.agencyModeFk IN(?) - AND t.warehouseFk = ? - AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY) - AND util.dayEnd(?) - AND t.refFk IS NULL - GROUP BY e.ticketFk`, [ - agencyIds, - reqArgs.warehouseId, - reqArgs.to, - reqArgs.to - ]); - - await closure.start(tickets, response.locals); - - response.status(200).json({ - message: 'Success' - }); - } catch (error) { - next(error); - } -}; diff --git a/print/methods/closure/closeByRoute.js b/print/methods/closure/closeByRoute.js deleted file mode 100644 index 1f5d571f6..000000000 --- a/print/methods/closure/closeByRoute.js +++ /dev/null @@ -1,62 +0,0 @@ -const db = require('vn-print/core/database'); -const Email = require('vn-print/core/email'); -const closure = require('./closure'); - -module.exports = async function(request, response, next) { - try { - const reqArgs = request.body; - - if (!reqArgs.routeId) - throw new Error('The argument routeId is required'); - - const tickets = await db.rawSql(` - SELECT - t.id, - t.clientFk, - t.companyFk, - c.name clientName, - c.email recipient, - c.salesPersonFk, - c.isToBeMailed, - c.hasToInvoice, - co.hasDailyInvoice, - eu.email salesPersonEmail - FROM expedition e - JOIN ticket t ON t.id = e.ticketFk - JOIN ticketState ts ON ts.ticketFk = t.id - JOIN alertLevel al ON al.id = ts.alertLevel - JOIN client c ON c.id = t.clientFk - JOIN province p ON p.id = c.provinceFk - JOIN country co ON co.id = p.countryFk - LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk - WHERE al.code = 'PACKED' - AND t.routeFk = ? - AND t.refFk IS NULL - GROUP BY e.ticketFk`, [reqArgs.routeId]); - - await closure.start(tickets, response.locals); - - // Send route report to the agency - const agencyMail = await db.findValue(` - SELECT am.reportMail - FROM route r - JOIN agencyMode am ON am.id = r.agencyModeFk - WHERE r.id = ?`, [reqArgs.routeId]); - - if (agencyMail) { - const args = Object.assign({ - routeId: Number.parseInt(reqArgs.routeId), - recipient: agencyMail - }, response.locals); - - const email = new Email('driver-route', args); - await email.send(); - } - - response.status(200).json({ - message: 'Success' - }); - } catch (error) { - next(error); - } -}; diff --git a/print/methods/closure/closeByTicket.js b/print/methods/closure/closeByTicket.js deleted file mode 100644 index 71cadcecf..000000000 --- a/print/methods/closure/closeByTicket.js +++ /dev/null @@ -1,44 +0,0 @@ -const db = require('vn-print/core/database'); -const closure = require('./closure'); - -module.exports = async function(request, response, next) { - try { - const reqArgs = request.body; - - if (!reqArgs.ticketId) - throw new Error('The argument ticketId is required'); - - const tickets = await db.rawSql(` - SELECT - t.id, - t.clientFk, - t.companyFk, - c.name clientName, - c.email recipient, - c.salesPersonFk, - c.isToBeMailed, - c.hasToInvoice, - co.hasDailyInvoice, - eu.email salesPersonEmail - FROM expedition e - JOIN ticket t ON t.id = e.ticketFk - JOIN ticketState ts ON ts.ticketFk = t.id - JOIN alertLevel al ON al.id = ts.alertLevel - JOIN client c ON c.id = t.clientFk - JOIN province p ON p.id = c.provinceFk - JOIN country co ON co.id = p.countryFk - LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk - WHERE al.code = 'PACKED' - AND t.id = ? - AND t.refFk IS NULL - GROUP BY e.ticketFk`, [reqArgs.ticketId]); - - await closure.start(tickets, response.locals); - - response.status(200).json({ - message: 'Success' - }); - } catch (error) { - next(error); - } -}; diff --git a/print/methods/closure/closure.js b/print/methods/closure/closure.js deleted file mode 100644 index 67a2538e8..000000000 --- a/print/methods/closure/closure.js +++ /dev/null @@ -1,181 +0,0 @@ -const db = require('vn-print/core/database'); -const Report = require('vn-print/core/report'); -const Email = require('vn-print/core/email'); -const smtp = require('vn-print/core/smtp'); -const config = require('vn-print/core/config'); -const storage = require('vn-print/core/storage'); - -module.exports = { - async start(tickets, reqArgs) { - if (tickets.length == 0) return; - - const failedtickets = []; - for (const ticket of tickets) { - try { - await db.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id]); - - const invoiceOut = await db.findOne(` - SELECT io.id, io.ref, io.serial, cny.code companyCode, io.issued - FROM ticket t - JOIN invoiceOut io ON io.ref = t.refFk - JOIN company cny ON cny.id = io.companyFk - WHERE t.id = ? - `, [ticket.id]); - - const mailOptions = { - overrideAttachments: true, - attachments: [] - }; - - const isToBeMailed = ticket.recipient && ticket.salesPersonFk && ticket.isToBeMailed; - - if (invoiceOut) { - const args = Object.assign({ - refFk: invoiceOut.ref, - recipientId: ticket.clientFk, - recipient: ticket.recipient, - replyTo: ticket.salesPersonEmail - }, reqArgs); - - const invoiceReport = new Report('invoice', args); - const stream = await invoiceReport.toPdfStream(); - - const issued = invoiceOut.issued; - const year = issued.getFullYear().toString(); - const month = (issued.getMonth() + 1).toString(); - const day = issued.getDate().toString(); - - const fileName = `${year}${invoiceOut.ref}.pdf`; - - // Store invoice - storage.write(stream, { - type: 'invoice', - path: `${year}/${month}/${day}`, - fileName: fileName - }); - - await db.rawSql('UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id]); - - if (isToBeMailed) { - const invoiceAttachment = { - filename: fileName, - content: stream - }; - - if (invoiceOut.serial == 'E' && invoiceOut.companyCode == 'VNL') { - const exportation = new Report('exportation', args); - const stream = await exportation.toPdfStream(); - const fileName = `CITES-${invoiceOut.ref}.pdf`; - - mailOptions.attachments.push({ - filename: fileName, - content: stream - }); - } - - mailOptions.attachments.push(invoiceAttachment); - - const email = new Email('invoice', args); - await email.send(mailOptions); - } - } else if (isToBeMailed) { - const args = Object.assign({ - ticketId: ticket.id, - recipientId: ticket.clientFk, - recipient: ticket.recipient, - replyTo: ticket.salesPersonEmail - }, reqArgs); - - const email = new Email('delivery-note-link', args); - await email.send(); - } - - // Incoterms authorization - const {firstOrder} = await db.findOne(` - SELECT COUNT(*) as firstOrder - FROM ticket t - JOIN client c ON c.id = t.clientFk - WHERE t.clientFk = ? - AND NOT t.isDeleted - AND c.isVies - `, [ticket.clientFk]); - - if (firstOrder == 1) { - const args = Object.assign({ - ticketId: ticket.id, - recipientId: ticket.clientFk, - recipient: ticket.recipient, - replyTo: ticket.salesPersonEmail - }, reqArgs); - - const email = new Email('incoterms-authorization', args); - await email.send(); - - const sample = await db.findOne( - `SELECT id - FROM sample - WHERE code = 'incoterms-authorization'`); - - await db.rawSql(` - INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?) - `, [ticket.clientFk, sample.id, ticket.companyFk]); - } - } catch (error) { - // Domain not found - if (error.responseCode == 450) - return invalidEmail(ticket); - - // Save tickets on a list of failed ids - failedtickets.push({ - id: ticket.id, - stacktrace: error - }); - } - } - - // Send email with failed tickets - if (failedtickets.length > 0) { - let body = 'This following tickets have failed:

'; - - 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 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/index.js b/print/methods/closure/index.js deleted file mode 100644 index 2d5eaf4c5..000000000 --- a/print/methods/closure/index.js +++ /dev/null @@ -1,9 +0,0 @@ -const express = require('express'); -const router = new express.Router(); - -router.post('/all', require('./closeAll')); -router.post('/by-ticket', require('./closeByTicket')); -router.post('/by-agency', require('./closeByAgency')); -router.post('/by-route', require('./closeByRoute')); - -module.exports = router; diff --git a/print/methods/email/email.js b/print/methods/email/email.js deleted file mode 100644 index 5d6882f7d..000000000 --- a/print/methods/email/email.js +++ /dev/null @@ -1,16 +0,0 @@ -const Email = require('vn-print/core/email'); - -module.exports = async function(request, response, next) { - try { - const templateName = request.params.name; - const args = response.locals; - const email = new Email(templateName, args); - await email.send(); - - response.status(200).json({ - message: 'Sent' - }); - } catch (error) { - next(error); - } -}; diff --git a/print/methods/email/index.js b/print/methods/email/index.js deleted file mode 100644 index 10c2d2325..000000000 --- a/print/methods/email/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const express = require('express'); -const router = new express.Router(); - -router.get('/:name', require('./email')); -router.get('/:name/preview', require('./preview')); - -module.exports = router; diff --git a/print/methods/email/preview.js b/print/methods/email/preview.js deleted file mode 100644 index e6a1aaf35..000000000 --- a/print/methods/email/preview.js +++ /dev/null @@ -1,14 +0,0 @@ -const Email = require('vn-print/core/email'); - -module.exports = async function(request, response, next) { - try { - const templateName = request.params.name; - const args = Object.assign({isPreview: true}, response.locals); - const email = new Email(templateName, args); - const template = await email.render(); - - response.send(template); - } catch (error) { - next(error); - } -}; diff --git a/print/methods/report/document.js b/print/methods/report/document.js deleted file mode 100644 index b24abf4ac..000000000 --- a/print/methods/report/document.js +++ /dev/null @@ -1,17 +0,0 @@ -const Report = require('vn-print/core/report'); - -module.exports = async function(request, response, next) { - try { - const reportName = request.params.name; - const args = response.locals; - const report = new Report(reportName, args); - const stream = await report.toPdfStream(); - const fileName = await report.getFileName(); - - response.setHeader('Content-type', 'application/pdf'); - response.setHeader('Content-Disposition', `inline; filename="${fileName}"`); - response.end(stream); - } catch (error) { - next(error); - } -}; diff --git a/print/methods/report/index.js b/print/methods/report/index.js deleted file mode 100644 index c422c76df..000000000 --- a/print/methods/report/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const express = require('express'); -const router = new express.Router(); - -router.get('/:name', require('./document')); -router.get('/:name/preview', require('./preview')); - -module.exports = router; diff --git a/print/methods/report/preview.js b/print/methods/report/preview.js deleted file mode 100644 index 0d6ad6f43..000000000 --- a/print/methods/report/preview.js +++ /dev/null @@ -1,13 +0,0 @@ -const Report = require('vn-print/core/report'); - -module.exports = async function(request, response, next) { - try { - const reportName = request.params.name; - const report = new Report(reportName, request.query); - const template = await report.render(); - - response.send(template); - } catch (error) { - next(error); - } -}; diff --git a/print/methods/routes.js b/print/methods/routes.js index 28671b3da..42043409b 100644 --- a/print/methods/routes.js +++ b/print/methods/routes.js @@ -1,22 +1,6 @@ module.exports = [ - { - url: '/api/report', - cb: require('./report') - }, - { - url: '/api/email', - cb: require('./email') - }, { url: '/api/csv', cb: require('./csv') - }, - { - url: '/api/closure', - cb: require('./closure') - }, - { - url: '/api/schedule', - cb: require('./schedule') } ]; diff --git a/print/methods/schedule/consumption.js b/print/methods/schedule/consumption.js deleted file mode 100644 index 39d39105b..000000000 --- a/print/methods/schedule/consumption.js +++ /dev/null @@ -1,58 +0,0 @@ -const db = require('vn-print/core/database'); -const Email = require('vn-print/core/email'); - -module.exports = async function(request, response, next) { - try { - const reqArgs = request.body; - - if (!reqArgs.clientIds) - throw new Error('The argument clientIds is required'); - if (!reqArgs.from) - throw new Error('The argument from is required'); - if (!reqArgs.to) - throw new Error('The argument to is required'); - - response.status(200).json({ - message: 'Success' - }); - - const clientIds = reqArgs.clientIds; - - const clients = await db.rawSql(` - SELECT - c.id, - c.email, - eu.email salesPersonEmail - FROM client c - JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk - JOIN ticket t ON t.clientFk = c.id - JOIN sale s ON s.ticketFk = t.id - JOIN item i ON i.id = s.itemFk - JOIN itemType it ON it.id = i.typeFk - WHERE c.id IN(?) - AND it.isPackaging = FALSE - AND DATE(t.shipped) BETWEEN ? AND ? - GROUP BY c.id`, [clientIds, reqArgs.from, reqArgs.to]); - - const clientData = new Map(); - for (const client of clients) - clientData.set(client.id, client); - - for (const clientId of reqArgs.clientIds) { - const client = clientData.get(clientId); - - if (client) { - const args = Object.assign({ - recipientId: clientId, - recipient: client.email, - replyTo: client.salesPersonEmail - }, response.locals); - - const email = new Email('campaign-metrics', args); - await email.send(); - } - } - } catch (error) { - next(error); - } -}; diff --git a/print/methods/schedule/index.js b/print/methods/schedule/index.js deleted file mode 100644 index 05d54b2ed..000000000 --- a/print/methods/schedule/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const express = require('express'); -const router = new express.Router(); - -router.post('/consumption', require('./consumption')); -router.post('/invoice', require('./invoice')); - -module.exports = router; diff --git a/print/methods/schedule/invoice.js b/print/methods/schedule/invoice.js deleted file mode 100644 index 87c696075..000000000 --- a/print/methods/schedule/invoice.js +++ /dev/null @@ -1,115 +0,0 @@ -const db = require('vn-print/core/database'); -const Email = require('vn-print/core/email'); -const Report = require('vn-print/core/report'); -const storage = require('vn-print/core/storage'); - -module.exports = async function(request, response, next) { - try { - response.status(200).json({ - message: 'Success' - }); - - const invoices = await db.rawSql(` - SELECT - io.id, - io.clientFk, - io.issued, - io.ref, - c.email recipient, - c.salesPersonFk, - c.isToBeMailed, - c.hasToInvoice, - co.hasDailyInvoice, - eu.email salesPersonEmail - FROM invoiceOut_queue ioq - JOIN invoiceOut io ON io.id = ioq.invoiceFk - JOIN client c ON c.id = io.clientFk - JOIN province p ON p.id = c.provinceFk - JOIN country co ON co.id = p.countryFk - LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk - WHERE status = ''`); - - let connection; - let invoiceId; - for (const invoiceOut of invoices) { - try { - invoiceId = invoiceOut.id; - connection = await db.getConnection(); - connection.query('START TRANSACTION'); - - const args = Object.assign({ - refFk: invoiceOut.ref, - recipientId: invoiceOut.clientFk, - recipient: invoiceOut.recipient, - replyTo: invoiceOut.salesPersonEmail - }, response.locals); - - const invoiceReport = new Report('invoice', args); - const stream = await invoiceReport.toPdfStream(); - - const issued = invoiceOut.issued; - const year = issued.getFullYear().toString(); - const month = (issued.getMonth() + 1).toString(); - const day = issued.getDate().toString(); - - const fileName = `${year}${invoiceOut.ref}.pdf`; - - // Store invoice - storage.write(stream, { - type: 'invoice', - path: `${year}/${month}/${day}`, - fileName: fileName - }); - - connection.query('UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id]); - - const isToBeMailed = invoiceOut.recipient && invoiceOut.salesPersonFk && invoiceOut.isToBeMailed; - - if (isToBeMailed) { - const mailOptions = { - overrideAttachments: true, - attachments: [] - }; - - const invoiceAttachment = { - filename: fileName, - content: stream - }; - - if (invoiceOut.serial == 'E' && invoiceOut.companyCode == 'VNL') { - const exportation = new Report('exportation', args); - const stream = await exportation.toPdfStream(); - const fileName = `CITES-${invoiceOut.ref}.pdf`; - - mailOptions.attachments.push({ - filename: fileName, - content: stream - }); - } - - mailOptions.attachments.push(invoiceAttachment); - - const email = new Email('invoice', args); - await email.send(mailOptions); - } - // Update queue status - const date = new Date(); - sql = `UPDATE invoiceOut_queue - SET status = "printed", - printed = ? - WHERE invoiceFk = ?`; - connection.query(sql, [date, invoiceOut.id]); - connection.query('COMMIT'); - } catch (error) { - connection.query('ROLLBACK'); - connection.release(); - sql = `UPDATE invoiceOut_queue - SET status = ? - WHERE invoiceFk = ?`; - await db.rawSql(sql, [error.message, invoiceId]); - } - } - } catch (error) { - next(error); - } -}; From ccec38ef97cfa96c8a973b51cd0618beceb4e270 Mon Sep 17 00:00:00 2001 From: joan Date: Thu, 29 Sep 2022 14:49:08 +0200 Subject: [PATCH 17/53] Renamed table --- modules/invoiceOut/back/methods/invoiceOut/sendQueued.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js b/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js index 47bb1db09..a1730ac81 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js +++ b/modules/invoiceOut/back/methods/invoiceOut/sendQueued.js @@ -106,7 +106,7 @@ module.exports = Self => { // Update queue status const date = new Date(); await Self.rawSql(` - UPDATE invoiceOut_queue + UPDATE invoiceOutQueue SET status = "printed", printed = ? WHERE invoiceFk = ?`, @@ -117,7 +117,7 @@ module.exports = Self => { await tx.rollback(); await Self.rawSql(` - UPDATE invoiceOut_queue + UPDATE invoiceOutQueue SET status = ? WHERE invoiceFk = ?`, [error.message, invoiceId]); From 3b0f1efbf4bb390d5217f73573157be2b900c1b3 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 30 Sep 2022 13:54:20 +0200 Subject: [PATCH 18/53] ACL's --- db/changes/10490-august/00-ACL.sql | 22 +++++++++++-------- db/changes/10490-august/00-sample.sql | 2 +- modules/claim/front/descriptor/index.html | 2 -- .../methods/client/campaignMetricsEmail.js | 1 + .../back/methods/client/campaignMetricsPdf.js | 1 + .../client/clientDebtStatementEmail.js | 1 + .../methods/client/clientDebtStatementHtml.js | 1 + .../back/methods/client/clientWelcomeEmail.js | 1 + .../back/methods/client/clientWelcomeHtml.js | 1 + .../back/methods/client/creditRequestEmail.js | 1 + .../back/methods/client/creditRequestHtml.js | 1 + .../methods/client/letterDebtorNdEmail.js | 1 + .../back/methods/client/letterDebtorNdHtml.js | 1 + .../methods/client/letterDebtorStEmail.js | 1 + .../back/methods/client/letterDebtorStHtml.js | 1 + .../back/methods/client/printerSetupEmail.js | 1 + .../back/methods/client/printerSetupHtml.js | 1 + .../back/methods/client/sepaCoreEmail.js | 1 + modules/client/back/models/client.js | 10 ++++----- .../back/methods/ticket/deliveryNoteEmail.js | 1 + .../back/methods/ticket/deliveryNotePdf.js | 1 + print/core/smtp.js | 2 +- .../email/payment-update/assets/css/import.js | 14 +++++++----- .../email/payment-update/payment-update.js | 13 ++++++----- .../claim-pickup-order.html | 4 ++-- 25 files changed, 54 insertions(+), 32 deletions(-) diff --git a/db/changes/10490-august/00-ACL.sql b/db/changes/10490-august/00-ACL.sql index 29277e8bb..b32a87a5a 100644 --- a/db/changes/10490-august/00-ACL.sql +++ b/db/changes/10490-august/00-ACL.sql @@ -2,20 +2,22 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp VALUES ('ClientConsumptionQueue', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Ticket', 'deliveryNotePdf', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Ticket', 'deliveryNoteEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Ticket', 'deliveryNoteEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'campaignMetricsPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Client', 'campaignMetricsEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'campaignMetricsEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'clientWelcomeHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Client', 'clientWelcomeEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientWelcomeEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'),, + ('Client', 'creditRequestHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'creditRequestEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'printerSetupHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Client', 'printerSetupEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Client', 'sepaCoreEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'printerSetupEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'sepaCoreEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'letterDebtorStHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Client', 'letterDebtorStEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorStEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'letterDebtorNdHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Client', 'letterDebtorNdEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorNdEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'clientDebtStatementHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Client', 'clientDebtStatementEmail', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientDebtStatementEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'incotermsAuthorizationHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'incotermsAuthorizationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'consumptionSendQueued', 'WRITE', 'ALLOW', 'ROLE', 'system'), @@ -28,7 +30,9 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp ('Travel', 'extraCommunityEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Entry', 'entryOrderPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('OsTicket', 'osTicketReportEmail', 'WRITE', 'ALLOW', 'ROLE', 'system'), - ('Item', 'buyerWasteEmail', 'WRITE', 'ALLOW', 'ROLE', 'system'); + ('Item', 'buyerWasteEmail', 'WRITE', 'ALLOW', 'ROLE', 'system'), + ('Claim', 'claimPickupPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Claim', 'claimPickupEmail', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'); INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId) VALUES ('Sector','*','READ','ALLOW','ROLE','employee'); diff --git a/db/changes/10490-august/00-sample.sql b/db/changes/10490-august/00-sample.sql index e9dd9e9a0..f84cd723e 100644 --- a/db/changes/10490-august/00-sample.sql +++ b/db/changes/10490-august/00-sample.sql @@ -3,4 +3,4 @@ alter table `vn`.`sample` UPDATE vn.sample t SET t.model = 'Clients' - WHERE t.id IN(13, 14, 15, 16, 18, 19, 20); \ No newline at end of file + WHERE t.id IN(12, 13, 14, 15, 16, 18, 19, 20); \ No newline at end of file diff --git a/modules/claim/front/descriptor/index.html b/modules/claim/front/descriptor/index.html index 96d0882e6..0bbacf94b 100644 --- a/modules/claim/front/descriptor/index.html +++ b/modules/claim/front/descriptor/index.html @@ -5,8 +5,6 @@ Show Pickup order diff --git a/modules/client/back/methods/client/campaignMetricsEmail.js b/modules/client/back/methods/client/campaignMetricsEmail.js index fab90fbe0..bb57f90a0 100644 --- a/modules/client/back/methods/client/campaignMetricsEmail.js +++ b/modules/client/back/methods/client/campaignMetricsEmail.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('campaignMetricsEmail', { description: 'Sends the campaign metrics email with an attached PDF', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/campaignMetricsPdf.js b/modules/client/back/methods/client/campaignMetricsPdf.js index a6afa95a3..14194d62b 100644 --- a/modules/client/back/methods/client/campaignMetricsPdf.js +++ b/modules/client/back/methods/client/campaignMetricsPdf.js @@ -3,6 +3,7 @@ const {Report} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('campaignMetricsPdf', { description: 'Returns the campaign metrics pdf', + accessType: 'READ', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/clientDebtStatementEmail.js b/modules/client/back/methods/client/clientDebtStatementEmail.js index 0b34598b7..8bcdc900f 100644 --- a/modules/client/back/methods/client/clientDebtStatementEmail.js +++ b/modules/client/back/methods/client/clientDebtStatementEmail.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('clientDebtStatementEmail', { description: 'Sends the client debt statement email with an attached PDF', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/clientDebtStatementHtml.js b/modules/client/back/methods/client/clientDebtStatementHtml.js index 79455f4c4..76502ff6c 100644 --- a/modules/client/back/methods/client/clientDebtStatementHtml.js +++ b/modules/client/back/methods/client/clientDebtStatementHtml.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('clientDebtStatementHtml', { description: 'Returns the client debt statement email preview', + accessType: 'READ', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/clientWelcomeEmail.js b/modules/client/back/methods/client/clientWelcomeEmail.js index aee4f9296..318ee18e6 100644 --- a/modules/client/back/methods/client/clientWelcomeEmail.js +++ b/modules/client/back/methods/client/clientWelcomeEmail.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('clientWelcomeEmail', { description: 'Sends the client welcome email with an attached PDF', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/clientWelcomeHtml.js b/modules/client/back/methods/client/clientWelcomeHtml.js index a54857e57..dfb560326 100644 --- a/modules/client/back/methods/client/clientWelcomeHtml.js +++ b/modules/client/back/methods/client/clientWelcomeHtml.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('clientWelcomeHtml', { description: 'Returns the client welcome email preview', + accessType: 'READ', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/creditRequestEmail.js b/modules/client/back/methods/client/creditRequestEmail.js index d6e6e69ea..b6a60e971 100644 --- a/modules/client/back/methods/client/creditRequestEmail.js +++ b/modules/client/back/methods/client/creditRequestEmail.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('clientCreditEmail', { description: 'Sends the credit request email with an attached PDF', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/creditRequestHtml.js b/modules/client/back/methods/client/creditRequestHtml.js index 2a7820c14..303308615 100644 --- a/modules/client/back/methods/client/creditRequestHtml.js +++ b/modules/client/back/methods/client/creditRequestHtml.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('creditRequestHtml', { description: 'Returns the credit request email preview', + accessType: 'READ', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/letterDebtorNdEmail.js b/modules/client/back/methods/client/letterDebtorNdEmail.js index 3d03a8ab0..e188c6e0a 100644 --- a/modules/client/back/methods/client/letterDebtorNdEmail.js +++ b/modules/client/back/methods/client/letterDebtorNdEmail.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('letterDebtorNdEmail', { description: 'Sends the second debtor letter email with an attached PDF', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/letterDebtorNdHtml.js b/modules/client/back/methods/client/letterDebtorNdHtml.js index d57e8edc5..d709a3cee 100644 --- a/modules/client/back/methods/client/letterDebtorNdHtml.js +++ b/modules/client/back/methods/client/letterDebtorNdHtml.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('letterDebtorNdHtml', { description: 'Returns the second letter debtor email preview', + accessType: 'READ', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/letterDebtorStEmail.js b/modules/client/back/methods/client/letterDebtorStEmail.js index bec260cb0..ee39a101b 100644 --- a/modules/client/back/methods/client/letterDebtorStEmail.js +++ b/modules/client/back/methods/client/letterDebtorStEmail.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('letterDebtorStEmail', { description: 'Sends the printer setup email with an attached PDF', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/letterDebtorStHtml.js b/modules/client/back/methods/client/letterDebtorStHtml.js index 68f8f5056..b97ce9767 100644 --- a/modules/client/back/methods/client/letterDebtorStHtml.js +++ b/modules/client/back/methods/client/letterDebtorStHtml.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('letterDebtorStHtml', { description: 'Returns the letter debtor email preview', + accessType: 'READ', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/printerSetupEmail.js b/modules/client/back/methods/client/printerSetupEmail.js index df4864dda..254948659 100644 --- a/modules/client/back/methods/client/printerSetupEmail.js +++ b/modules/client/back/methods/client/printerSetupEmail.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('printerSetupEmail', { description: 'Sends the printer setup email with an attached PDF', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/printerSetupHtml.js b/modules/client/back/methods/client/printerSetupHtml.js index 37e318723..1ef1843e0 100644 --- a/modules/client/back/methods/client/printerSetupHtml.js +++ b/modules/client/back/methods/client/printerSetupHtml.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('printerSetupHtml', { description: 'Returns the printer setup email preview', + accessType: 'READ', accepts: [ { arg: 'id', diff --git a/modules/client/back/methods/client/sepaCoreEmail.js b/modules/client/back/methods/client/sepaCoreEmail.js index 47e0be132..93c9d4302 100644 --- a/modules/client/back/methods/client/sepaCoreEmail.js +++ b/modules/client/back/methods/client/sepaCoreEmail.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('sepaCoreEmail', { description: 'Sends the campaign metrics email with an attached PDF', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 3f6853c55..3bd89eff1 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -1,4 +1,3 @@ -const got = require('got'); const UserError = require('vn-loopback/util/user-error'); const getFinalState = require('vn-loopback/util/hook').getFinalState; const isMultiple = require('vn-loopback/util/hook').isMultiple; @@ -292,23 +291,22 @@ module.exports = Self => { const $t = httpRequest.__; const headers = httpRequest.headers; const origin = headers.origin; - const authorization = headers.authorization; const salesPersonId = instance.salesPersonFk; if (salesPersonId) { // Send email to client if (instance.email) { + const {Email} = require('vn-print'); const worker = await models.EmailUser.findById(salesPersonId); const params = { - authorization: authorization, + id: instance.id, recipientId: instance.id, recipient: instance.email, replyTo: worker.email }; - await got.get(`${origin}/api/email/payment-update`, { - searchParams: params - }); + const email = new Email('payment-update', params); + await email.send(); } const fullUrl = `${origin}/#!/client/${instance.id}/billing-data`; diff --git a/modules/ticket/back/methods/ticket/deliveryNoteEmail.js b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js index b15783e1b..cf9f5dd62 100644 --- a/modules/ticket/back/methods/ticket/deliveryNoteEmail.js +++ b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js @@ -3,6 +3,7 @@ const {Email} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('deliveryNoteEmail', { description: 'Sends the delivery note email with an attached PDF', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/modules/ticket/back/methods/ticket/deliveryNotePdf.js b/modules/ticket/back/methods/ticket/deliveryNotePdf.js index 3f6af8359..b2b3f7198 100644 --- a/modules/ticket/back/methods/ticket/deliveryNotePdf.js +++ b/modules/ticket/back/methods/ticket/deliveryNotePdf.js @@ -3,6 +3,7 @@ const {Report} = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('deliveryNotePdf', { description: 'Returns the delivery note pdf', + accessType: 'READ', accepts: [ { arg: 'id', diff --git a/print/core/smtp.js b/print/core/smtp.js index 50a413673..a55ba448d 100644 --- a/print/core/smtp.js +++ b/print/core/smtp.js @@ -29,7 +29,7 @@ module.exports = { for (let attachment of options.attachments) { const fileName = attachment.filename; const filePath = attachment.path; - if (fileName.includes('.png')) return; + if (fileName.includes('.png')) continue; if (fileName || filePath) attachments.push(filePath ? filePath : fileName); diff --git a/print/templates/email/payment-update/assets/css/import.js b/print/templates/email/payment-update/assets/css/import.js index b44d6bd37..1582b82c5 100644 --- a/print/templates/email/payment-update/assets/css/import.js +++ b/print/templates/email/payment-update/assets/css/import.js @@ -1,8 +1,12 @@ -const Stylesheet = require(`${appPath}/core/stylesheet`); +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); module.exports = new Stylesheet([ - `${appPath}/common/css/spacing.css`, - `${appPath}/common/css/misc.css`, - `${appPath}/common/css/layout.css`, - `${appPath}/common/css/email.css`]) + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) .mergeStyles(); + diff --git a/print/templates/email/payment-update/payment-update.js b/print/templates/email/payment-update/payment-update.js index 2b92976a3..a9d99d4ef 100755 --- a/print/templates/email/payment-update/payment-update.js +++ b/print/templates/email/payment-update/payment-update.js @@ -1,11 +1,11 @@ -const Component = require(`${appPath}/core/component`); +const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); module.exports = { name: 'payment-update', async serverPrefetch() { - this.payMethod = await this.fetchPayMethod(this.recipientId); + this.payMethod = await this.fetchPayMethod(this.id); if (!this.payMethod) throw new Error('Something went wrong'); @@ -16,8 +16,8 @@ module.exports = { }, }, methods: { - fetchPayMethod(clientId) { - return this.findOneFromDef('payMethod', [clientId]); + fetchPayMethod(id) { + return this.findOneFromDef('payMethod', [id]); } }, components: { @@ -25,9 +25,10 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - recipientId: { + id: { type: [Number, String], - required: true + required: true, + description: 'The client id' } } }; diff --git a/print/templates/reports/claim-pickup-order/claim-pickup-order.html b/print/templates/reports/claim-pickup-order/claim-pickup-order.html index 1f6db4966..6764344b5 100644 --- a/print/templates/reports/claim-pickup-order/claim-pickup-order.html +++ b/print/templates/reports/claim-pickup-order/claim-pickup-order.html @@ -17,7 +17,7 @@ {{$t('claimId')}} - {{claimId}} + {{id}} {{$t('clientId')}} @@ -85,7 +85,7 @@ From 21bb95fc884f88faccdfd6d7dfb6eb99d72f5fcd Mon Sep 17 00:00:00 2001 From: joan Date: Mon, 3 Oct 2022 08:28:47 +0200 Subject: [PATCH 19/53] CSV refactor --- front/core/services/email.js | 14 +-- front/core/services/report.js | 17 +-- {print/methods/csv => loopback/util}/csv.js | 6 + .../back/methods/invoiceOut/invoiceCsv.js | 85 +++++++++++++ .../methods/invoiceOut/invoiceCsvEmail.js | 117 ++++++++++++++++++ modules/invoiceOut/back/models/invoice-out.js | 2 + .../invoiceOut/front/descriptor-menu/index.js | 18 ++- .../back/methods/ticket/deliveryNoteCsv.js | 84 +++++++++++++ .../methods/ticket/deliveryNoteCsvEmail.js | 117 ++++++++++++++++++ modules/ticket/back/models/ticket-methods.js | 2 + modules/ticket/front/descriptor-menu/index.js | 10 +- print/core/router.js | 62 ---------- print/methods/csv/delivery-note/download.js | 24 ---- print/methods/csv/delivery-note/send.js | 40 ------ print/methods/csv/delivery-note/sql/sales.sql | 35 ------ .../methods/csv/delivery-note/sql/ticket.sql | 9 -- print/methods/csv/index.js | 9 -- print/methods/csv/invoice/download.js | 24 ---- print/methods/csv/invoice/send.js | 40 ------ print/methods/csv/invoice/sql/invoice.sql | 10 -- print/methods/csv/invoice/sql/sales.sql | 35 ------ print/methods/routes.js | 6 - 22 files changed, 427 insertions(+), 339 deletions(-) rename {print/methods/csv => loopback/util}/csv.js (85%) create mode 100644 modules/invoiceOut/back/methods/invoiceOut/invoiceCsv.js create mode 100644 modules/invoiceOut/back/methods/invoiceOut/invoiceCsvEmail.js create mode 100644 modules/ticket/back/methods/ticket/deliveryNoteCsv.js create mode 100644 modules/ticket/back/methods/ticket/deliveryNoteCsvEmail.js delete mode 100644 print/core/router.js delete mode 100644 print/methods/csv/delivery-note/download.js delete mode 100644 print/methods/csv/delivery-note/send.js delete mode 100644 print/methods/csv/delivery-note/sql/sales.sql delete mode 100644 print/methods/csv/delivery-note/sql/ticket.sql delete mode 100644 print/methods/csv/index.js delete mode 100644 print/methods/csv/invoice/download.js delete mode 100644 print/methods/csv/invoice/send.js delete mode 100644 print/methods/csv/invoice/sql/invoice.sql delete mode 100644 print/methods/csv/invoice/sql/sales.sql delete mode 100644 print/methods/routes.js diff --git a/front/core/services/email.js b/front/core/services/email.js index b39627573..02aa9051b 100644 --- a/front/core/services/email.js +++ b/front/core/services/email.js @@ -10,7 +10,7 @@ class Email { /** * Sends an email displaying a notification when it's sent. * - * @param {String} template The email report name + * @param {String} path The email report name * @param {Object} params The email parameters * @return {Promise} Promise resolved when it's sent */ @@ -18,18 +18,6 @@ class Email { return this.$http.post(path, params) .then(() => this.vnApp.showMessage(this.$t('Notification sent!'))); } - - /** - * Sends an email displaying a notification when it's sent. - * - * @param {String} template The email report name - * @param {Object} params The email parameters - * @return {Promise} Promise resolved when it's sent - */ - sendCsv(template, params) { - return this.$http.get(`csv/${template}/send`, {params}) - .then(() => this.vnApp.showMessage(this.$t('Notification sent!'))); - } } Email.$inject = ['$http', '$translate', 'vnApp']; diff --git a/front/core/services/report.js b/front/core/services/report.js index d28959d47..45024d9e0 100644 --- a/front/core/services/report.js +++ b/front/core/services/report.js @@ -10,7 +10,7 @@ class Report { * Shows a report in another window, automatically adds the authorization * token to params. * - * @param {String} report The report name + * @param {String} path The report name * @param {Object} params The report parameters */ show(path, params) { @@ -20,21 +20,6 @@ class Report { const serializedParams = this.$httpParamSerializer(params); window.open(`api/${path}?${serializedParams}`); } - - /** - * Shows a report in another window, automatically adds the authorization - * token to params. - * - * @param {String} report The report name - * @param {Object} params The report parameters - */ - showCsv(report, params) { - params = Object.assign({ - authorization: this.vnToken.token - }, params); - const serializedParams = this.$httpParamSerializer(params); - window.open(`api/csv/${report}/download?${serializedParams}`); - } } Report.$inject = ['$httpParamSerializer', 'vnToken']; diff --git a/print/methods/csv/csv.js b/loopback/util/csv.js similarity index 85% rename from print/methods/csv/csv.js rename to loopback/util/csv.js index d8725582d..e79c18da8 100644 --- a/print/methods/csv/csv.js +++ b/loopback/util/csv.js @@ -1,3 +1,9 @@ +/** + * Transforms an object to a raw data CSV file. + * + * @param {Object} rows Data + * @return {String} Formatted CSV data + */ function toCSV(rows) { const [columns] = rows; let content = Object.keys(columns).join('\t'); diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceCsv.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceCsv.js new file mode 100644 index 000000000..d33df74a2 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceCsv.js @@ -0,0 +1,85 @@ +const {toCSV} = require('vn-loopback/util/csv'); + +module.exports = Self => { + Self.remoteMethod('invoiceCsv', { + description: 'Returns the delivery note csv', + accessType: 'READ', + accepts: [ + { + arg: 'reference', + type: 'string', + required: true, + description: 'The invoice reference', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The client id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:reference/invoice-csv', + verb: 'GET' + } + }); + + Self.invoiceCsv = async reference => { + const sales = await Self.rawSql(` + SELECT io.ref Invoice, + io.issued InvoiceDate, + s.ticketFk Ticket, + s.itemFk Item, + s.concept Description, + i.size, + i.subName Producer, + s.quantity Quantity, + s.price Price, + s.discount Discount, + s.created Created, + tc.code Taxcode, + tc.description TaxDescription, + i.tag5, + i.value5, + i.tag6, + i.value6, + i.tag7, + i.value7, + i.tag8, + i.value8, + i.tag9, + i.value9, + i.tag10, + i.value10 + FROM sale s + JOIN ticket t ON t.id = s.ticketFk + JOIN item i ON i.id = s.itemFk + JOIN supplier s2 ON s2.id = t.companyFk + JOIN itemTaxCountry itc ON itc.itemFk = i.id + AND itc.countryFk = s2.countryFk + JOIN taxClass tc ON tc.id = itc.taxClassFk + JOIN invoiceOut io ON io.ref = t.refFk + WHERE t.refFk = ? + ORDER BY s.ticketFk, s.created`, [reference]); + + const content = toCSV(sales); + + return [content, 'text/csv', `inline; filename="doc-${reference}.pdf"`]; + }; +}; diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceCsvEmail.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceCsvEmail.js new file mode 100644 index 000000000..38d451595 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceCsvEmail.js @@ -0,0 +1,117 @@ +const {Email} = require('vn-print'); +const {toCSV} = require('vn-loopback/util/csv'); + +module.exports = Self => { + Self.remoteMethodCtx('invoiceCsvEmail', { + description: 'Returns the delivery note csv', + accessType: 'READ', + accepts: [ + { + arg: 'reference', + type: 'string', + required: true, + description: 'The invoice reference', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The client id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:reference/invoice-csv-email', + verb: 'POST' + } + }); + + Self.invoiceCsvEmail = async(ctx, reference) => { + const args = Object.assign({}, ctx.args); + + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const sales = await Self.rawSql(` + SELECT io.ref Invoice, + io.issued InvoiceDate, + s.ticketFk Ticket, + s.itemFk Item, + s.concept Description, + i.size, + i.subName Producer, + s.quantity Quantity, + s.price Price, + s.discount Discount, + s.created Created, + tc.code Taxcode, + tc.description TaxDescription, + i.tag5, + i.value5, + i.tag6, + i.value6, + i.tag7, + i.value7, + i.tag8, + i.value8, + i.tag9, + i.value9, + i.tag10, + i.value10 + FROM sale s + JOIN ticket t ON t.id = s.ticketFk + JOIN item i ON i.id = s.itemFk + JOIN supplier s2 ON s2.id = t.companyFk + JOIN itemTaxCountry itc ON itc.itemFk = i.id + AND itc.countryFk = s2.countryFk + JOIN taxClass tc ON tc.id = itc.taxClassFk + JOIN invoiceOut io ON io.ref = t.refFk + WHERE t.refFk = ? + ORDER BY s.ticketFk, s.created`, [reference]); + + const content = toCSV(sales); + const fileName = `invoice_${reference}.csv`; + const email = new Email('invoice', params); + + return email.send({ + overrideAttachments: true, + attachments: [{ + filename: fileName, + content: content + }] + }); + }; +}; diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index f58fe3978..5af64de2b 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -12,4 +12,6 @@ module.exports = Self => { require('../methods/invoiceOut/invoiceEmail')(Self); require('../methods/invoiceOut/exportationPdf')(Self); require('../methods/invoiceOut/sendQueued')(Self); + require('../methods/invoiceOut/invoiceCsv')(Self); + require('../methods/invoiceOut/invoiceCsvEmail')(Self); }; diff --git a/modules/invoiceOut/front/descriptor-menu/index.js b/modules/invoiceOut/front/descriptor-menu/index.js index 78b2cb56e..456939119 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.js +++ b/modules/invoiceOut/front/descriptor-menu/index.js @@ -81,13 +81,6 @@ class Controller extends Section { }); } - showCsvInvoice() { - this.vnReport.showCsv('invoice', { - recipientId: this.invoiceOut.client.id, - refFk: this.invoiceOut.ref - }); - } - sendPdfInvoice($data) { if (!$data.email) return this.vnApp.showError(this.$t(`The email can't be empty`)); @@ -98,14 +91,19 @@ class Controller extends Section { }); } + showCsvInvoice() { + this.vnReport.show(`InvoiceOuts/${this.invoiceOut.ref}/invoice-csv`, { + recipientId: this.invoiceOut.client.id + }); + } + sendCsvInvoice($data) { if (!$data.email) return this.vnApp.showError(this.$t(`The email can't be empty`)); - return this.vnEmail.sendCsv('invoice', { + return this.vnEmail.send(`InvoiceOuts/${this.invoiceOut.ref}/invoice-csv-email`, { recipientId: this.invoiceOut.client.id, - recipient: $data.email, - refFk: this.invoiceOut.ref + recipient: $data.email }); } diff --git a/modules/ticket/back/methods/ticket/deliveryNoteCsv.js b/modules/ticket/back/methods/ticket/deliveryNoteCsv.js new file mode 100644 index 000000000..55ec4089d --- /dev/null +++ b/modules/ticket/back/methods/ticket/deliveryNoteCsv.js @@ -0,0 +1,84 @@ +const {toCSV} = require('vn-loopback/util/csv'); + +module.exports = Self => { + Self.remoteMethod('deliveryNoteCsv', { + description: 'Returns the delivery note csv', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The ticket id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The client id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/delivery-note-csv', + verb: 'GET' + } + }); + + Self.deliveryNoteCsv = async id => { + const sales = await Self.rawSql(` + SELECT io.ref Invoice, + io.issued InvoiceDate, + s.ticketFk Ticket, + s.itemFk Item, + s.concept Description, + i.size, + i.subName Producer, + s.quantity Quantity, + s.price Price, + s.discount Discount, + s.created Created, + tc.code Taxcode, + tc.description TaxDescription, + i.tag5, + i.value5, + i.tag6, + i.value6, + i.tag7, + i.value7, + i.tag8, + i.value8, + i.tag9, + i.value9, + i.tag10, + i.value10 + FROM vn.sale s + JOIN vn.ticket t ON t.id = s.ticketFk + JOIN vn.item i ON i.id = s.itemFk + JOIN vn.supplier s2 ON s2.id = t.companyFk + JOIN vn.itemTaxCountry itc ON itc.itemFk = i.id + AND itc.countryFk = s2.countryFk + JOIN vn.taxClass tc ON tc.id = itc.taxClassFk + LEFT JOIN vn.invoiceOut io ON io.id = t.refFk + WHERE s.ticketFk = ? + ORDER BY s.ticketFk, s.created`, [id]); + const content = toCSV(sales); + + return [content, 'text/csv', `inline; filename="doc-${id}.pdf"`]; + }; +}; diff --git a/modules/ticket/back/methods/ticket/deliveryNoteCsvEmail.js b/modules/ticket/back/methods/ticket/deliveryNoteCsvEmail.js new file mode 100644 index 000000000..79702cbaf --- /dev/null +++ b/modules/ticket/back/methods/ticket/deliveryNoteCsvEmail.js @@ -0,0 +1,117 @@ +const {Email} = require('vn-print'); +const {toCSV} = require('vn-loopback/util/csv'); + +module.exports = Self => { + Self.remoteMethodCtx('deliveryNoteCsvEmail', { + description: 'Returns the delivery note csv', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The ticket id', + http: {source: 'path'} + }, + { + arg: 'recipient', + type: 'string', + description: 'The recipient email', + required: true, + }, + { + arg: 'replyTo', + type: 'string', + description: 'The sender email to reply to', + required: false + }, + { + arg: 'recipientId', + type: 'number', + description: 'The client id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/delivery-note-csv-email', + verb: 'POST' + } + }); + + Self.deliveryNoteCsvEmail = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + + const params = { + recipient: args.recipient, + lang: ctx.req.getLocale() + }; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const sales = await Self.rawSql(` + SELECT io.ref Invoice, + io.issued InvoiceDate, + s.ticketFk Ticket, + s.itemFk Item, + s.concept Description, + i.size, + i.subName Producer, + s.quantity Quantity, + s.price Price, + s.discount Discount, + s.created Created, + tc.code Taxcode, + tc.description TaxDescription, + i.tag5, + i.value5, + i.tag6, + i.value6, + i.tag7, + i.value7, + i.tag8, + i.value8, + i.tag9, + i.value9, + i.tag10, + i.value10 + FROM vn.sale s + JOIN vn.ticket t ON t.id = s.ticketFk + JOIN vn.item i ON i.id = s.itemFk + JOIN vn.supplier s2 ON s2.id = t.companyFk + JOIN vn.itemTaxCountry itc ON itc.itemFk = i.id + AND itc.countryFk = s2.countryFk + JOIN vn.taxClass tc ON tc.id = itc.taxClassFk + LEFT JOIN vn.invoiceOut io ON io.id = t.refFk + WHERE s.ticketFk = ? + ORDER BY s.ticketFk, s.created`, [id]); + + const content = toCSV(sales); + const fileName = `ticket_${id}.csv`; + const email = new Email('delivery-note', params); + + return email.send({ + overrideAttachments: true, + attachments: [{ + filename: fileName, + content: content + }] + }); + }; +}; diff --git a/modules/ticket/back/models/ticket-methods.js b/modules/ticket/back/models/ticket-methods.js index 8b8f2bea5..9255e52e6 100644 --- a/modules/ticket/back/models/ticket-methods.js +++ b/modules/ticket/back/models/ticket-methods.js @@ -27,6 +27,8 @@ module.exports = function(Self) { require('../methods/ticket/refund')(Self); require('../methods/ticket/deliveryNotePdf')(Self); require('../methods/ticket/deliveryNoteEmail')(Self); + require('../methods/ticket/deliveryNoteCsv')(Self); + require('../methods/ticket/deliveryNoteCsvEmail')(Self); require('../methods/ticket/closeAll')(Self); require('../methods/ticket/closeByTicket')(Self); require('../methods/ticket/closeByAgency')(Self); diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js index 05860cf88..f73aae721 100644 --- a/modules/ticket/front/descriptor-menu/index.js +++ b/modules/ticket/front/descriptor-menu/index.js @@ -140,17 +140,15 @@ class Controller extends Section { } showCsvDeliveryNote() { - this.vnReport.showCsv('delivery-note', { - recipientId: this.ticket.client.id, - ticketId: this.id, + this.vnReport.show(`tickets/${this.id}/delivery-note-csv`, { + recipientId: this.ticket.client.id }); } sendCsvDeliveryNote($data) { - return this.vnEmail.sendCsv('delivery-note', { + return this.vnEmail.send(`tickets/${this.id}/delivery-note-csv-email`, { recipientId: this.ticket.client.id, - recipient: $data.email, - ticketId: this.id + recipient: $data.email }); } diff --git a/print/core/router.js b/print/core/router.js deleted file mode 100644 index cd64ba07e..000000000 --- a/print/core/router.js +++ /dev/null @@ -1,62 +0,0 @@ -const db = require('./database'); - -module.exports = app => { - const routes = require('../methods/routes'); - - 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({}, request.query); - const props = Object.assign(args, request.body); - props.authorization = auth.id; - - response.locals = props; - response.locals.auth = { - userId: auth.userId, - token: auth.id, - email: auth.email, - locale: auth.lang - }; - - next(); - } catch (error) { - next(error); - } - }); - - // Register routes - for (let route of routes) - app.use(route.url, route.cb); - - function getToken(request) { - const headers = request.headers; - const queryParams = request.query; - - return headers.authorization || queryParams.authorization; - } - - function isTokenExpired(created, ttl) { - const date = new Date(created); - const currentDate = new Date(); - - date.setSeconds(date.getSeconds() + ttl); - - if (currentDate > date) - return true; - - return false; - } -}; diff --git a/print/methods/csv/delivery-note/download.js b/print/methods/csv/delivery-note/download.js deleted file mode 100644 index d369d5f4a..000000000 --- a/print/methods/csv/delivery-note/download.js +++ /dev/null @@ -1,24 +0,0 @@ -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/send.js b/print/methods/csv/delivery-note/send.js deleted file mode 100644 index 478f20f57..000000000 --- a/print/methods/csv/delivery-note/send.js +++ /dev/null @@ -1,40 +0,0 @@ -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/delivery-note/sql/sales.sql b/print/methods/csv/delivery-note/sql/sales.sql deleted file mode 100644 index e5b419571..000000000 --- a/print/methods/csv/delivery-note/sql/sales.sql +++ /dev/null @@ -1,35 +0,0 @@ -SELECT io.ref Invoice, - io.issued InvoiceDate, - s.ticketFk Ticket, - s.itemFk Item, - s.concept Description, - i.size, - i.subName Producer, - s.quantity Quantity, - s.price Price, - s.discount Discount, - s.created Created, - tc.code Taxcode, - tc.description TaxDescription, - i.tag5, - i.value5, - i.tag6, - i.value6, - i.tag7, - i.value7, - i.tag8, - i.value8, - i.tag9, - i.value9, - i.tag10, - i.value10 -FROM vn.sale s - JOIN vn.ticket t ON t.id = s.ticketFk - JOIN vn.item i ON i.id = s.itemFk - JOIN vn.supplier s2 ON s2.id = t.companyFk - JOIN vn.itemTaxCountry itc ON itc.itemFk = i.id - AND itc.countryFk = s2.countryFk - JOIN vn.taxClass tc ON tc.id = itc.taxClassFk - LEFT JOIN vn.invoiceOut io ON io.id = t.refFk -WHERE s.ticketFk = ? -ORDER BY s.ticketFk, s.created \ No newline at end of file diff --git a/print/methods/csv/delivery-note/sql/ticket.sql b/print/methods/csv/delivery-note/sql/ticket.sql deleted file mode 100644 index b80c7c42c..000000000 --- a/print/methods/csv/delivery-note/sql/ticket.sql +++ /dev/null @@ -1,9 +0,0 @@ -SELECT - t.id, - t.clientFk, - c.email recipient, - eu.email salesPersonEmail -FROM ticket t - JOIN client c ON c.id = t.clientFk - LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk -WHERE t.id = ? \ No newline at end of file diff --git a/print/methods/csv/index.js b/print/methods/csv/index.js deleted file mode 100644 index 6bdd1b60d..000000000 --- a/print/methods/csv/index.js +++ /dev/null @@ -1,9 +0,0 @@ -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 deleted file mode 100644 index 9cca99f2d..000000000 --- a/print/methods/csv/invoice/download.js +++ /dev/null @@ -1,24 +0,0 @@ -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.refFk) - throw new Error('The argument refFk is required'); - - const refFk = reqArgs.refFk; - const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [refFk]); - const content = toCSV(sales); - const fileName = `invoice_${refFk}.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/send.js b/print/methods/csv/invoice/send.js deleted file mode 100644 index 2729e4a2b..000000000 --- a/print/methods/csv/invoice/send.js +++ /dev/null @@ -1,40 +0,0 @@ -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.refFk) - throw new Error('The argument refFk is required'); - - const refFk = reqArgs.refFk; - const invoice = await db.findOneFromDef(`${sqlPath}/invoice`, [refFk]); - const sales = await db.rawSqlFromDef(`${sqlPath}/sales`, [refFk]); - - const args = Object.assign({ - refFk: invoice.refFk, - recipientId: invoice.clientFk, - recipient: invoice.recipient, - replyTo: invoice.salesPersonEmail - }, response.locals); - - const content = toCSV(sales); - const fileName = `invoice_${refFk}.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/csv/invoice/sql/invoice.sql b/print/methods/csv/invoice/sql/invoice.sql deleted file mode 100644 index d484766a0..000000000 --- a/print/methods/csv/invoice/sql/invoice.sql +++ /dev/null @@ -1,10 +0,0 @@ -SELECT - io.id, - io.clientFk, - c.email recipient, - eu.email salesPersonEmail -FROM invoiceOut io - JOIN client c ON c.id = io.clientFk - LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk - LEFT JOIN ticket t ON t.refFk = io.ref -WHERE t.refFk = ? \ No newline at end of file diff --git a/print/methods/csv/invoice/sql/sales.sql b/print/methods/csv/invoice/sql/sales.sql deleted file mode 100644 index 33fe62476..000000000 --- a/print/methods/csv/invoice/sql/sales.sql +++ /dev/null @@ -1,35 +0,0 @@ -SELECT io.ref Invoice, - io.issued InvoiceDate, - s.ticketFk Ticket, - s.itemFk Item, - s.concept Description, - i.size, - i.subName Producer, - s.quantity Quantity, - s.price Price, - s.discount Discount, - s.created Created, - tc.code Taxcode, - tc.description TaxDescription, - i.tag5, - i.value5, - i.tag6, - i.value6, - i.tag7, - i.value7, - i.tag8, - i.value8, - i.tag9, - i.value9, - i.tag10, - i.value10 -FROM sale s - JOIN ticket t ON t.id = s.ticketFk - JOIN item i ON i.id = s.itemFk - JOIN supplier s2 ON s2.id = t.companyFk - JOIN itemTaxCountry itc ON itc.itemFk = i.id - AND itc.countryFk = s2.countryFk - JOIN taxClass tc ON tc.id = itc.taxClassFk - JOIN invoiceOut io ON io.ref = t.refFk -WHERE t.refFk = ? -ORDER BY s.ticketFk, s.created \ No newline at end of file diff --git a/print/methods/routes.js b/print/methods/routes.js deleted file mode 100644 index 42043409b..000000000 --- a/print/methods/routes.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = [ - { - url: '/api/csv', - cb: require('./csv') - } -]; From c177c0366dfecf3ed9f3769cb324d198ec7f9b35 Mon Sep 17 00:00:00 2001 From: joan Date: Mon, 3 Oct 2022 13:35:49 +0200 Subject: [PATCH 20/53] Item PDF --- db/changes/10490-august/00-ACL.sql | 7 +- modules/item/back/methods/item/labelPdf.js | 72 +++++++++++++++++++ modules/item/back/models/item.js | 1 + .../reports/item-label/item-label.js | 10 ++- 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 modules/item/back/methods/item/labelPdf.js diff --git a/db/changes/10490-august/00-ACL.sql b/db/changes/10490-august/00-ACL.sql index b32a87a5a..55852a38d 100644 --- a/db/changes/10490-august/00-ACL.sql +++ b/db/changes/10490-august/00-ACL.sql @@ -3,6 +3,8 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp ('ClientConsumptionQueue', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Ticket', 'deliveryNotePdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Ticket', 'deliveryNoteEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), + ('Ticket', 'deliveryNoteCsvPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Ticket', 'deliveryNoteCsvEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'campaignMetricsPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'campaignMetricsEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'clientWelcomeHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), @@ -24,6 +26,8 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp ('InvoiceOut', 'invoiceEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('InvoiceOut', 'exportationPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('InvoiceOut', 'sendQueued', 'WRITE', 'ALLOW', 'ROLE', 'system'), + ('Ticket', 'invoiceCsvPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Ticket', 'invoiceCsvEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Supplier', 'campaignMetricsPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Supplier', 'campaignMetricsEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Travel', 'extraCommunityPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), @@ -32,7 +36,8 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp ('OsTicket', 'osTicketReportEmail', 'WRITE', 'ALLOW', 'ROLE', 'system'), ('Item', 'buyerWasteEmail', 'WRITE', 'ALLOW', 'ROLE', 'system'), ('Claim', 'claimPickupPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Claim', 'claimPickupEmail', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'); + ('Claim', 'claimPickupEmail', 'WRITE', 'ALLOW', 'ROLE', 'claimManager'), + ('Item', 'labelPdf', 'READ', 'ALLOW', 'ROLE', 'employee'); INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId) VALUES ('Sector','*','READ','ALLOW','ROLE','employee'); diff --git a/modules/item/back/methods/item/labelPdf.js b/modules/item/back/methods/item/labelPdf.js new file mode 100644 index 000000000..747869b37 --- /dev/null +++ b/modules/item/back/methods/item/labelPdf.js @@ -0,0 +1,72 @@ +const {Report} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('labelPdf', { + description: 'Returns the item label pdf', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The item id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + }, + { + arg: 'warehouseId', + type: 'number', + description: 'The warehouse id', + required: true + }, + { + arg: 'labelNumber', + type: 'number', + required: false + }, + { + arg: 'totalLabels', + type: 'number', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/label-pdf', + verb: 'GET' + } + }); + + Self.labelPdf = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('item-label', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="item-${id}.pdf"`]; + }; +}; diff --git a/modules/item/back/models/item.js b/modules/item/back/models/item.js index 381033a1e..b8baa97ea 100644 --- a/modules/item/back/models/item.js +++ b/modules/item/back/models/item.js @@ -16,6 +16,7 @@ module.exports = Self => { require('../methods/item/createIntrastat')(Self); require('../methods/item/activeBuyers')(Self); require('../methods/item/buyerWasteEmail')(Self); + require('../methods/item/labelPdf')(Self); Self.validatesPresenceOf('originFk', {message: 'Cannot be blank'}); diff --git a/print/templates/reports/item-label/item-label.js b/print/templates/reports/item-label/item-label.js index 09bc38abc..d03d03cfa 100755 --- a/print/templates/reports/item-label/item-label.js +++ b/print/templates/reports/item-label/item-label.js @@ -40,7 +40,9 @@ module.exports = { }); }, getBarcodeBase64(id) { - return qrcode.toDataURL(id, {margin: 0}); + const data = String(id); + + return qrcode.toDataURL(data, {margin: 0}); }, packing() { const stems = this.item.stems ? this.item.stems : 1; @@ -53,17 +55,19 @@ module.exports = { }, props: { id: { + type: Number, required: true, description: 'The item id' }, warehouseId: { + type: Number, required: true }, labelNumber: { - type: String + type: Number }, totalLabels: { - type: String + type: Number } } }; From c8bad23621874429ece02e0a5ce9ade65a0b9ed6 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 4 Oct 2022 07:41:40 +0200 Subject: [PATCH 21/53] Tests --- modules/claim/front/descriptor/index.spec.js | 14 ++--- .../client/front/consumption/index.spec.js | 19 +++---- modules/client/front/notification/index.js | 2 +- .../client/front/notification/index.spec.js | 5 +- modules/client/front/sample/create/index.js | 52 ------------------- .../client/front/sample/create/index.spec.js | 10 ++-- modules/entry/front/descriptor/index.spec.js | 7 +-- .../front/descriptor-menu/index.spec.js | 21 ++------ .../supplier/front/consumption/index.spec.js | 10 ++-- .../front/descriptor-menu/index.spec.js | 24 ++++----- modules/ticket/front/index/index.js | 7 +-- modules/ticket/front/index/index.spec.js | 4 +- 12 files changed, 49 insertions(+), 126 deletions(-) diff --git a/modules/claim/front/descriptor/index.spec.js b/modules/claim/front/descriptor/index.spec.js index 669a73954..e6785d3d8 100644 --- a/modules/claim/front/descriptor/index.spec.js +++ b/modules/claim/front/descriptor/index.spec.js @@ -24,12 +24,13 @@ describe('Item Component vnClaimDescriptor', () => { window.open = jasmine.createSpy('open'); const params = { - recipientId: claim.clientFk, - claimId: claim.id + recipientId: claim.clientFk }; controller.showPickupOrder(); - expect(controller.vnReport.show).toHaveBeenCalledWith('claim-pickup-order', params); + const expectedPath = `Claims/${claim.id}/claim-pickup-pdf`; + + expect(controller.vnReport.show).toHaveBeenCalledWith(expectedPath, params); }); }); @@ -39,12 +40,13 @@ describe('Item Component vnClaimDescriptor', () => { const params = { recipient: claim.client.email, - recipientId: claim.clientFk, - claimId: claim.id + recipientId: claim.clientFk }; controller.sendPickupOrder(); - expect(controller.vnEmail.send).toHaveBeenCalledWith('claim-pickup-order', params); + const expectedPath = `Claims/${claim.id}/claim-pickup-email`; + + expect(controller.vnEmail.send).toHaveBeenCalledWith(expectedPath, params); }); }); diff --git a/modules/client/front/consumption/index.spec.js b/modules/client/front/consumption/index.spec.js index 16b764b56..33cbce58f 100644 --- a/modules/client/front/consumption/index.spec.js +++ b/modules/client/front/consumption/index.spec.js @@ -34,15 +34,16 @@ describe('Client', () => { controller.showReport(); + const clientId = controller.client.id; const expectedParams = { - recipientId: 1101, + recipientId: clientId, from: now, to: now }; const serializedParams = $httpParamSerializer(expectedParams); - const path = `api/report/campaign-metrics?${serializedParams}`; + const expectedPath = `api/Clients/${clientId}/campaign-metrics-pdf?${serializedParams}`; - expect(window.open).toHaveBeenCalledWith(path); + expect(window.open).toHaveBeenCalledWith(expectedPath); }); }); @@ -53,16 +54,10 @@ describe('Client', () => { from: now, to: now }; - const expectedParams = { - recipientId: 1101, - from: now, - to: now - }; + const clientId = controller.client.id; + const expectedPath = `Clients/${clientId}/campaign-metrics-email`; - const serializedParams = $httpParamSerializer(expectedParams); - const path = `email/campaign-metrics?${serializedParams}`; - - $httpBackend.expect('GET', path).respond({}); + $httpBackend.expect('POST', expectedPath).respond({}); controller.sendEmail(); $httpBackend.flush(); }); diff --git a/modules/client/front/notification/index.js b/modules/client/front/notification/index.js index d61c8f771..e70af12b2 100644 --- a/modules/client/front/notification/index.js +++ b/modules/client/front/notification/index.js @@ -85,7 +85,7 @@ export default class Controller extends Section { this.$http.post('ClientConsumptionQueues', {params}) .then(() => this.$.filters.hide()) - .then(() => this.vnApp.showSuccess(this.$t('Notifications queued'))); + .then(() => this.vnApp.showSuccess(this.$t('Notifications sent!'))); } exprBuilder(param, value) { diff --git a/modules/client/front/notification/index.spec.js b/modules/client/front/notification/index.spec.js index 8847357f7..ea082c403 100644 --- a/modules/client/front/notification/index.spec.js +++ b/modules/client/front/notification/index.spec.js @@ -61,7 +61,6 @@ describe('Client notification', () => { controller.$.filters = {hide: () => {}}; controller.campaign = { - id: 1, from: new Date(), to: new Date() }; @@ -71,10 +70,10 @@ describe('Client notification', () => { data[1].$checked = true; const params = Object.assign({ - clientIds: [1101, 1102] + clients: [1101, 1102] }, controller.campaign); - $httpBackend.expect('POST', `schedule/consumption`, params).respond(200, params); + $httpBackend.expect('POST', `ClientConsumptionQueues`, {params}).respond(200, params); controller.onSendClientConsumption(); $httpBackend.flush(); diff --git a/modules/client/front/sample/create/index.js b/modules/client/front/sample/create/index.js index df0211d06..4e6256ee6 100644 --- a/modules/client/front/sample/create/index.js +++ b/modules/client/front/sample/create/index.js @@ -40,58 +40,6 @@ class Controller extends Section { this.$.watcher.realSubmit().then(() => this.send()); } - // showPreview() { - // this.send(true, res => { - // this.$.showPreview.show(); - // const dialog = document.body.querySelector('div.vn-dialog'); - // const body = dialog.querySelector('tpl-body'); - // const scroll = dialog.querySelector('div:first-child'); - - // body.innerHTML = res.data; - // scroll.scrollTop = 0; - // }); - // } - - // sendSample() { - // this.send(false, () => { - // this.vnApp.showSuccess(this.$t('Notification sent!')); - // this.$state.go('client.card.sample.index'); - // }); - // } - - // send(isPreview, cb) { - // const sampleType = this.$.sampleType.selection; - // const params = { - // recipientId: this.$params.id, - // recipient: this.clientSample.recipient, - // replyTo: this.clientSample.replyTo - // }; - - // if (!params.recipient) - // return this.vnApp.showError(this.$t('Email cannot be blank')); - - // if (!sampleType) - // return this.vnApp.showError(this.$t('Choose a sample')); - - // if (sampleType.hasCompany && !this.clientSample.companyFk) - // return this.vnApp.showError(this.$t('Choose a company')); - - // if (sampleType.hasCompany) - // params.companyId = this.clientSample.companyFk; - - // if (sampleType.datepickerEnabled && !this.clientSample.from) - // return this.vnApp.showError(this.$t('Choose a date')); - - // if (sampleType.datepickerEnabled) - // params.from = this.clientSample.from; - - // let query = `email/${sampleType.code}`; - // if (isPreview) - // query = `email/${sampleType.code}/preview`; - - // this.$http.get(query, {params}).then(cb); - // } - validateParams(params) { const sampleType = this.$.sampleType.selection; diff --git a/modules/client/front/sample/create/index.spec.js b/modules/client/front/sample/create/index.spec.js index 781025fd2..6e9da54ef 100644 --- a/modules/client/front/sample/create/index.spec.js +++ b/modules/client/front/sample/create/index.spec.js @@ -40,6 +40,7 @@ describe('Client', () => { $httpParamSerializer = _$httpParamSerializer_; $element = angular.element(''); controller = $componentController('vnClientSampleCreate', {$element, $scope}); + controller.client = {id: 1101}; const element = document.createElement('div'); document.body.querySelector = () => { return { @@ -51,11 +52,11 @@ describe('Client', () => { })); describe('onSubmit()', () => { - it(`should call sendSample() method`, () => { - jest.spyOn(controller, 'sendSample'); + it(`should call send() method`, () => { + jest.spyOn(controller, 'send'); controller.onSubmit(); - expect(controller.sendSample).toHaveBeenCalledWith(); + expect(controller.send).toHaveBeenCalledWith(); }); }); @@ -65,7 +66,8 @@ describe('Client', () => { controller.$.sampleType.selection = { hasCompany: false, - code: 'MyReport' + code: 'MyReport', + model: 'Clients' }; controller.clientSample = { recipientId: 1101 diff --git a/modules/entry/front/descriptor/index.spec.js b/modules/entry/front/descriptor/index.spec.js index 84defea3b..714bb9f3c 100644 --- a/modules/entry/front/descriptor/index.spec.js +++ b/modules/entry/front/descriptor/index.spec.js @@ -17,13 +17,10 @@ describe('Entry Component vnEntryDescriptor', () => { jest.spyOn(controller.vnReport, 'show'); window.open = jasmine.createSpy('open'); - const params = { - clientId: controller.vnConfig.storage.currentUserWorkerId, - entryId: entry.id - }; controller.showEntryReport(); + const expectedPath = `Entries/${entry.id}/entry-order-pdf`; - expect(controller.vnReport.show).toHaveBeenCalledWith('entry-order', params); + expect(controller.vnReport.show).toHaveBeenCalledWith(expectedPath); }); }); diff --git a/modules/invoiceOut/front/descriptor-menu/index.spec.js b/modules/invoiceOut/front/descriptor-menu/index.spec.js index da7c87894..d2ccfa117 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.spec.js +++ b/modules/invoiceOut/front/descriptor-menu/index.spec.js @@ -41,11 +41,10 @@ describe('vnInvoiceOutDescriptorMenu', () => { jest.spyOn(window, 'open').mockReturnThis(); const expectedParams = { - recipientId: invoiceOut.client.id, - refFk: invoiceOut.ref + recipientId: invoiceOut.client.id }; const serializedParams = $httpParamSerializer(expectedParams); - const expectedPath = `api/csv/invoice/download?${serializedParams}`; + const expectedPath = `api/InvoiceOuts/${invoiceOut.ref}/invoice-csv?${serializedParams}`; controller.showCsvInvoice(); expect(window.open).toHaveBeenCalledWith(expectedPath); @@ -84,14 +83,8 @@ describe('vnInvoiceOutDescriptorMenu', () => { jest.spyOn(controller.vnApp, 'showMessage'); const $data = {email: 'brucebanner@gothamcity.com'}; - const expectedParams = { - recipient: $data.email, - recipientId: invoiceOut.client.id, - refFk: invoiceOut.ref - }; - const serializedParams = $httpParamSerializer(expectedParams); - $httpBackend.expectGET(`email/invoice?${serializedParams}`).respond(); + $httpBackend.expectPOST(`InvoiceOuts/${invoiceOut.ref}/invoice-email`).respond(); controller.sendPdfInvoice($data); $httpBackend.flush(); @@ -104,14 +97,8 @@ describe('vnInvoiceOutDescriptorMenu', () => { jest.spyOn(controller.vnApp, 'showMessage'); const $data = {email: 'brucebanner@gothamcity.com'}; - const expectedParams = { - recipient: $data.email, - recipientId: invoiceOut.client.id, - refFk: invoiceOut.ref - }; - const serializedParams = $httpParamSerializer(expectedParams); - $httpBackend.expectGET(`csv/invoice/send?${serializedParams}`).respond(); + $httpBackend.expectPOST(`InvoiceOuts/${invoiceOut.ref}/invoice-csv-email`).respond(); controller.sendCsvInvoice($data); $httpBackend.flush(); diff --git a/modules/supplier/front/consumption/index.spec.js b/modules/supplier/front/consumption/index.spec.js index d095a174b..ebf19ccec 100644 --- a/modules/supplier/front/consumption/index.spec.js +++ b/modules/supplier/front/consumption/index.spec.js @@ -42,7 +42,7 @@ describe('Supplier', () => { to: now }; const serializedParams = $httpParamSerializer(expectedParams); - const path = `api/report/supplier-campaign-metrics?${serializedParams}`; + const path = `api/Suppliers/${supplierId}/campaign-metrics-pdf?${serializedParams}`; expect(window.open).toHaveBeenCalledWith(path); }); @@ -66,7 +66,8 @@ describe('Supplier', () => { controller.sendEmail(); $httpBackend.flush(); - expect(controller.vnApp.showError).toHaveBeenCalledWith(`This supplier doesn't have a contact with an email address`); + expect(controller.vnApp.showError) + .toHaveBeenCalledWith(`This supplier doesn't have a contact with an email address`); }); it('should make a GET query sending the report', () => { @@ -91,16 +92,15 @@ describe('Supplier', () => { to: now }; const expectedParams = { - recipientId: 2, recipient: 'batman@gothamcity.com', from: now, to: now }; serializedParams = $httpParamSerializer(expectedParams); - const path = `email/supplier-campaign-metrics?${serializedParams}`; + const path = `Suppliers/${supplierId}/campaign-metrics-email`; - $httpBackend.expect('GET', path).respond({}); + $httpBackend.expect('POST', path).respond({}); controller.sendEmail(); $httpBackend.flush(); }); diff --git a/modules/ticket/front/descriptor-menu/index.spec.js b/modules/ticket/front/descriptor-menu/index.spec.js index 2d08a7846..091b9a2cf 100644 --- a/modules/ticket/front/descriptor-menu/index.spec.js +++ b/modules/ticket/front/descriptor-menu/index.spec.js @@ -124,12 +124,11 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { jest.spyOn(window, 'open').mockReturnThis(); const type = 'deliveryNote'; const expectedParams = { - ticketId: ticket.id, recipientId: ticket.client.id, type: type }; const serializedParams = $httpParamSerializer(expectedParams); - const expectedPath = `api/report/delivery-note?${serializedParams}`; + const expectedPath = `api/tickets/${ticket.id}/delivery-note-pdf?${serializedParams}`; controller.showPdfDeliveryNote(type); expect(window.open).toHaveBeenCalledWith(expectedPath); @@ -143,12 +142,13 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { const $data = {email: 'brucebanner@gothamcity.com'}; const params = { recipient: $data.email, - recipientId: ticket.client.id, - ticketId: ticket.id + recipientId: ticket.client.id }; controller.sendPdfDeliveryNote($data); - expect(controller.vnEmail.send).toHaveBeenCalledWith('delivery-note', params); + const expectedPath = `tickets/${ticket.id}/delivery-note-email`; + + expect(controller.vnEmail.send).toHaveBeenCalledWith(expectedPath, params); }); }); @@ -157,11 +157,10 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { jest.spyOn(window, 'open').mockReturnThis(); const expectedParams = { - ticketId: ticket.id, recipientId: ticket.client.id }; const serializedParams = $httpParamSerializer(expectedParams); - const expectedPath = `api/csv/delivery-note/download?${serializedParams}`; + const expectedPath = `api/tickets/${ticket.id}/delivery-note-csv?${serializedParams}`; controller.showCsvDeliveryNote(); expect(window.open).toHaveBeenCalledWith(expectedPath); @@ -170,21 +169,18 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { describe('sendCsvDeliveryNote()', () => { it('should make a query to the csv delivery-note send endpoint and show a message snackbar', () => { - jest.spyOn(controller.vnApp, 'showMessage'); + jest.spyOn(controller.vnEmail, 'send'); const $data = {email: 'brucebanner@gothamcity.com'}; const expectedParams = { - ticketId: ticket.id, recipient: $data.email, recipientId: ticket.client.id, }; - const serializedParams = $httpParamSerializer(expectedParams); - - $httpBackend.expectGET(`csv/delivery-note/send?${serializedParams}`).respond(); controller.sendCsvDeliveryNote($data); - $httpBackend.flush(); - expect(controller.vnApp.showMessage).toHaveBeenCalled(); + const expectedPath = `tickets/${ticket.id}/delivery-note-csv-email`; + + expect(controller.vnEmail.send).toHaveBeenCalledWith(expectedPath, expectedParams); }); }); diff --git a/modules/ticket/front/index/index.js b/modules/ticket/front/index/index.js index 2df4de0a5..3039a2a03 100644 --- a/modules/ticket/front/index/index.js +++ b/modules/ticket/front/index/index.js @@ -29,11 +29,8 @@ export default class Controller extends Section { } openDeliveryNotes(ids) { - for (let id of ids) { - this.vnReport.show('delivery-note', { - ticketId: id, - }); - } + for (let id of ids) + this.vnReport.show(`Tickets/${id}/delivery-note-pdf`); } openBalanceDialog() { diff --git a/modules/ticket/front/index/index.spec.js b/modules/ticket/front/index/index.spec.js index b966ca8c4..84473686c 100644 --- a/modules/ticket/front/index/index.spec.js +++ b/modules/ticket/front/index/index.spec.js @@ -96,8 +96,8 @@ describe('Component vnTicketIndex', () => { controller.setDelivered(); $httpBackend.flush(); - expect($window.open).toHaveBeenCalledWith(`api/report/delivery-note?ticketId=${tickets[1].id}`); - expect($window.open).toHaveBeenCalledWith(`api/report/delivery-note?ticketId=${tickets[2].id}`); + expect($window.open).toHaveBeenCalledWith(`Tickets/${tickets[1].id}/delivery-note-pdf`); + expect($window.open).toHaveBeenCalledWith(`Tickets/${tickets[2].id}/delivery-note-pdf`); }); }); From 3dbd30421730f7985c88c5d1508b8bac108c26d6 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 4 Oct 2022 09:21:24 +0200 Subject: [PATCH 22/53] Updated unit tests --- front/core/services/report.js | 3 +- modules/client/front/sample/create/index.html | 5 +- modules/client/front/sample/create/index.js | 42 +++++--- .../client/front/sample/create/index.spec.js | 95 ++++++++++--------- modules/ticket/front/index/index.spec.js | 4 +- 5 files changed, 87 insertions(+), 62 deletions(-) diff --git a/front/core/services/report.js b/front/core/services/report.js index 45024d9e0..d6eb28ea4 100644 --- a/front/core/services/report.js +++ b/front/core/services/report.js @@ -18,7 +18,8 @@ class Report { access_token: this.vnToken.token }, params); const serializedParams = this.$httpParamSerializer(params); - window.open(`api/${path}?${serializedParams}`); + const query = serializedParams ? `?${serializedParams}` : ''; + window.open(`api/${path}${query}`); } } Report.$inject = ['$httpParamSerializer', 'vnToken']; diff --git a/modules/client/front/sample/create/index.html b/modules/client/front/sample/create/index.html index 5df2b29ef..725d0cd0f 100644 --- a/modules/client/front/sample/create/index.html +++ b/modules/client/front/sample/create/index.html @@ -41,8 +41,7 @@ model="ClientSample.typeFk" data="samplesVisible" show-field="description" - label="Sample" - required="true"> + label="Sample"> @@ -80,11 +79,9 @@ diff --git a/modules/client/front/sample/create/index.js b/modules/client/front/sample/create/index.js index 4e6256ee6..13ef875da 100644 --- a/modules/client/front/sample/create/index.js +++ b/modules/client/front/sample/create/index.js @@ -37,27 +37,38 @@ class Controller extends Section { onSubmit() { this.$.watcher.check(); + + const validationMessage = this.validate(); + if (validationMessage) + return this.vnApp.showError(this.$t(validationMessage)); + this.$.watcher.realSubmit().then(() => this.send()); } - validateParams(params) { + validate() { const sampleType = this.$.sampleType.selection; - if (!params.recipient) - return this.vnApp.showError(this.$t('Email cannot be blank')); + if (!this.clientSample.recipient) + return 'Email cannot be blank'; if (!sampleType) - return this.vnApp.showError(this.$t('Choose a sample')); + return 'Choose a sample'; if (sampleType.hasCompany && !this.clientSample.companyFk) - return this.vnApp.showError(this.$t('Choose a company')); + return 'Choose a company'; + + if (sampleType.datepickerEnabled && !this.clientSample.from) + return 'Choose a date'; + + return; + } + + setParams(params) { + const sampleType = this.$.sampleType.selection; if (sampleType.hasCompany) params.companyId = this.clientSample.companyFk; - if (sampleType.datepickerEnabled && !this.clientSample.from) - return this.vnApp.showError(this.$t('Choose a date')); - if (sampleType.datepickerEnabled) params.from = this.clientSample.from; } @@ -66,11 +77,14 @@ class Controller extends Section { const sampleType = this.$.sampleType.selection; const params = { - recipientId: this.$params.id, - recipient: this.clientSample.recipient + recipientId: this.$params.id }; - this.validateParams(params); + const validationMessage = this.validate(); + if (validationMessage) + return this.vnApp.showError(this.$t(validationMessage)); + + this.setParams(params); const path = `${sampleType.model}/${this.$params.id}/${sampleType.code}-html`; this.$http.get(path, {params}) @@ -94,7 +108,11 @@ class Controller extends Section { replyTo: this.clientSample.replyTo }; - this.validateParams(params); + const validationMessage = this.validate(); + if (validationMessage) + return this.vnApp.showError(this.$t(validationMessage)); + + this.setParams(params); const path = `${sampleType.model}/${this.$params.id}/${sampleType.code}-email`; this.vnEmail.send(path, params) diff --git a/modules/client/front/sample/create/index.spec.js b/modules/client/front/sample/create/index.spec.js index 6e9da54ef..8e33a1075 100644 --- a/modules/client/front/sample/create/index.spec.js +++ b/modules/client/front/sample/create/index.spec.js @@ -40,7 +40,7 @@ describe('Client', () => { $httpParamSerializer = _$httpParamSerializer_; $element = angular.element(''); controller = $componentController('vnClientSampleCreate', {$element, $scope}); - controller.client = {id: 1101}; + controller._client = {id: 1101}; const element = document.createElement('div'); document.body.querySelector = () => { return { @@ -49,11 +49,23 @@ describe('Client', () => { } }; }; + // $httpBackend.expectGET('EmailUsers?filter=%7B%22where%22:%7B%7D%7D').respond(); })); describe('onSubmit()', () => { it(`should call send() method`, () => { - jest.spyOn(controller, 'send'); + controller.send = jest.fn(); + + controller.$.sampleType.selection = { + hasCompany: false, + code: 'MyReport', + model: 'Clients' + }; + + controller.clientSample = { + recipient: 'email@email' + }; + controller.onSubmit(); expect(controller.send).toHaveBeenCalledWith(); @@ -73,7 +85,7 @@ describe('Client', () => { recipientId: 1101 }; - controller.send(false, () => {}); + controller.send(); expect(controller.$http.get).not.toHaveBeenCalled(); }); @@ -87,7 +99,7 @@ describe('Client', () => { recipient: 'client@email.com' }; - controller.send(false, () => {}); + controller.send(); expect(controller.$http.get).not.toHaveBeenCalled(); }); @@ -104,84 +116,81 @@ describe('Client', () => { recipient: 'client@email.com' }; - controller.send(false, () => {}); + controller.send(); expect(controller.$http.get).not.toHaveBeenCalled(); }); it(`should perform an HTTP query without passing companyFk param`, () => { + $state.go = jest.fn(); + controller.$.sampleType.selection = { hasCompany: false, - code: 'MyReport' + code: 'my-report', + model: 'Clients' }; controller.clientSample = { recipientId: 1101, recipient: 'client@email.com' }; - const expectedParams = { - recipientId: 1101, - recipient: 'client@email.com' - }; - const serializedParams = $httpParamSerializer(expectedParams); - $httpBackend.expect('GET', `email/MyReport?${serializedParams}`).respond(true); - controller.send(false, () => {}); + const expectedPath = `Clients/${controller.client.id}/my-report-email`; + $httpBackend.expect('POST', expectedPath).respond(true); + controller.send(); $httpBackend.flush(); }); it(`should perform an HTTP query passing companyFk param`, () => { + $state.go = jest.fn(); + controller.$.sampleType.selection = { hasCompany: true, - code: 'MyReport' + code: 'my-report', + model: 'Clients' }; controller.clientSample = { recipientId: 1101, recipient: 'client@email.com', companyFk: 442 }; - const expectedParams = { - recipientId: 1101, - recipient: 'client@email.com', - companyId: 442 - }; - const serializedParams = $httpParamSerializer(expectedParams); - $httpBackend.expect('GET', `email/MyReport?${serializedParams}`).respond(true); - controller.send(false, () => {}); + const expectedPath = `Clients/${controller.client.id}/my-report-email`; + $httpBackend.expect('POST', expectedPath).respond(true); + controller.send(); $httpBackend.flush(); }); }); - describe('showPreview()', () => { + describe('preview()', () => { it(`should open a sample preview`, () => { jest.spyOn(controller.$.showPreview, 'show'); - controller.send = (isPreview, cb) => { - cb({ - data: '
' - }); + controller.$.sampleType.selection = { + hasCompany: true, + code: 'my-report', + model: 'Clients' }; - controller.showPreview(); + controller.clientSample = { + recipientId: 1101, + recipient: 'client@email.com', + companyFk: 442 + }; + + const expectedParams = { + companyId: 442, + recipientId: 1101 + }; + const serializedParams = $httpParamSerializer(expectedParams); + + const expectedPath = `Clients/${controller.client.id}/my-report-html?${serializedParams}`; + $httpBackend.expect('GET', expectedPath).respond(true); + controller.preview(); + $httpBackend.flush(); expect(controller.$.showPreview.show).toHaveBeenCalledWith(); }); }); - describe('sendSample()', () => { - it(`should perform a query (GET) and call go() method`, () => { - jest.spyOn(controller.$state, 'go'); - - controller.send = (isPreview, cb) => { - cb({ - data: true - }); - }; - controller.sendSample(); - - expect(controller.$state.go).toHaveBeenCalledWith('client.card.sample.index'); - }); - }); - describe('getWorkerEmail()', () => { it(`should perform a query and then set the replyTo property to the clientSample object`, () => { const expectedEmail = 'batman@arkhamcity.com'; diff --git a/modules/ticket/front/index/index.spec.js b/modules/ticket/front/index/index.spec.js index 84473686c..03071654e 100644 --- a/modules/ticket/front/index/index.spec.js +++ b/modules/ticket/front/index/index.spec.js @@ -96,8 +96,8 @@ describe('Component vnTicketIndex', () => { controller.setDelivered(); $httpBackend.flush(); - expect($window.open).toHaveBeenCalledWith(`Tickets/${tickets[1].id}/delivery-note-pdf`); - expect($window.open).toHaveBeenCalledWith(`Tickets/${tickets[2].id}/delivery-note-pdf`); + expect($window.open).toHaveBeenCalledWith(`api/Tickets/${tickets[1].id}/delivery-note-pdf`); + expect($window.open).toHaveBeenCalledWith(`api/Tickets/${tickets[2].id}/delivery-note-pdf`); }); }); From 1598b6c703f7d1674d05c3c3a8711736b6a055b1 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 4 Oct 2022 09:39:42 +0200 Subject: [PATCH 23/53] Back unit tests --- modules/client/front/sample/create/index.html | 5 ++++- .../back/methods/invoiceOut/specs/globalInvoicing.spec.js | 5 ++++- modules/ticket/back/methods/expedition/specs/filter.spec.js | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/client/front/sample/create/index.html b/modules/client/front/sample/create/index.html index 725d0cd0f..5df2b29ef 100644 --- a/modules/client/front/sample/create/index.html +++ b/modules/client/front/sample/create/index.html @@ -41,7 +41,8 @@ model="ClientSample.typeFk" data="samplesVisible" show-field="description" - label="Sample"> + label="Sample" + required="true">
@@ -79,9 +80,11 @@ diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js index e0ed6c91c..f7546b72e 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/globalInvoicing.spec.js @@ -8,6 +8,9 @@ describe('InvoiceOut globalInvoicing()', () => { const invoiceSerial = 'A'; const activeCtx = { accessToken: {userId: userId}, + __: value => { + return value; + } }; const ctx = {req: activeCtx}; @@ -22,7 +25,7 @@ describe('InvoiceOut globalInvoicing()', () => { invoiceDate: new Date(), maxShipped: new Date(), fromClientId: clientId, - toClientId: clientId, + toClientId: 1106, companyFk: companyFk }; const result = await models.InvoiceOut.globalInvoicing(ctx, options); diff --git a/modules/ticket/back/methods/expedition/specs/filter.spec.js b/modules/ticket/back/methods/expedition/specs/filter.spec.js index 85e98da4a..f643462cc 100644 --- a/modules/ticket/back/methods/expedition/specs/filter.spec.js +++ b/modules/ticket/back/methods/expedition/specs/filter.spec.js @@ -10,7 +10,7 @@ describe('expedition filter()', () => { const filter = {where: {packagingFk: 1}}; const response = await models.Expedition.filter(filter, options); - expect(response.length).toEqual(10); + expect(response.length).toBeGreaterThan(1); await tx.rollback(); } catch (e) { From eadff3fff93acf8268d09194f5a9904726dae7c7 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 4 Oct 2022 09:46:44 +0200 Subject: [PATCH 24/53] Updated back unit tests --- modules/client/back/models/client-consumption-queue.json | 2 +- modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/client/back/models/client-consumption-queue.json b/modules/client/back/models/client-consumption-queue.json index 328af00c5..e423f218c 100644 --- a/modules/client/back/models/client-consumption-queue.json +++ b/modules/client/back/models/client-consumption-queue.json @@ -8,7 +8,7 @@ }, "properties": { "params": { - "type": "json" + "type": "string" }, "queued": { "type": "date" diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index 7f2cbb442..2aa277b6f 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -138,7 +138,7 @@ module.exports = Self => { if (newInvoice.id) { await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions); - query = `INSERT IGNORE INTO invoiceOut_queue(invoiceFk) VALUES(?)`; + query = `INSERT IGNORE INTO invoiceOutQueue(invoiceFk) VALUES(?)`; await Self.rawSql(query, [newInvoice.id], myOptions); invoicesIds.push(newInvoice.id); From 377a0f722823a6d14b030fc8c6dbb3bc4a1a0cb6 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 4 Oct 2022 13:41:37 +0200 Subject: [PATCH 25/53] Attachments refactor --- db/changes/10490-august/00-ACL.sql | 6 +- e2e/paths/04-item/09_index.spec.js | 2 +- .../methods/client/clientDebtStatementHtml.js | 2 + .../methods/client/clientDebtStatementPdf.js | 61 ++++++++++++++++++ .../back/methods/client/creditRequestHtml.js | 2 + .../back/methods/client/creditRequestPdf.js | 56 +++++++++++++++++ .../client/incotermsAuthorizationHtml.js | 2 + .../client/incotermsAuthorizationPdf.js | 62 +++++++++++++++++++ .../back/methods/client/letterDebtorNdHtml.js | 2 + .../back/methods/client/letterDebtorPdf.js | 62 +++++++++++++++++++ .../back/methods/client/letterDebtorStHtml.js | 2 + modules/client/back/models/client-methods.js | 4 ++ modules/item/front/index/style.scss | 10 +++ print/common/css/email.css | 5 ++ .../attachment/assets/css/style.css | 11 ++-- .../components/attachment/attachment.html | 8 ++- .../core/components/attachment/attachment.js | 8 +-- print/core/email.js | 1 - print/core/mixins/prop-validator.js | 4 +- print/core/mixins/user-locale.js | 2 +- .../client-debt-statement/attachments.json | 6 -- .../client-debt-statement.js | 11 +++- .../email/credit-request/credit-request.js | 17 ++++- .../incoterms-authorization/attachments.json | 6 -- .../incoterms-authorization.js | 11 +++- .../email/letter-debtor-nd/attachments.json | 6 -- .../letter-debtor-nd/letter-debtor-nd.js | 11 +++- .../email/letter-debtor-st/attachments.json | 6 -- .../letter-debtor-st/letter-debtor-st.js | 11 +++- 29 files changed, 347 insertions(+), 50 deletions(-) create mode 100644 modules/client/back/methods/client/clientDebtStatementPdf.js create mode 100644 modules/client/back/methods/client/creditRequestPdf.js create mode 100644 modules/client/back/methods/client/incotermsAuthorizationPdf.js create mode 100644 modules/client/back/methods/client/letterDebtorPdf.js delete mode 100644 print/templates/email/client-debt-statement/attachments.json delete mode 100644 print/templates/email/incoterms-authorization/attachments.json delete mode 100644 print/templates/email/letter-debtor-nd/attachments.json delete mode 100644 print/templates/email/letter-debtor-st/attachments.json diff --git a/db/changes/10490-august/00-ACL.sql b/db/changes/10490-august/00-ACL.sql index 55852a38d..2cce197b2 100644 --- a/db/changes/10490-august/00-ACL.sql +++ b/db/changes/10490-august/00-ACL.sql @@ -8,18 +8,22 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp ('Client', 'campaignMetricsPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'campaignMetricsEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'clientWelcomeHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), - ('Client', 'clientWelcomeEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'),, + ('Client', 'clientWelcomeEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'creditRequestPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'creditRequestHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'creditRequestEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'printerSetupHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'printerSetupEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'sepaCoreEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'letterDebtorPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'letterDebtorStHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'letterDebtorStEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'letterDebtorNdHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'letterDebtorNdEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'clientDebtStatementPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'clientDebtStatementHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'clientDebtStatementEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), + ('Client', 'incotermsAuthorizationPdf', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'incotermsAuthorizationHtml', 'READ', 'ALLOW', 'ROLE', 'employee'), ('Client', 'incotermsAuthorizationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Client', 'consumptionSendQueued', 'WRITE', 'ALLOW', 'ROLE', 'system'), diff --git a/e2e/paths/04-item/09_index.spec.js b/e2e/paths/04-item/09_index.spec.js index 6e0a4bd5c..03492f8c1 100644 --- a/e2e/paths/04-item/09_index.spec.js +++ b/e2e/paths/04-item/09_index.spec.js @@ -1,7 +1,7 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; -describe('Item index path', () => { +fdescribe('Item index path', () => { let browser; let page; beforeAll(async() => { diff --git a/modules/client/back/methods/client/clientDebtStatementHtml.js b/modules/client/back/methods/client/clientDebtStatementHtml.js index 76502ff6c..bfed696bc 100644 --- a/modules/client/back/methods/client/clientDebtStatementHtml.js +++ b/modules/client/back/methods/client/clientDebtStatementHtml.js @@ -46,6 +46,7 @@ module.exports = Self => { }); Self.clientDebtStatementHtml = async(ctx, id) => { + const {accessToken} = ctx.req; const args = Object.assign({}, ctx.args); const params = {lang: ctx.req.getLocale()}; @@ -54,6 +55,7 @@ module.exports = Self => { params[param] = args[param]; params.isPreview = true; + params.access_token = accessToken.id; const report = new Email('client-debt-statement', params); const html = await report.render(); diff --git a/modules/client/back/methods/client/clientDebtStatementPdf.js b/modules/client/back/methods/client/clientDebtStatementPdf.js new file mode 100644 index 000000000..8e2dca314 --- /dev/null +++ b/modules/client/back/methods/client/clientDebtStatementPdf.js @@ -0,0 +1,61 @@ +const {Report} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('clientDebtStatementPdf', { + description: 'Returns the client debt statement pdf', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + }, + { + arg: 'from', + type: 'string', + required: true + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/client-debt-statement-pdf', + verb: 'GET' + } + }); + + Self.clientDebtStatementPdf = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('client-debt-statement', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/methods/client/creditRequestHtml.js b/modules/client/back/methods/client/creditRequestHtml.js index 303308615..6b2d7fe4e 100644 --- a/modules/client/back/methods/client/creditRequestHtml.js +++ b/modules/client/back/methods/client/creditRequestHtml.js @@ -41,6 +41,7 @@ module.exports = Self => { }); Self.creditRequestHtml = async(ctx, id) => { + const {accessToken} = ctx.req; const args = Object.assign({}, ctx.args); const params = {lang: ctx.req.getLocale()}; @@ -49,6 +50,7 @@ module.exports = Self => { params[param] = args[param]; params.isPreview = true; + params.access_token = accessToken.id; const report = new Email('credit-request', params); const html = await report.render(); diff --git a/modules/client/back/methods/client/creditRequestPdf.js b/modules/client/back/methods/client/creditRequestPdf.js new file mode 100644 index 000000000..2e3dc0619 --- /dev/null +++ b/modules/client/back/methods/client/creditRequestPdf.js @@ -0,0 +1,56 @@ +const {Report} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('creditRequestPdf', { + description: 'Returns the credit request pdf', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/credit-request-pdf', + verb: 'GET' + } + }); + + Self.creditRequestPdf = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('credit-request', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/methods/client/incotermsAuthorizationHtml.js b/modules/client/back/methods/client/incotermsAuthorizationHtml.js index f8c3e6e60..875495d93 100644 --- a/modules/client/back/methods/client/incotermsAuthorizationHtml.js +++ b/modules/client/back/methods/client/incotermsAuthorizationHtml.js @@ -47,6 +47,7 @@ module.exports = Self => { }); Self.incotermsAuthorizationHtml = async(ctx, id) => { + const {accessToken} = ctx.req; const args = Object.assign({}, ctx.args); const params = {lang: ctx.req.getLocale()}; @@ -55,6 +56,7 @@ module.exports = Self => { params[param] = args[param]; params.isPreview = true; + params.access_token = accessToken.id; const report = new Email('incoterms-authorization', params); const html = await report.render(); diff --git a/modules/client/back/methods/client/incotermsAuthorizationPdf.js b/modules/client/back/methods/client/incotermsAuthorizationPdf.js new file mode 100644 index 000000000..9a8a8d296 --- /dev/null +++ b/modules/client/back/methods/client/incotermsAuthorizationPdf.js @@ -0,0 +1,62 @@ +const {Report} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('incotermsAuthorizationPdf', { + description: 'Returns the incoterms authorization pdf', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + }, + { + arg: 'companyId', + type: 'number', + description: 'The company id', + required: true + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/incoterms-authorization-pdf', + verb: 'GET' + } + }); + + Self.incotermsAuthorizationPdf = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('incoterms-authorization', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/methods/client/letterDebtorNdHtml.js b/modules/client/back/methods/client/letterDebtorNdHtml.js index d709a3cee..320fbaef3 100644 --- a/modules/client/back/methods/client/letterDebtorNdHtml.js +++ b/modules/client/back/methods/client/letterDebtorNdHtml.js @@ -47,6 +47,7 @@ module.exports = Self => { }); Self.letterDebtorNdHtml = async(ctx, id) => { + const {accessToken} = ctx.req; const args = Object.assign({}, ctx.args); const params = {lang: ctx.req.getLocale()}; @@ -55,6 +56,7 @@ module.exports = Self => { params[param] = args[param]; params.isPreview = true; + params.access_token = accessToken.id; const report = new Email('letter-debtor-nd', params); const html = await report.render(); diff --git a/modules/client/back/methods/client/letterDebtorPdf.js b/modules/client/back/methods/client/letterDebtorPdf.js new file mode 100644 index 000000000..421d531e6 --- /dev/null +++ b/modules/client/back/methods/client/letterDebtorPdf.js @@ -0,0 +1,62 @@ +const {Report} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('letterDebtorPdf', { + description: 'Returns the letter debtor pdf', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The client id', + http: {source: 'path'} + }, + { + arg: 'recipientId', + type: 'number', + description: 'The recipient id', + required: false + }, + { + arg: 'companyId', + type: 'number', + description: 'The company id', + required: true + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/letter-debtor-pdf', + verb: 'GET' + } + }); + + Self.letterDebtorPdf = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('letter-debtor', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/methods/client/letterDebtorStHtml.js b/modules/client/back/methods/client/letterDebtorStHtml.js index b97ce9767..acf75272b 100644 --- a/modules/client/back/methods/client/letterDebtorStHtml.js +++ b/modules/client/back/methods/client/letterDebtorStHtml.js @@ -47,6 +47,7 @@ module.exports = Self => { }); Self.letterDebtorStHtml = async(ctx, id) => { + const {accessToken} = ctx.req; const args = Object.assign({}, ctx.args); const params = {lang: ctx.req.getLocale()}; @@ -55,6 +56,7 @@ module.exports = Self => { params[param] = args[param]; params.isPreview = true; + params.access_token = accessToken.id; const report = new Email('letter-debtor-st', params); const html = await report.render(); diff --git a/modules/client/back/models/client-methods.js b/modules/client/back/models/client-methods.js index bacbea727..04d10413a 100644 --- a/modules/client/back/models/client-methods.js +++ b/modules/client/back/models/client-methods.js @@ -32,14 +32,18 @@ module.exports = Self => { require('../methods/client/printerSetupHtml')(Self); require('../methods/client/printerSetupEmail')(Self); require('../methods/client/sepaCoreEmail')(Self); + require('../methods/client/letterDebtorPdf')(Self); require('../methods/client/letterDebtorStHtml')(Self); require('../methods/client/letterDebtorStEmail')(Self); require('../methods/client/letterDebtorNdHtml')(Self); require('../methods/client/letterDebtorNdEmail')(Self); + require('../methods/client/clientDebtStatementPdf')(Self); require('../methods/client/clientDebtStatementHtml')(Self); require('../methods/client/clientDebtStatementEmail')(Self); + require('../methods/client/creditRequestPdf')(Self); require('../methods/client/creditRequestHtml')(Self); require('../methods/client/creditRequestEmail')(Self); + require('../methods/client/incotermsAuthorizationPdf')(Self); require('../methods/client/incotermsAuthorizationHtml')(Self); require('../methods/client/incotermsAuthorizationEmail')(Self); require('../methods/client/consumptionSendQueued')(Self); diff --git a/modules/item/front/index/style.scss b/modules/item/front/index/style.scss index 451dd09ae..e9fd9f935 100644 --- a/modules/item/front/index/style.scss +++ b/modules/item/front/index/style.scss @@ -21,4 +21,14 @@ vn-item-product { vn-label-value:first-of-type section{ margin-top: 9px; } +} + +vn-item-index { + table { + img { + border-radius: 50%; + width: 50px; + height: 50px; + } + } } \ No newline at end of file diff --git a/print/common/css/email.css b/print/common/css/email.css index 6e6350ff5..5fe3b955e 100644 --- a/print/common/css/email.css +++ b/print/common/css/email.css @@ -31,3 +31,8 @@ h1 { font-weight: 100; font-size: 1.5em } + +h6 { + font-weight: 100; + font-size: 1.2em +} diff --git a/print/core/components/attachment/assets/css/style.css b/print/core/components/attachment/assets/css/style.css index 775c43ada..37fde9285 100644 --- a/print/core/components/attachment/assets/css/style.css +++ b/print/core/components/attachment/assets/css/style.css @@ -4,19 +4,22 @@ div { } a { - background-color: #F5F5F5; + background-color: #fcfcfc; border: 1px solid #CCC; display: flex; vertical-align: middle; box-sizing: border-box; min-width: 150px; text-decoration: none; - border-radius: 3px; + border-radius: 8px; color: #8dba25 } a > div.icon { + border-radius: 5px; + padding: 2px 5px; + background-color: red; font-weight: bold; - font-size: 18px; - color: #555 + font-size: 12px; + color: #FFF } \ No newline at end of file diff --git a/print/core/components/attachment/attachment.html b/print/core/components/attachment/attachment.html index 88fa64434..0044190a7 100644 --- a/print/core/components/attachment/attachment.html +++ b/print/core/components/attachment/attachment.html @@ -1,6 +1,10 @@ -
+ \ No newline at end of file diff --git a/print/core/components/attachment/attachment.js b/print/core/components/attachment/attachment.js index 5c78a895c..30e1944a4 100755 --- a/print/core/components/attachment/attachment.js +++ b/print/core/components/attachment/attachment.js @@ -4,10 +4,10 @@ module.exports = { attachmentPath() { const filename = this.attachment.filename; const component = this.attachment.component; - if (this.attachment.cid) + if (this.attachment.cid && component) return `/api/${component}/assets/files/${filename}`; - else - return `/api/report/${component}?${this.getHttpParams()}`; + else if (this.attachment.path) + return `/api/${this.attachment.path}?${this.getHttpParams()}`; } }, methods: { @@ -15,7 +15,7 @@ module.exports = { const props = this.args; let query = ''; for (let param in props) { - if (!(props[param] instanceof Object)) { + if (props[param] && !(props[param] instanceof Object)) { if (query != '') query += '&'; query += `${param}=${props[param]}`; } diff --git a/print/core/email.js b/print/core/email.js index 353b70367..0184e360c 100644 --- a/print/core/email.js +++ b/print/core/email.js @@ -1,6 +1,5 @@ const path = require('path'); const smtp = require('./smtp'); -const config = require('./config'); const Component = require('./component'); const Report = require('./report'); diff --git a/print/core/mixins/prop-validator.js b/print/core/mixins/prop-validator.js index 16c71a6db..cb41d3dd8 100644 --- a/print/core/mixins/prop-validator.js +++ b/print/core/mixins/prop-validator.js @@ -4,7 +4,7 @@ const validator = { const props = this.$options.props; const invalidProps = []; - for (prop in props) { + for (const prop in props) { const isObject = typeof props[prop] === 'object'; const isRequired = props[prop].required; const isNotDefined = this[prop] === undefined; @@ -19,7 +19,7 @@ const validator = { throw new Error(`Required properties not found [${required}]`); } }, - props: ['isPreview', 'authorization'] + props: ['isPreview', 'access_token'] }; Vue.mixin(validator); diff --git a/print/core/mixins/user-locale.js b/print/core/mixins/user-locale.js index 0e4727334..18b4c68c5 100644 --- a/print/core/mixins/user-locale.js +++ b/print/core/mixins/user-locale.js @@ -24,7 +24,7 @@ const userLocale = { }); } }, - props: ['auth', 'recipientId'] + props: ['recipientId'] }; Vue.mixin(userLocale); diff --git a/print/templates/email/client-debt-statement/attachments.json b/print/templates/email/client-debt-statement/attachments.json deleted file mode 100644 index 9cc4911e6..000000000 --- a/print/templates/email/client-debt-statement/attachments.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "filename": "client-debt-statement.pdf", - "component": "client-debt-statement" - } -] \ No newline at end of file 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 4d5499960..85b3c5cc3 100755 --- a/print/templates/email/client-debt-statement/client-debt-statement.js +++ b/print/templates/email/client-debt-statement/client-debt-statement.js @@ -2,7 +2,6 @@ const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); -const attachments = require('./attachments.json'); module.exports = { name: 'client-debt-statement', @@ -12,7 +11,15 @@ module.exports = { 'attachment': attachment.build() }, data() { - return {attachments}; + return { + attachments: [ + { + filename: 'client-debt-statement.pdf', + type: 'pdf', + path: `Clients/${this.id}/client-debt-statement-pdf` + } + ] + }; }, props: { id: { diff --git a/print/templates/email/credit-request/credit-request.js b/print/templates/email/credit-request/credit-request.js index 79c33ba0c..8f68d56c0 100755 --- a/print/templates/email/credit-request/credit-request.js +++ b/print/templates/email/credit-request/credit-request.js @@ -2,7 +2,6 @@ const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); -const attachments = require('./attachments.json'); module.exports = { name: 'credit-request', @@ -12,6 +11,20 @@ module.exports = { 'attachment': attachment.build() }, data() { - return {attachments}; + return { + attachments: [ + { + filename: 'credit-request.pdf', + type: 'pdf', + path: `Clients/${this.id}/credit-request-pdf` + } + ] + }; }, + props: { + id: { + type: Number, + required: true + } + } }; diff --git a/print/templates/email/incoterms-authorization/attachments.json b/print/templates/email/incoterms-authorization/attachments.json deleted file mode 100644 index 9dfd945db..000000000 --- a/print/templates/email/incoterms-authorization/attachments.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "filename": "incoterms-authorization.pdf", - "component": "incoterms-authorization" - } -] \ No newline at end of file diff --git a/print/templates/email/incoterms-authorization/incoterms-authorization.js b/print/templates/email/incoterms-authorization/incoterms-authorization.js index f8db74e0e..b1c7286dd 100755 --- a/print/templates/email/incoterms-authorization/incoterms-authorization.js +++ b/print/templates/email/incoterms-authorization/incoterms-authorization.js @@ -2,12 +2,19 @@ const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); -const attachments = require('./attachments.json'); module.exports = { name: 'incoterms-authorization', data() { - return {attachments}; + return { + attachments: [ + { + filename: 'incoterms-authorization.pdf', + type: 'pdf', + path: `Clients/${this.id}/incoterms-authorization-pdf` + } + ] + }; }, components: { 'email-header': emailHeader.build(), diff --git a/print/templates/email/letter-debtor-nd/attachments.json b/print/templates/email/letter-debtor-nd/attachments.json deleted file mode 100644 index 1e21ea343..000000000 --- a/print/templates/email/letter-debtor-nd/attachments.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "filename": "letter-debtor.pdf", - "component": "letter-debtor" - } -] \ No newline at end of file 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 a51797fa1..cf9cc7ddd 100755 --- a/print/templates/email/letter-debtor-nd/letter-debtor-nd.js +++ b/print/templates/email/letter-debtor-nd/letter-debtor-nd.js @@ -2,7 +2,6 @@ const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); -const attachments = require('./attachments.json'); module.exports = { name: 'letter-debtor-nd', @@ -13,7 +12,15 @@ module.exports = { throw new Error('Something went wrong'); }, data() { - return {attachments}; + return { + attachments: [ + { + filename: 'letter-debtor.pdf', + type: 'pdf', + path: `Clients/${this.id}/letter-debtor-pdf` + } + ] + }; }, methods: { fetchDebtor(id, companyId) { diff --git a/print/templates/email/letter-debtor-st/attachments.json b/print/templates/email/letter-debtor-st/attachments.json deleted file mode 100644 index 1e21ea343..000000000 --- a/print/templates/email/letter-debtor-st/attachments.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "filename": "letter-debtor.pdf", - "component": "letter-debtor" - } -] \ No newline at end of file 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 9f357e6de..1a6555673 100755 --- a/print/templates/email/letter-debtor-st/letter-debtor-st.js +++ b/print/templates/email/letter-debtor-st/letter-debtor-st.js @@ -2,7 +2,6 @@ const Component = require(`vn-print/core/component`); const emailHeader = new Component('email-header'); const emailFooter = new Component('email-footer'); const attachment = new Component('attachment'); -const attachments = require('./attachments.json'); module.exports = { name: 'letter-debtor-st', @@ -13,7 +12,15 @@ module.exports = { throw new Error('Something went wrong'); }, data() { - return {attachments}; + return { + attachments: [ + { + filename: 'letter-debtor.pdf', + type: 'pdf', + path: `Clients/${this.id}/letter-debtor-pdf` + } + ] + }; }, methods: { fetchDebtor(id, companyId) { From f256af3d02f494332ede22344cf4fbb7f09918b8 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 4 Oct 2022 14:48:28 +0200 Subject: [PATCH 26/53] Log host ip --- back/tests.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/back/tests.js b/back/tests.js index 809906177..3ab31afee 100644 --- a/back/tests.js +++ b/back/tests.js @@ -18,6 +18,9 @@ async function test() { await container.run(isCI); dataSources = JSON.parse(JSON.stringify(dataSources)); + console.log('host ', container.dbConf.host); + console.log('port ', container.dbConf.port); + Object.assign(dataSources.vn, { host: container.dbConf.host, port: container.dbConf.port From 98a2f796914ddded3ed35ce789b9f620545948ee Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 10:05:01 +0200 Subject: [PATCH 27/53] Run container on jenkins network --- db/docker.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/db/docker.js b/db/docker.js index 34026f85f..e22d935ae 100644 --- a/db/docker.js +++ b/db/docker.js @@ -43,7 +43,12 @@ module.exports = class Docker { let runChown = process.platform != 'linux'; log('Starting container...'); - const container = await this.execP(`docker run --env RUN_CHOWN=${runChown} -d ${dockerArgs} salix-db`); + const container = await this.execP(` + docker run + --network jenkins_default + --env RUN_CHOWN=${runChown} + -d ${dockerArgs} salix-db + `); this.id = container.stdout.trim(); try { From 13bfed69553b6ff3e24d3678254dd8cd059ed514 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 10:06:11 +0200 Subject: [PATCH 28/53] use jenkins network --- db/docker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/docker.js b/db/docker.js index e22d935ae..18d2cdab4 100644 --- a/db/docker.js +++ b/db/docker.js @@ -45,7 +45,7 @@ module.exports = class Docker { log('Starting container...'); const container = await this.execP(` docker run - --network jenkins_default + --network="jenkins_default" --env RUN_CHOWN=${runChown} -d ${dockerArgs} salix-db `); From 1534bdd1886ccab5ec7b2466bb91e5efa57ab933 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 10:16:17 +0200 Subject: [PATCH 29/53] Syntax error --- db/docker.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/db/docker.js b/db/docker.js index 18d2cdab4..32462e07e 100644 --- a/db/docker.js +++ b/db/docker.js @@ -44,9 +44,9 @@ module.exports = class Docker { log('Starting container...'); const container = await this.execP(` - docker run - --network="jenkins_default" - --env RUN_CHOWN=${runChown} + docker run \ + --network="jenkins_default" \ + --env RUN_CHOWN=${runChown} \ -d ${dockerArgs} salix-db `); this.id = container.stdout.trim(); From b0dac6c12df2d87104c9c7eb8fbaee86a6fcebe7 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 10:23:24 +0200 Subject: [PATCH 30/53] Use jenkins network --- db/docker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/docker.js b/db/docker.js index 32462e07e..32fec0038 100644 --- a/db/docker.js +++ b/db/docker.js @@ -45,7 +45,7 @@ module.exports = class Docker { log('Starting container...'); const container = await this.execP(` docker run \ - --network="jenkins_default" \ + --network="jenkins" \ --env RUN_CHOWN=${runChown} \ -d ${dockerArgs} salix-db `); From 80d0b415ec60e6b8d8411406fdc26243580c3a75 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 10:28:07 +0200 Subject: [PATCH 31/53] Host log --- db/docker.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/db/docker.js b/db/docker.js index 32fec0038..bca84aa08 100644 --- a/db/docker.js +++ b/db/docker.js @@ -60,6 +60,8 @@ module.exports = class Docker { this.dbConf.host = netSettings.Gateway; this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; + + console.log('Container host: ', this.dbConf.host); } await this.wait(); From ee0938d7d64e446311837e46420a08515a823c66 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 10:36:05 +0200 Subject: [PATCH 32/53] Test --- db/docker.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/db/docker.js b/db/docker.js index bca84aa08..32fec0038 100644 --- a/db/docker.js +++ b/db/docker.js @@ -60,8 +60,6 @@ module.exports = class Docker { this.dbConf.host = netSettings.Gateway; this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; - - console.log('Container host: ', this.dbConf.host); } await this.wait(); From 239c324eff255ddce1918574342552a738b09875 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 11:03:48 +0200 Subject: [PATCH 33/53] Log network settings --- db/docker.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/db/docker.js b/db/docker.js index 32fec0038..29ed6d25d 100644 --- a/db/docker.js +++ b/db/docker.js @@ -56,8 +56,12 @@ module.exports = class Docker { let inspect = await this.execP(`docker inspect -f "{{json .NetworkSettings}}" ${this.id}`); let netSettings = JSON.parse(inspect.stdout); - if (ci) + if (ci) { + console.log('Running on CI...'); this.dbConf.host = netSettings.Gateway; + } + + console.log(netSettings); this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; } From 0fccae0113341645f9cbddaa686d278471c2039a Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 11:06:23 +0200 Subject: [PATCH 34/53] Network ip address --- db/docker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/db/docker.js b/db/docker.js index 29ed6d25d..0b3c281e9 100644 --- a/db/docker.js +++ b/db/docker.js @@ -58,7 +58,8 @@ module.exports = class Docker { if (ci) { console.log('Running on CI...'); - this.dbConf.host = netSettings.Gateway; + // this.dbConf.host = netSettings.Gateway; + this.dbConf.host = netSettings.Networks.jenkins.IPAddress; } console.log(netSettings); From 0ad583f22f2661fcb1ac82bcbfd154a6e9a6c0ee Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 11:14:49 +0200 Subject: [PATCH 35/53] Log host & port --- db/docker.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/db/docker.js b/db/docker.js index 0b3c281e9..016cdbe12 100644 --- a/db/docker.js +++ b/db/docker.js @@ -62,9 +62,11 @@ module.exports = class Docker { this.dbConf.host = netSettings.Networks.jenkins.IPAddress; } - console.log(netSettings); + // console.log(netSettings); this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; + console.log('Host: ', this.dbConf.host); + console.log('Port: ', this.dbConf.host); } await this.wait(); From 0502f9ebf0c95957b3fce6f04e02f281c2820e71 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 11:19:07 +0200 Subject: [PATCH 36/53] Log port --- db/docker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/docker.js b/db/docker.js index 016cdbe12..6342ba548 100644 --- a/db/docker.js +++ b/db/docker.js @@ -66,7 +66,7 @@ module.exports = class Docker { this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; console.log('Host: ', this.dbConf.host); - console.log('Port: ', this.dbConf.host); + console.log('Port: ', this.dbConf.port); } await this.wait(); From e6512d00a13410d09b37deca520b2c9a804a032d Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 12:16:59 +0200 Subject: [PATCH 37/53] Use port 3306 --- db/docker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/db/docker.js b/db/docker.js index 6342ba548..a844c13f2 100644 --- a/db/docker.js +++ b/db/docker.js @@ -64,7 +64,8 @@ module.exports = class Docker { // console.log(netSettings); - this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; + // this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; + this.dbConf.port = 3306; console.log('Host: ', this.dbConf.host); console.log('Port: ', this.dbConf.port); } From 1cafbdab6ec8af0d8e57c3b20feaab63002367c5 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 12:26:42 +0200 Subject: [PATCH 38/53] Connect to docker network --- db/docker.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/db/docker.js b/db/docker.js index a844c13f2..3bf05cc9b 100644 --- a/db/docker.js +++ b/db/docker.js @@ -57,17 +57,12 @@ module.exports = class Docker { let netSettings = JSON.parse(inspect.stdout); if (ci) { - console.log('Running on CI...'); - // this.dbConf.host = netSettings.Gateway; this.dbConf.host = netSettings.Networks.jenkins.IPAddress; - } + this.dbConf.port = 3306; - // console.log(netSettings); - - // this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; - this.dbConf.port = 3306; - console.log('Host: ', this.dbConf.host); - console.log('Port: ', this.dbConf.port); + await this.execP(`docker network connect jenkins ${this.id}`); + } else + this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; } await this.wait(); From 627f0d762e4653b648bb0fbbb33ee1828c368281 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 12:33:06 +0200 Subject: [PATCH 39/53] attach to network --- db/docker.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/db/docker.js b/db/docker.js index 3bf05cc9b..1ab4115e5 100644 --- a/db/docker.js +++ b/db/docker.js @@ -45,7 +45,6 @@ module.exports = class Docker { log('Starting container...'); const container = await this.execP(` docker run \ - --network="jenkins" \ --env RUN_CHOWN=${runChown} \ -d ${dockerArgs} salix-db `); @@ -53,14 +52,15 @@ module.exports = class Docker { try { if (this.isRandom) { + if (ci) + await this.execP(`docker network connect jenkins ${this.id}`); + let inspect = await this.execP(`docker inspect -f "{{json .NetworkSettings}}" ${this.id}`); let netSettings = JSON.parse(inspect.stdout); if (ci) { this.dbConf.host = netSettings.Networks.jenkins.IPAddress; this.dbConf.port = 3306; - - await this.execP(`docker network connect jenkins ${this.id}`); } else this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; } From 9644e1e5ec44190d7d25e2841ae3af91638a11f1 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 12:37:16 +0200 Subject: [PATCH 40/53] Removed console.log --- back/tests.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/back/tests.js b/back/tests.js index 3ab31afee..809906177 100644 --- a/back/tests.js +++ b/back/tests.js @@ -18,9 +18,6 @@ async function test() { await container.run(isCI); dataSources = JSON.parse(JSON.stringify(dataSources)); - console.log('host ', container.dbConf.host); - console.log('port ', container.dbConf.port); - Object.assign(dataSources.vn, { host: container.dbConf.host, port: container.dbConf.port From 8468eda05aa426bb4c58144016359dd128d16085 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 12:47:37 +0200 Subject: [PATCH 41/53] run with network --- db/docker.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/db/docker.js b/db/docker.js index 1ab4115e5..b52c2639b 100644 --- a/db/docker.js +++ b/db/docker.js @@ -42,9 +42,13 @@ module.exports = class Docker { let runChown = process.platform != 'linux'; + let network = ''; + if (ci) network = '--network="jenkins"'; + log('Starting container...'); const container = await this.execP(` docker run \ + ${network} \ --env RUN_CHOWN=${runChown} \ -d ${dockerArgs} salix-db `); @@ -52,9 +56,6 @@ module.exports = class Docker { try { if (this.isRandom) { - if (ci) - await this.execP(`docker network connect jenkins ${this.id}`); - let inspect = await this.execP(`docker inspect -f "{{json .NetworkSettings}}" ${this.id}`); let netSettings = JSON.parse(inspect.stdout); From 6f8e2c8e7974a6e9003d5eeb93c360b2a31b90bb Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 13:01:28 +0200 Subject: [PATCH 42/53] Disabled junit --- back/tests.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/back/tests.js b/back/tests.js index 809906177..38dcc6384 100644 --- a/back/tests.js +++ b/back/tests.js @@ -41,12 +41,12 @@ async function test() { } })); - if (isCI) { - const JunitReporter = require('jasmine-reporters'); - jasmine.addReporter(new JunitReporter.JUnitXmlReporter()); + // if (isCI) { + // const JunitReporter = require('jasmine-reporters'); + // jasmine.addReporter(new JunitReporter.JUnitXmlReporter()); - jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; - } + // jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; + // } const backSpecs = [ './back/**/*[sS]pec.js', From f2407ceb0e7831e2c509942e0838b83cc29130a5 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 13:17:29 +0200 Subject: [PATCH 43/53] Removed focus --- e2e/paths/04-item/09_index.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/paths/04-item/09_index.spec.js b/e2e/paths/04-item/09_index.spec.js index 03492f8c1..6e0a4bd5c 100644 --- a/e2e/paths/04-item/09_index.spec.js +++ b/e2e/paths/04-item/09_index.spec.js @@ -1,7 +1,7 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; -fdescribe('Item index path', () => { +describe('Item index path', () => { let browser; let page; beforeAll(async() => { From 726b2d5eb2cac2aa9887026f0512d46c76d715ee Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 13:26:18 +0200 Subject: [PATCH 44/53] Exit on completion --- back/tests.js | 3 ++- modules/invoiceOut/back/methods/invoiceOut/download.js | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/back/tests.js b/back/tests.js index 38dcc6384..725aec6e4 100644 --- a/back/tests.js +++ b/back/tests.js @@ -60,7 +60,8 @@ async function test() { helpers: [], }); - jasmine.exitOnCompletion = false; + if (!isCI) jasmine.exitOnCompletion = false; + await jasmine.execute(); if (app) await app.disconnect(); if (container) await container.rm(); diff --git a/modules/invoiceOut/back/methods/invoiceOut/download.js b/modules/invoiceOut/back/methods/invoiceOut/download.js index 19dea5b1a..74f5c95fe 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/download.js +++ b/modules/invoiceOut/back/methods/invoiceOut/download.js @@ -62,8 +62,14 @@ module.exports = Self => { name: fileName }; - await fs.access(file.path); - let stream = fs.createReadStream(file.path); + try { + await fs.access(file.path); + } catch (error) { + await Self.createPdf(ctx, id); + } + + const stream = fs.createReadStream(file.path); + return [stream, file.contentType, `filename="${file.name}"`]; } catch (error) { if (error.code === 'ENOENT') From df929c77ce345ed48c560c4b402b2c69fcac1307 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 13:32:43 +0200 Subject: [PATCH 45/53] Test --- back/tests.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/back/tests.js b/back/tests.js index 725aec6e4..e9eaf386e 100644 --- a/back/tests.js +++ b/back/tests.js @@ -41,12 +41,12 @@ async function test() { } })); - // if (isCI) { - // const JunitReporter = require('jasmine-reporters'); - // jasmine.addReporter(new JunitReporter.JUnitXmlReporter()); + if (isCI) { + const JunitReporter = require('jasmine-reporters'); + jasmine.addReporter(new JunitReporter.JUnitXmlReporter()); - // jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; - // } + jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; + } const backSpecs = [ './back/**/*[sS]pec.js', @@ -61,6 +61,8 @@ async function test() { }); if (!isCI) jasmine.exitOnCompletion = false; + else + jasmine.exitOnCompletion = true; await jasmine.execute(); if (app) await app.disconnect(); From 076fce058c1bb91bfa135d6184faad28092711a6 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 13:38:17 +0200 Subject: [PATCH 46/53] Exit on completion --- back/tests.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/back/tests.js b/back/tests.js index e9eaf386e..96f3258a7 100644 --- a/back/tests.js +++ b/back/tests.js @@ -41,11 +41,14 @@ async function test() { } })); + jasmine.exitOnCompletion = false; + if (isCI) { const JunitReporter = require('jasmine-reporters'); jasmine.addReporter(new JunitReporter.JUnitXmlReporter()); jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; + jasmine.exitOnCompletion = true; } const backSpecs = [ @@ -60,10 +63,6 @@ async function test() { helpers: [], }); - if (!isCI) jasmine.exitOnCompletion = false; - else - jasmine.exitOnCompletion = true; - await jasmine.execute(); if (app) await app.disconnect(); if (container) await container.rm(); From 45ccf782f859c41dfef1be8487cf270dfd495ac0 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 13:45:19 +0200 Subject: [PATCH 47/53] 3 workers --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4a1f9ba54..3d2be8b41 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -58,7 +58,7 @@ pipeline { stage('Frontend') { steps { nodejs('node-v14') { - sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2' + sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=3' } } } From 182d47f3ef404c373ffa734615311dde0291ef20 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 13:50:51 +0200 Subject: [PATCH 48/53] two workers --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 3d2be8b41..4a1f9ba54 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -58,7 +58,7 @@ pipeline { stage('Frontend') { steps { nodejs('node-v14') { - sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=3' + sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2' } } } From 7844ae27955ee5e08820ace70755e3ed4bc8bf1e Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 13:53:51 +0200 Subject: [PATCH 49/53] 3 workers --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4a1f9ba54..3d2be8b41 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -58,7 +58,7 @@ pipeline { stage('Frontend') { steps { nodejs('node-v14') { - sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2' + sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=3' } } } From 5fa96277abe4b5b2d01ee61bcfe0bba669b37082 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 13:58:46 +0200 Subject: [PATCH 50/53] two workers --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 3d2be8b41..4a1f9ba54 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -58,7 +58,7 @@ pipeline { stage('Frontend') { steps { nodejs('node-v14') { - sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=3' + sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2' } } } From 68d7bc8e20ab33acf30a73fc6b8ef3b15567393c Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 14:14:05 +0200 Subject: [PATCH 51/53] Test --- back/tests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/back/tests.js b/back/tests.js index 96f3258a7..60b2e2e1d 100644 --- a/back/tests.js +++ b/back/tests.js @@ -66,7 +66,7 @@ async function test() { await jasmine.execute(); if (app) await app.disconnect(); if (container) await container.rm(); - console.log('app disconnected & container removed'); + console.log('App disconnected & container removed'); } test(); From b8615fef46d0d9eda316b0795ef7e45d215c3105 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 14:30:13 +0200 Subject: [PATCH 52/53] Upgraded puppeteer --- print/package-lock.json | 1676 --------------------------------------- print/package.json | 2 +- 2 files changed, 1 insertion(+), 1677 deletions(-) delete mode 100644 print/package-lock.json diff --git a/print/package-lock.json b/print/package-lock.json deleted file mode 100644 index c824de5df..000000000 --- a/print/package-lock.json +++ /dev/null @@ -1,1676 +0,0 @@ -{ - "name": "vn-print", - "version": "2.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/mime-types": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz", - "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=" - }, - "agent-base": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", - "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==" - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" - }, - "buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "cheerio": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", - "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash.assignin": "^4.0.9", - "lodash.bind": "^4.1.4", - "lodash.defaults": "^4.0.1", - "lodash.filter": "^4.4.0", - "lodash.flatten": "^4.2.0", - "lodash.foreach": "^4.3.0", - "lodash.map": "^4.4.0", - "lodash.merge": "^4.4.0", - "lodash.pick": "^4.2.1", - "lodash.reduce": "^4.4.0", - "lodash.reject": "^4.4.0", - "lodash.some": "^4.4.0" - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "datauri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/datauri/-/datauri-2.0.0.tgz", - "integrity": "sha512-zS2HSf9pI5XPlNZgIqJg/wCJpecgU/HA6E/uv2EfaWnW1EiTGLfy/EexTIsC9c99yoCOTXlqeeWk4FkCSuO3/g==", - "requires": { - "image-size": "^0.7.3", - "mimer": "^1.0.0" - } - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "denque": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", - "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==" - }, - "dijkstrajs": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.1.tgz", - "integrity": "sha1-082BIh4+pAdCz83lVtTpnpjdxxs=" - }, - "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", - "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" - } - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extract-zip": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", - "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", - "requires": { - "concat-stream": "^1.6.2", - "debug": "^2.6.9", - "mkdirp": "^0.5.4", - "yauzl": "^2.10.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "requires": { - "pend": "~1.2.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "requires": { - "is-property": "^1.0.2" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", - "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=" - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-proxy-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", - "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", - "requires": { - "agent-base": "5", - "debug": "4" - } - }, - "iconv-lite": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", - "integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "image-size": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", - "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "intl": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/intl/-/intl-1.2.5.tgz", - "integrity": "sha1-giRKIZDE5Bn4Nx9ao02qNCDiq94=" - }, - "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", - "requires": { - "has": "^1.0.3" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsonexport": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonexport/-/jsonexport-3.2.0.tgz", - "integrity": "sha512-GbO9ugb0YTZatPd/hqCGR0FSwbr82H6OzG04yzdrG7XOe4QZ0jhQ+kOsB29zqkzoYJLmLxbbrFiuwbQu891XnQ==" - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "juice": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/juice/-/juice-5.2.0.tgz", - "integrity": "sha512-0l6GZmT3efexyaaay3SchKT5kG311N59TEFP5lfvEy0nz9SNqjx311plJ3b4jze7arsmDsiHQLh/xnAuk0HFTQ==", - "requires": { - "cheerio": "^0.22.0", - "commander": "^2.15.1", - "cross-spawn": "^6.0.5", - "deep-extend": "^0.6.0", - "mensch": "^0.3.3", - "slick": "^1.12.2", - "web-resource-inliner": "^4.3.1" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" - }, - "lodash.assignin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", - "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=" - }, - "lodash.bind": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", - "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=" - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" - }, - "lodash.filter": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", - "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=" - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" - }, - "lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" - }, - "lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=" - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" - }, - "lodash.reduce": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", - "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" - }, - "lodash.reject": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", - "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=" - }, - "lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=" - }, - "lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "requires": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "lodash.unescape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", - "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=" - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "mensch": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", - "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==" - }, - "mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" - }, - "mime-db": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", - "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==" - }, - "mime-types": { - "version": "2.1.29", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", - "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", - "requires": { - "mime-db": "1.46.0" - } - }, - "mimer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mimer/-/mimer-1.1.0.tgz", - "integrity": "sha512-y9dVfy2uiycQvDNiAYW6zp49ZhFlXDMr5wfdOiMbdzGM/0N5LNR6HTUn3un+WUQcM0koaw8FMTG1bt5EnHJdvQ==" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "mysql2": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-1.7.0.tgz", - "integrity": "sha512-xTWWQPjP5rcrceZQ7CSTKR/4XIDeH/cRkNH/uzvVGQ7W5c7EJ0dXeJUusk7OKhIoHj7uFKUxDVSCfLIl+jluog==", - "requires": { - "denque": "^1.4.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.5.0", - "long": "^4.0.0", - "lru-cache": "^5.1.1", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.1" - } - }, - "named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", - "requires": { - "lru-cache": "^4.1.3" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "nodemailer": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.7.0.tgz", - "integrity": "sha512-IludxDypFpYw4xpzKdMAozBSkzKHmNBvGanUREjJItgJ2NYcK/s8+PggVhj7c2yGFQykKsnnmv1+Aqo0ZfjHmw==" - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "requires": { - "boolbase": "~1.0.0" - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "pngjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "puppeteer": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-2.1.1.tgz", - "integrity": "sha512-LWzaDVQkk1EPiuYeTOj+CZRIjda4k2s5w4MK4xoH2+kgWV/SDlkYHmxatDdtYrciHUKSXTsGgPgPP8ILVdBsxg==", - "requires": { - "@types/mime-types": "^2.1.0", - "debug": "^4.1.0", - "extract-zip": "^1.6.6", - "https-proxy-agent": "^4.0.0", - "mime": "^2.0.3", - "mime-types": "^2.1.25", - "progress": "^2.0.1", - "proxy-from-env": "^1.0.0", - "rimraf": "^2.6.1", - "ws": "^6.1.0" - } - }, - "qrcode": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.4.4.tgz", - "integrity": "sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q==", - "requires": { - "buffer": "^5.4.3", - "buffer-alloc": "^1.2.0", - "buffer-from": "^1.1.1", - "dijkstrajs": "^1.0.1", - "isarray": "^2.0.1", - "pngjs": "^3.3.0", - "yargs": "^13.2.4" - } - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" - }, - "serialize-javascript": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", - "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", - "requires": { - "randombytes": "^2.1.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "slick": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", - "integrity": "sha1-vQSN23TefRymkV+qSldXCzVQwtc=" - }, - "source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "sqlstring": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", - "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==" - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "strftime": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/strftime/-/strftime-0.10.0.tgz", - "integrity": "sha1-s/D6QZKVICpaKJ9ta+n0kJphcZM=" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "valid-data-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-2.0.0.tgz", - "integrity": "sha512-dyCZnv3aCey7yfTgIqdZanKl7xWAEEKCbgmR7SKqyK6QT/Z07ROactrgD1eA37C69ODRj7rNOjzKWVPh0EUjBA==" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "vue": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.12.tgz", - "integrity": "sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==" - }, - "vue-i18n": { - "version": "8.24.1", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.24.1.tgz", - "integrity": "sha512-iqM+npjvI9SGOAYkw1Od/y4O74gpvn5WOHeb3K125TmDJssvR62tDMMLIasPmKNbePZ1BMZ6d5jOBsrB/cK8Lw==" - }, - "vue-server-renderer": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.6.12.tgz", - "integrity": "sha512-3LODaOsnQx7iMFTBLjki8xSyOxhCtbZ+nQie0wWY4iOVeEtTg1a3YQAjd82WvKxrWHHTshjvLb7OXMc2/dYuxw==", - "requires": { - "chalk": "^1.1.3", - "hash-sum": "^1.0.2", - "he": "^1.1.0", - "lodash.template": "^4.5.0", - "lodash.uniq": "^4.5.0", - "resolve": "^1.2.0", - "serialize-javascript": "^3.1.0", - "source-map": "0.5.6" - } - }, - "web-resource-inliner": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-4.3.4.tgz", - "integrity": "sha512-agVAgRhOOi4GVlvKK34oM23tDgH8390HfLnZY2HZl8OFBwKNvUJkH7t89AT2iluQP8w9VHAAKX6Z8EN7/9tqKA==", - "requires": { - "async": "^3.1.0", - "chalk": "^2.4.2", - "datauri": "^2.0.0", - "htmlparser2": "^4.0.0", - "lodash.unescape": "^4.0.1", - "request": "^2.88.0", - "safer-buffer": "^2.1.2", - "valid-data-url": "^2.0.0", - "xtend": "^4.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "dom-serializer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", - "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "entities": "^2.0.0" - }, - "dependencies": { - "domhandler": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", - "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", - "requires": { - "domelementtype": "^2.1.0" - } - } - } - }, - "domelementtype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", - "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" - }, - "domhandler": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", - "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", - "requires": { - "domelementtype": "^2.0.1" - } - }, - "domutils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.5.0.tgz", - "integrity": "sha512-Ho16rzNMOFk2fPwChGh3D2D9OEHAfG19HgmRR2l+WLSsIstNsAYBzePH412bL0y5T44ejABIVfTHQ8nqi/tBCg==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0" - }, - "dependencies": { - "domhandler": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", - "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", - "requires": { - "domelementtype": "^2.1.0" - } - } - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "htmlparser2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", - "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^3.0.0", - "domutils": "^2.0.0", - "entities": "^2.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", - "requires": { - "async-limiter": "~1.0.0" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - } -} diff --git a/print/package.json b/print/package.json index 09ef2b1c8..ed1df5037 100755 --- a/print/package.json +++ b/print/package.json @@ -20,7 +20,7 @@ "juice": "^5.2.0", "mysql2": "^1.7.0", "nodemailer": "^4.7.0", - "puppeteer": "^2.0.0", + "puppeteer": "^18.0.5", "qrcode": "^1.4.2", "strftime": "^0.10.0", "vue": "^2.6.10", From b134aeb0ea40c4d964f995e8fd35efef3aa58076 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 5 Oct 2022 16:19:07 +0200 Subject: [PATCH 53/53] Mock report pdf --- .../back/methods/invoiceOut/createPdf.js | 6 ++--- .../invoiceOut/specs/createPdf.spec.js | 22 ++++++------------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js index 3ab5f526c..e56516237 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js +++ b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js @@ -1,5 +1,5 @@ const UserError = require('vn-loopback/util/user-error'); -const {Report, storage} = require('vn-print'); +const print = require('vn-print'); module.exports = Self => { Self.remoteMethodCtx('createPdf', { @@ -52,7 +52,7 @@ module.exports = Self => { hasPdf: true }, myOptions); - const invoiceReport = new Report('invoice', { + const invoiceReport = new print.Report('invoice', { reference: invoiceOut.ref, recipientId: invoiceOut.clientFk }); @@ -66,7 +66,7 @@ module.exports = Self => { const fileName = `${year}${invoiceOut.ref}.pdf`; // Store invoice - storage.write(stream, { + print.storage.write(stream, { type: 'invoice', path: `${year}/${month}/${day}`, fileName: fileName diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js index 7600f065f..803338ef3 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js @@ -1,7 +1,6 @@ const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); -const fs = require('fs-extra'); -const axios = require('axios'); +const print = require('vn-print'); describe('InvoiceOut createPdf()', () => { const userId = 1; @@ -16,22 +15,15 @@ describe('InvoiceOut createPdf()', () => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); - const response = { - data: { - pipe: () => {}, - on: () => {}, + + spyOn(print, 'Report').and.returnValue({ + toPdfStream: () => { + return ''; } - }; - spyOn(axios, 'get').and.returnValue(new Promise(resolve => resolve(response))); - spyOn(models.InvoiceContainer, 'container').and.returnValue({ - client: {root: '/path'} - }); - spyOn(fs, 'mkdir').and.returnValue(true); - spyOn(fs, 'createWriteStream').and.returnValue({ - on: (event, cb) => cb(), - end: () => {} }); + spyOn(print.storage, 'write').and.returnValue(true); + const tx = await models.InvoiceOut.beginTransaction({}); const options = {transaction: tx};