merge
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"name": "MailServer",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"port": 3003,
|
||||||
|
"debug": true,
|
||||||
|
"defaultLanguage": "es",
|
||||||
|
"senderMail": "noreply@localhost",
|
||||||
|
"senderName": ""
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"host": "localhost",
|
||||||
|
"port": 3306,
|
||||||
|
"user": "reports",
|
||||||
|
"password": "",
|
||||||
|
"database": ""
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"host": "localhost",
|
||||||
|
"port": 465,
|
||||||
|
"secure": true,
|
||||||
|
"auth": {
|
||||||
|
"user": "noreply",
|
||||||
|
"pass": ""
|
||||||
|
},
|
||||||
|
"tls": {
|
||||||
|
"rejectUnauthorized": false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
var mysql = require('mysql');
|
||||||
|
var settings = require('./settings.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Variable de instancia del pool
|
||||||
|
*/
|
||||||
|
pool: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iniciar pool de conexión con la base de datos
|
||||||
|
*/
|
||||||
|
init: function() {
|
||||||
|
this.pool = mysql.createPool(settings.mysql());
|
||||||
|
|
||||||
|
this.pool.getConnection(function(error, connection) {
|
||||||
|
if (error) {
|
||||||
|
throw new Error('Can\'t connect to database: ' + error.code);
|
||||||
|
} else if (settings.app().debug) {
|
||||||
|
console.log('Database connection stablished');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,26 @@
|
||||||
|
var fs = require('fs');
|
||||||
|
var settings = require('./settings.js');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Devuelve las claves de idioma de una plantilla
|
||||||
|
* @param {String} template - Nombre de la plantilla
|
||||||
|
* @param {String} countryCode - Código de idioma
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
load: function(template, countryCode, cb) {
|
||||||
|
var localeFile = path.join(__dirname, 'template', `${template}`, 'locale', `${countryCode}.json`);
|
||||||
|
var defaultLocaleFile = path.join(__dirname, 'template', `${template}`, 'locale', `${settings.app().defaultLanguage}.json`);
|
||||||
|
|
||||||
|
fs.stat(localeFile, (error, stats) => {
|
||||||
|
if (error)
|
||||||
|
fs.stat(defaultLocaleFile, (error, stats) => {
|
||||||
|
if (error)
|
||||||
|
cb(null, 'Translation not found for template ' + template + '.');
|
||||||
|
return cb(require(defaultLocaleFile));
|
||||||
|
});
|
||||||
|
return cb(require(localeFile));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,49 @@
|
||||||
|
var nodemailer = require('nodemailer');
|
||||||
|
var settings = require('./settings.js');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Módulo para el envío de emails
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
transporter: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Si todavía no está inicializada la configuración,
|
||||||
|
* carga el fichero de configuración.
|
||||||
|
*/
|
||||||
|
init: function() {
|
||||||
|
this.transporter = nodemailer.createTransport(settings.smtp());
|
||||||
|
|
||||||
|
this.transporter.verify(function(error, success) {
|
||||||
|
if (error) {
|
||||||
|
throw new Error(error);
|
||||||
|
} else if (settings.app().debug) {
|
||||||
|
console.log('SMTP connection stablished');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envia un email con los datos recibidos desde un vector.
|
||||||
|
* @param {Object} data - Datos para el envío del email
|
||||||
|
*/
|
||||||
|
send: function(recipient, subject, body, attachments, cb) {
|
||||||
|
let mailOptions = {
|
||||||
|
from: '"' + settings.app().senderName + '" <' + settings.app().senderMail + '>',
|
||||||
|
to: recipient,
|
||||||
|
subject: subject,
|
||||||
|
html: body,
|
||||||
|
attachments
|
||||||
|
};
|
||||||
|
|
||||||
|
this.transporter.sendMail(mailOptions, (error, info) => {
|
||||||
|
if (error) {
|
||||||
|
return cb(null, 'Email not sent: ' + error);
|
||||||
|
} else if (settings.app().debug) {
|
||||||
|
console.log('Mail sent ' + info.messageId + ' [' + info.response + ']');
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,27 @@
|
||||||
|
var express = require('express');
|
||||||
|
var router = new express.Router();
|
||||||
|
var mail = require('../mail.js');
|
||||||
|
var database = require('../database.js');
|
||||||
|
var template = require('../template.js');
|
||||||
|
|
||||||
|
// Escrito de cambios en méto de pago del cliente
|
||||||
|
router.post('/:userId/payment-update', function(request, response, next) {
|
||||||
|
database.pool.query('SELECT `e-mail` AS email, LOWER(p.Codigo) AS countryCode FROM Clientes AS c JOIN Paises AS p ON p.id = c.Id_Pais WHERE Id_Cliente = ?', [request.params.userId], function(error, qryRs) {
|
||||||
|
if (qryRs.length == 0)
|
||||||
|
return response.json({data: {message: 'Client not found'}});
|
||||||
|
|
||||||
|
template.getTemplate('payment-update', qryRs[0].countryCode, {userId: request.params.userId}, function(tplRs, error) {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
mail.send(qryRs[0].email, tplRs.subject, tplRs.body, tplRs.attachments, (mailrs, error) => {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
return response.json({data: {message: 'Mail sent'}});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -0,0 +1,28 @@
|
||||||
|
var express = require('express');
|
||||||
|
var router = new express.Router();
|
||||||
|
var mail = require('../mail.js');
|
||||||
|
var database = require('../database.js');
|
||||||
|
var template = require('../template.js');
|
||||||
|
|
||||||
|
router.get('/:userId/notice', function(request, response) {
|
||||||
|
database.pool.query('SELECT `e-mail` AS email, LOWER(p.Codigo) AS countryCode FROM Clientes AS c JOIN Paises AS p ON p.id = c.Id_Pais WHERE Id_Cliente = ?', [request.params.userId], function(error, qryRs) {
|
||||||
|
if (qryRs.length == 0)
|
||||||
|
return response.json({data: {message: 'Client not found'}});
|
||||||
|
|
||||||
|
template.getTemplate('notice', qryRs[0].countryCode, {userId: request.params.userId}, function(tplRs, error) {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
mail.send(qryRs[0].email, tplRs.subject, tplRs.body, tplRs.attachments, (mailrs, error) => {
|
||||||
|
if (error)
|
||||||
|
return response.json({data: {message: error}});
|
||||||
|
|
||||||
|
return response.json({data: {message: 'Mail sent'}});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
response.send(request.params.userid);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -0,0 +1,16 @@
|
||||||
|
var express = require('express');
|
||||||
|
var router = new express.Router();
|
||||||
|
var settings = require('./settings.js');
|
||||||
|
|
||||||
|
// Mailer default page
|
||||||
|
router.get('/', function(request, response) {
|
||||||
|
response.send(settings.app().name + ' v' + settings.app().version);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Manuscripts
|
||||||
|
router.use('/manuscript', require('./route/manuscript.js'));
|
||||||
|
|
||||||
|
// Notifications
|
||||||
|
router.use('/notification', require('./route/notification.js'));
|
||||||
|
|
||||||
|
module.exports = router;
|
|
@ -0,0 +1,45 @@
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Módulo de configuración
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Obtiene la configuración en función del entorno en el que se está
|
||||||
|
* ejecutando la aplicación.
|
||||||
|
* @param {String} name Nombre del fichero
|
||||||
|
* @return {Object} Objeto de configuración
|
||||||
|
*/
|
||||||
|
getConfig: function(name) {
|
||||||
|
let env = process.env.NODE_ENV;
|
||||||
|
|
||||||
|
if (!env)
|
||||||
|
env = 'development';
|
||||||
|
|
||||||
|
return require(path.join(__dirname, 'config', `${name}.${env}.json`));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuración de la aplicación
|
||||||
|
* @return {Object} Objeto de configuración app
|
||||||
|
*/
|
||||||
|
app: function() {
|
||||||
|
return this.getConfig('app');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuración de smtp
|
||||||
|
* @return {Object} Objeto de configuración smtp
|
||||||
|
*/
|
||||||
|
smtp: function() {
|
||||||
|
return this.getConfig('smtp');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuración de mysql
|
||||||
|
* @return {Object} Objeto de configuración MySQL
|
||||||
|
*/
|
||||||
|
mysql: function() {
|
||||||
|
return this.getConfig('mysql');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,114 @@
|
||||||
|
var fs = require('fs');
|
||||||
|
var mustache = require('mustache');
|
||||||
|
var locale = require('./locale.js');
|
||||||
|
var path = require('path');
|
||||||
|
var inlineCss = require('inline-css');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Obtiene la plantilla.
|
||||||
|
* @param {String} template - Nombre de la plantilla
|
||||||
|
* @param {Object} countryCode - Código del idioma
|
||||||
|
* @param {Object} params - Datos a reemplazar.
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
getTemplate: function(template, countryCode, params, cb) {
|
||||||
|
var templatePath = path.join(__dirname, 'template', `${template}`, `${template}.html`);
|
||||||
|
var classPath = path.join(__dirname, 'template', `${template}`, `${template}.js`);
|
||||||
|
var stylePath = path.join(__dirname, 'template', `${template}`, `${template}.css`);
|
||||||
|
|
||||||
|
fs.stat(templatePath, (error, stat) => {
|
||||||
|
if (error)
|
||||||
|
return cb(null, 'Template ' + template + ' not found');
|
||||||
|
|
||||||
|
let TemplateClass = require(classPath);
|
||||||
|
let instance = new TemplateClass();
|
||||||
|
|
||||||
|
let getRenderedStyles = body => {
|
||||||
|
this.renderStyles(stylePath, body, body => {
|
||||||
|
var titleSubject = body.match(new RegExp('<title>(.*?)</title>', 'i'))[1];
|
||||||
|
this.getAttachments(template, body, attachments => {
|
||||||
|
cb({body: body, subject: titleSubject, attachments: attachments});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let getDataCb = () => {
|
||||||
|
this.render(templatePath, instance, body => getRenderedStyles(body));
|
||||||
|
};
|
||||||
|
|
||||||
|
locale.load(template, countryCode, (translations, error) => {
|
||||||
|
instance._ = translations;
|
||||||
|
instance.getData(params, () => getDataCb());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renderiza las plantillas
|
||||||
|
* @param {String} path - Ruta de la plantilla
|
||||||
|
* @param {Object} data - Listado de parámetros a remplazar
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
render: function(path, data, cb) {
|
||||||
|
fs.readFile(path, 'utf8', function(error, body) {
|
||||||
|
mustache.parse(body);
|
||||||
|
cb(mustache.render(body, data));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renderiza los estilos de las plantillas.
|
||||||
|
* @param {String} path - Ruta de la hoja de estilos
|
||||||
|
* @param {String} body - Html renderizado
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
renderStyles: function(path, html, cb) {
|
||||||
|
fs.stat(path, error => {
|
||||||
|
if (error) return cb(null, 'Template stylesheet not found');
|
||||||
|
fs.readFile(path, 'utf8', (error, css) => {
|
||||||
|
let style = '<style>' + css + '</style>';
|
||||||
|
let body = style + html;
|
||||||
|
let options = {url: ' '};
|
||||||
|
|
||||||
|
inlineCss(body, options)
|
||||||
|
.then(function(body) {
|
||||||
|
cb(body);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene todos los ficheros adjuntos de la plantilla
|
||||||
|
* @param {String} template - Nombre de la plantilla
|
||||||
|
* @param {String} body - html de la plantilla
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
getAttachments: function(template, body, cb) {
|
||||||
|
var attachments = [];
|
||||||
|
var tplAttachments = body.match(new RegExp('src="cid:(.*?)"', 'ig'));
|
||||||
|
|
||||||
|
for (var i = 0; i < tplAttachments.length; i++) {
|
||||||
|
var name = tplAttachments[i].replace('src="cid:', '').replace('"', '');
|
||||||
|
var attachmentPath = path.join(__dirname, 'template/image', name);
|
||||||
|
|
||||||
|
attachments.push({filename: name, path: attachmentPath, cid: name});
|
||||||
|
}
|
||||||
|
|
||||||
|
var attachmentsPath = path.join(__dirname, 'template', `${template}`, 'attachment.json');
|
||||||
|
|
||||||
|
fs.stat(attachmentsPath, (error, stats) => {
|
||||||
|
if (error) return cb(null, 'Could not load attachments from template ' + template);
|
||||||
|
|
||||||
|
var attachObj = require(attachmentsPath);
|
||||||
|
|
||||||
|
for (var i = 0; i < attachObj.length; i++) {
|
||||||
|
var attachmentPath = path.join(__dirname, 'template', `${template}`, 'attachment', attachObj[i]);
|
||||||
|
attachments.push({filename: attachObj[i], path: attachmentPath, cid: attachObj[i]});
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(attachments);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.4 KiB |
|
@ -0,0 +1 @@
|
||||||
|
[]
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"subject": "Has recibido una nueva notificación",
|
||||||
|
"title": "Nueva notificación",
|
||||||
|
"hello": "Hola",
|
||||||
|
"bodyDescription": "test",
|
||||||
|
"actionButton": "Visita nuestra Web",
|
||||||
|
"infoButton": "Ayúdanos a mejorar",
|
||||||
|
"fiscalAddress": "VERDNATURA LEVANTE SL, B97367486 Avda. Espioca, 100, 46460 Silla _ www.verdnatura.es _ clientes@verdnatura.es",
|
||||||
|
"privacy": "- AVISO - Este mensaje es privado y confidencial, y debe ser utilizado exclusivamente por la persona destinataria del mismo. Si usted ha recibido este mensaje por error, le rogamos lo comunique al remitente y borre dicho mensaje y cualquier documento adjunto que pudiera contener. Verdnatura Levante SL no renuncia a la confidencialidad ni a ningún privilegio por causa de transmisión errónea o mal funcionamiento. Igualmente no se hace responsable de los cambios, alteraciones, errores u omisiones que pudieran hacerse al mensaje una vez enviado.",
|
||||||
|
"privacyLaw": "En cumplimiento de lo dispuesto en la Ley Orgánica 15/1999, de Protección de Datos de Carácter Personal, le comunicamos que los datos personales que facilite se incluirán en ficheros automatizados de VERDNATURA LEVANTE S.L., pudiendo en todo momento ejercitar los derechos de acceso, rectificación, cancelación y oposición, comunicándolo por escrito al domicilio social de la entidad. La finalidad del fichero es la gestión administrativa, contabilidad, y facturación."
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="es">
|
||||||
|
<head>
|
||||||
|
<title>{{_.subject}}</title>
|
||||||
|
<meta charset="utf8"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div style="width: 600px;margin: 0 auto;font-family: arial, sans-serif;font-size: 16px;color: #555">
|
||||||
|
<!-- Banner block -->
|
||||||
|
<div>
|
||||||
|
<a href="https://www.verdnatura.es"/><img src="cid:header.png" alt="VerdNatura" style="margin:0"/></a>
|
||||||
|
</div>
|
||||||
|
<!-- Banner block end -->
|
||||||
|
|
||||||
|
<!-- Title block -->
|
||||||
|
<div style="padding: 35px 0;background-color:#95d831;text-align: center">
|
||||||
|
<h1 style="margin: 0;font-size: 32px;color: #333;">{{_.title}}</h1>
|
||||||
|
</div>
|
||||||
|
<!-- Title block end -->
|
||||||
|
|
||||||
|
<!-- Mail body block -->
|
||||||
|
<div style="padding: 20px 0">
|
||||||
|
<p style="text-align: justify">Hola, {{username}}</p>
|
||||||
|
<p style="text-align: justify">{{_.bodyDescription}}</p>
|
||||||
|
</div>
|
||||||
|
<!-- Mail body block end -->
|
||||||
|
|
||||||
|
<!-- Action button block -->
|
||||||
|
<div style="background-color: #333;overflow:hidden">
|
||||||
|
<a href="https://www.verdnatura.es" target="_blank" style="display:block;float:left;width:300px;height:72px;color:#fff;font-size:22px;text-decoration:none">
|
||||||
|
<div style="float:left;width:230px;padding:22px 0;height:72px;text-align:center">{{_.actionButton}}</div>
|
||||||
|
<div style="background-color:#95d831;text-align:center;float:right;padding-top:22px;height:50px;width:70px"><img style="margin:0" src="cid:action.png"/></div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="https://goo.gl/forms/j8WSL151ZW6QtlT72" target="_blank" style="display:block;float:left;width:300px;height:72px;color:#fff;font-size:22px;text-decoration:none">
|
||||||
|
<div style="float:left;width:230px;padding:22px 0;height:72px;text-align:center">{{_.infoButton}}</div>
|
||||||
|
<div style="background-color:#95d831;text-align:center;float:right;padding-top:22px;height:50px;width:70px"><img style="margin:0" src="cid:info.png"/></div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<!-- Action button block end-->
|
||||||
|
|
||||||
|
<!-- Networks block -->
|
||||||
|
<div style="padding:20px 0;background-color:#555;text-align:center">
|
||||||
|
<a href="https://www.facebook.com/Verdnatura" target="_blank" style="text-decoration:none;margin-right: 10px">
|
||||||
|
<img src="cid:facebook.png" alt="Visita nuestro Facebook" style="margin:0"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.twitter.com/Verdnatura" target="_blank" style="text-decoration:none;margin-right: 10px">
|
||||||
|
<img src="cid:twitter.png" alt="Visita nuestro Twitter" style="margin:0"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.youtube.com/Verdnatura" target="_blank" style="text-decoration:none;margin-right: 10px">
|
||||||
|
<img src="cid:youtube.png" alt="Visita nuestro canal de Youtube" style="margin:0"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.pinterest.com/Verdnatura" target="_blank" style="text-decoration:none;margin-right: 10px">
|
||||||
|
<img src="cid:pinterest.png" alt="Visita nuestro Pinterest" style="margin:0"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.instagram.com/Verdnatura" target="_blank" style="text-decoration:none;margin-right: 10px">
|
||||||
|
<img src="cid:instagram.png" alt="Visita nuestro Instagram" style="margin:0"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.linkedin.com/company/verdnatura" target="_blank" style="text-decoration:none;margin-right: 10px">
|
||||||
|
<img src="cid:linkedin.png" alt="Visita nuestro Linkedin" style="width:50px;margin:0"/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<!-- Networks block end -->
|
||||||
|
|
||||||
|
<!-- Privacy block -->
|
||||||
|
<div style="padding:20px 0;font-size:10px;font-weight:100">
|
||||||
|
<p style="text-align: justify">{{_.fiscalAddress}}</p>
|
||||||
|
<p style="text-align: justify">{{_.privacy}}</p>
|
||||||
|
<p style="text-align: justify">{{_.privacyLaw}}</p>
|
||||||
|
</div>
|
||||||
|
<!-- Privacy block end -->
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,14 @@
|
||||||
|
var path = require('path');
|
||||||
|
var database = require(path.join(__dirname, '../../database.js'));
|
||||||
|
|
||||||
|
module.exports = class Notice {
|
||||||
|
getData(params, cb) {
|
||||||
|
let query = `SELECT c. Cliente FROM Clientes AS c WHERE Id_Cliente = ?`;
|
||||||
|
database.pool.query(query, [params.userId], (error, result) => {
|
||||||
|
Object.assign(this, result[0]);
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
[]
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"subject": "Cambios en las condiciones de pago",
|
||||||
|
"title": "Cambio en las condiciones",
|
||||||
|
"dear": "Estimado cliente",
|
||||||
|
"bodyDescription": "Le informamos que han cambiado las condiciones de pago de su cuenta. A continuación le indicamos las nuevas condiciones:",
|
||||||
|
"paymentMethod": "Método de pago",
|
||||||
|
"paymentDay": "Día de pago",
|
||||||
|
"everyMonth": "de cada mes",
|
||||||
|
"cardPaymentAdvice": "Su modo de pago actual implica que deberá abonar el importe de los pedidos realizados en el mismo día para que se puedan enviar.",
|
||||||
|
"accountPaymentAdviceBefore": "Su modo de pago actual implica que se le pasará un cargo a la cuenta",
|
||||||
|
"accountPaymentAdviceAfter": "por el importe pendiente, al vencimiento establecido en las condiciones.",
|
||||||
|
"notifyError": "En el caso de detectar algún error en los datos indicados o para cualquier aclaración, debe dirigirse a su comercial.",
|
||||||
|
"actionButton": "Visita nuestra Web",
|
||||||
|
"infoButton": "Ayúdanos a mejorar",
|
||||||
|
"fiscalAddress": "VERDNATURA LEVANTE SL, B97367486 Avda. Espioca, 100, 46460 Silla _ www.verdnatura.es _ clientes@verdnatura.es",
|
||||||
|
"privacy": "- AVISO - Este mensaje es privado y confidencial, y debe ser utilizado exclusivamente por la persona destinataria del mismo. Si usted ha recibido este mensaje por error, le rogamos lo comunique al remitente y borre dicho mensaje y cualquier documento adjunto que pudiera contener. Verdnatura Levante SL no renuncia a la confidencialidad ni a ningún privilegio por causa de transmisión errónea o mal funcionamiento. Igualmente no se hace responsable de los cambios, alteraciones, errores u omisiones que pudieran hacerse al mensaje una vez enviado.",
|
||||||
|
"privacyLaw": "En cumplimiento de lo dispuesto en la Ley Orgánica 15/1999, de Protección de Datos de Carácter Personal, le comunicamos que los datos personales que facilite se incluirán en ficheros automatizados de VERDNATURA LEVANTE S.L., pudiendo en todo momento ejercitar los derechos de acceso, rectificación, cancelación y oposición, comunicándolo por escrito al domicilio social de la entidad. La finalidad del fichero es la gestión administrativa, contabilidad, y facturación."
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
img {
|
||||||
|
margin: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
background-color: #EEE
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
font-family: arial, sans-serif;
|
||||||
|
max-width: 600px;
|
||||||
|
min-width: 320px;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 0 auto;
|
||||||
|
color: #555
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner img {
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
background-color: #95d831;
|
||||||
|
text-align: center;
|
||||||
|
padding: 35px 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.title h1 {
|
||||||
|
font-size: 32px;
|
||||||
|
color: #333;
|
||||||
|
margin: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
background-color:#FFF;
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
background-color: #FFF;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons a {
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons .btn {
|
||||||
|
background-color: #333;
|
||||||
|
min-width: 300px;
|
||||||
|
height: 72px;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons .btn .text {
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 22px
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons .btn .icon {
|
||||||
|
background-color: #95d831;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 22px;
|
||||||
|
float: right;
|
||||||
|
height: 50px;
|
||||||
|
width: 70px
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
background-color: #555;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a {
|
||||||
|
text-decoration: none;
|
||||||
|
margin-right: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a img {
|
||||||
|
margin: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.privacy {
|
||||||
|
padding: 20px 0;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 100
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="es">
|
||||||
|
<head>
|
||||||
|
<title>{{_.subject}}</title>
|
||||||
|
<meta charset="utf8"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="container">
|
||||||
|
<!-- Banner block -->
|
||||||
|
<div class="banner">
|
||||||
|
<a href="https://www.verdnatura.es"/><img src="cid:header.png" alt="VerdNatura"/></a>
|
||||||
|
</div>
|
||||||
|
<!-- Banner block end -->
|
||||||
|
|
||||||
|
<!-- Title block -->
|
||||||
|
<div class="title">
|
||||||
|
<h1>{{_.title}}</h1>
|
||||||
|
</div>
|
||||||
|
<!-- Title block end -->
|
||||||
|
|
||||||
|
<!-- Mail body block -->
|
||||||
|
<div class="body">
|
||||||
|
<p style="text-align: justify">{{_.dear}},</p>
|
||||||
|
<p style="text-align: justify">{{_.bodyDescription}}</p>
|
||||||
|
<p style="text-align: justify">
|
||||||
|
<div>{{_.paymentMethod}}: <strong style="font-size: 16px">{{payMethod}}</strong></div>
|
||||||
|
{{{paymentDay}}}
|
||||||
|
</p>
|
||||||
|
<p style="text-align: justify">{{paymentAdvice}}</p>
|
||||||
|
<p style="text-align: justify">{{_.notifyError}}</p>
|
||||||
|
</div>
|
||||||
|
<!-- Mail body block end -->
|
||||||
|
|
||||||
|
<!-- Action button block -->
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="https://www.verdnatura.es" target="_blank"><div class="btn">
|
||||||
|
<span class="text">{{_.actionButton}}</span>
|
||||||
|
<span class="icon"><img src="cid:action.png"/></span>
|
||||||
|
</div></a><a href="https://goo.gl/forms/j8WSL151ZW6QtlT72" target="_blank"><div class="btn">
|
||||||
|
<span class="text">{{_.infoButton}}</span>
|
||||||
|
<span class="icon"><img src="cid:info.png"/></span>
|
||||||
|
</div></a>
|
||||||
|
</div>
|
||||||
|
<!-- Action button block -->
|
||||||
|
|
||||||
|
<!-- Networks block -->
|
||||||
|
<div class="footer">
|
||||||
|
<a href="https://www.facebook.com/Verdnatura" target="_blank">
|
||||||
|
<img src="cid:facebook.png" alt="Facebook"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.twitter.com/Verdnatura" target="_blank">
|
||||||
|
<img src="cid:twitter.png" alt="Twitter"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.youtube.com/Verdnatura" target="_blank">
|
||||||
|
<img src="cid:youtube.png" alt="Youtube"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.pinterest.com/Verdnatura" target="_blank">
|
||||||
|
<img src="cid:pinterest.png" alt="Pinterest"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.instagram.com/Verdnatura" target="_blank">
|
||||||
|
<img src="cid:instagram.png" alt="Instagram"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.linkedin.com/company/verdnatura" target="_blank">
|
||||||
|
<img src="cid:linkedin.png" alt="Linkedin"/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<!-- Networks block end -->
|
||||||
|
|
||||||
|
<!-- Privacy block -->
|
||||||
|
<div class="privacy">
|
||||||
|
<p style="text-align: justify">{{_.fiscalAddress}}</p>
|
||||||
|
<p style="text-align: justify">{{_.privacy}}</p>
|
||||||
|
<p style="text-align: justify">{{_.privacyLaw}}</p>
|
||||||
|
</div>
|
||||||
|
<!-- Privacy block end -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,31 @@
|
||||||
|
var path = require('path');
|
||||||
|
var database = require(path.join(__dirname, '../../database.js'));
|
||||||
|
var format = require(path.join(__dirname, '../../util/format.js'));
|
||||||
|
|
||||||
|
module.exports = class PaymentUpdate {
|
||||||
|
getData(params, cb) {
|
||||||
|
let query = `SELECT pm.name AS payMethod, pm.id AS payMethodId, c.vencimiento AS payDay, c.CC AS accountAddress
|
||||||
|
FROM Clientes AS c JOIN pay_met AS pm ON pm.id = c.pay_met_id WHERE Id_Cliente = ?`;
|
||||||
|
database.pool.query(query, [params.userId], (error, result) => {
|
||||||
|
Object.assign(this, result[0]);
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get paymentDay() {
|
||||||
|
if (this.payMethodId != 5) {
|
||||||
|
return `<div>${this._.paymentDay}: <strong style="font-size: 16px">${this.payDay} ${this._.everyMonth}</strong></div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get paymentAdvice() {
|
||||||
|
switch (this.payMethodId) {
|
||||||
|
case 4:
|
||||||
|
return `${this._.accountPaymentAdviceBefore} ${format.partialAccountAddress(this.accountAddress)} ${this._.accountPaymentAdviceAfter}`;
|
||||||
|
case 5:
|
||||||
|
return this._.cardPaymentAdvice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
let database = require('../database.js');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve el iban
|
||||||
|
* @param {String} addressNumber - Dirección de cuenta bancaria
|
||||||
|
* @param {Object} cb - Callback
|
||||||
|
*/
|
||||||
|
accountAddressIban: function(addressNumber, cb) {
|
||||||
|
database.pool.query('SELECT vn2008.cc_to_iban(?) AS iban', [addressNumber], function(error, result) {
|
||||||
|
cb(result[0].iban);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene el numero de cuenta completo incluyendo iban
|
||||||
|
* @param {String} addressNumber - Dirección de cuenta bancaria
|
||||||
|
* @return {String} Cuenta bancaria formateada
|
||||||
|
*/
|
||||||
|
accountAddress: function(addressNumber) {
|
||||||
|
var formattedAccountAddress = addressNumber.replace(/(.{4})/g, '$1-');
|
||||||
|
return formattedAccountAddress.substring(0, formattedAccountAddress.length - 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve el numero de cuenta mostrando únicamente los últimos 4 dígitos.
|
||||||
|
* @param {String} addressNumber - Dirección de cuenta bancaria
|
||||||
|
* @return {String} Cuenta bancaria formateada
|
||||||
|
*/
|
||||||
|
partialAccountAddress: function(addressNumber) {
|
||||||
|
let address = this.accountAddress(addressNumber);
|
||||||
|
return address.substring(0, 19).replace(/[0-9]/g, 'X') + address.substring(19, 24);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,10 @@
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Obtiene las variables de entorno
|
||||||
|
* @param {String} env - Nombre de la variable de entorno
|
||||||
|
* @return {String} Valor de la variable de entorno
|
||||||
|
*/
|
||||||
|
getEnv: function(env) {
|
||||||
|
return process.env[env];
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"name": "Ticket",
|
||||||
|
"base": "MyModel",
|
||||||
|
"validateUpsert": true,
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"id": true,
|
||||||
|
"type": "Number",
|
||||||
|
"forceId": false
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"type": "date"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "*",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"permission": "DENY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"accessType": "*",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "root",
|
||||||
|
"permission": "ALLOW"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|