Campaign metrics

This commit is contained in:
Joan Sanchez 2022-09-22 08:48:29 +02:00
parent 5a43bdb6c9
commit 8105c12a18
17 changed files with 217 additions and 85 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"`];
};
};

View File

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

View File

@ -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) {

View File

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

View File

@ -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"`];
};
};

View File

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

View File

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

View File

@ -25,7 +25,7 @@
<div class="grid-block vn-pa-ml">
<h1>{{ $t('title') }}</h1>
<p>{{$t('dear')}},</p>
<p v-html="$t('description', [ticketId])"></p>
<p v-html="$t('description', [id])"></p>
<p v-html="$t('poll')"></p>
<p v-html="$t('help')"></p>
<p v-html="$t('conclusion')"></p>

View File

@ -9,7 +9,7 @@ module.exports = {
'email-footer': emailFooter.build()
},
props: {
ticketId: {
id: {
type: [Number, String],
required: true
}

View File

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

View File

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

View File

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