merge
|
@ -1,26 +1,6 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Iniciar",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/services/auth/server/server.js",
|
||||
"stopOnEntry": false,
|
||||
"args": [],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": null,
|
||||
"runtimeExecutable": null,
|
||||
"runtimeArgs": [
|
||||
"--nolazy"
|
||||
],
|
||||
"env": {
|
||||
"NODE_ENV": "development"
|
||||
},
|
||||
"console": "internalConsole",
|
||||
"sourceMaps": false,
|
||||
"outFiles": []
|
||||
},
|
||||
{
|
||||
"name": "Asociar",
|
||||
"type": "node",
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"client": "$ctrl.client"
|
||||
},
|
||||
"menu": {
|
||||
"description": "Datos básicos",
|
||||
"description": "Basic data",
|
||||
"icon": "person"
|
||||
}
|
||||
}, {
|
||||
|
@ -37,7 +37,7 @@
|
|||
"client": "$ctrl.client"
|
||||
},
|
||||
"menu": {
|
||||
"description": "Datos fiscales",
|
||||
"description": "Fiscal data",
|
||||
"icon": "account_balance"
|
||||
}
|
||||
}, {
|
||||
|
@ -64,7 +64,7 @@
|
|||
"client": "$ctrl.client"
|
||||
},
|
||||
"menu": {
|
||||
"description": "Consignatarios",
|
||||
"description": "Addresses",
|
||||
"icon": "local_shipping"
|
||||
}
|
||||
}, {
|
||||
|
@ -83,7 +83,7 @@
|
|||
"client": "$ctrl.client"
|
||||
},
|
||||
"menu": {
|
||||
"description": "Acceso web",
|
||||
"description": "Web access",
|
||||
"icon": "language"
|
||||
}
|
||||
}, {
|
||||
|
@ -99,13 +99,59 @@
|
|||
"client": "$ctrl.client"
|
||||
},
|
||||
"menu": {
|
||||
"description": "Notas",
|
||||
"description": "Notes",
|
||||
"icon": "insert_drive_file"
|
||||
}
|
||||
}, {
|
||||
"url": "/create",
|
||||
"state": "clientCard.notes.create",
|
||||
"component": "vn-note-create"
|
||||
}, {
|
||||
"url": "/credit",
|
||||
"abstract": true,
|
||||
"state": "clientCard.credit",
|
||||
"component": "ui-view"
|
||||
}, {
|
||||
"url": "/list",
|
||||
"state": "clientCard.credit.list",
|
||||
"component": "vn-client-credit-list",
|
||||
"params": {
|
||||
"client": "$ctrl.client"
|
||||
},
|
||||
"menu": {
|
||||
"description": "Credit",
|
||||
"icon": "credit_card"
|
||||
}
|
||||
}, {
|
||||
"url": "/create",
|
||||
"state": "clientCard.credit.create",
|
||||
"component": "vn-client-credit-create",
|
||||
"params": {
|
||||
"client": "$ctrl.client"
|
||||
}
|
||||
}, {
|
||||
"url": "/greuge",
|
||||
"abstract": true,
|
||||
"state": "clientCard.greuge",
|
||||
"component": "ui-view"
|
||||
}, {
|
||||
"url": "/list",
|
||||
"state": "clientCard.greuge.list",
|
||||
"component": "vn-client-greuge-list",
|
||||
"params": {
|
||||
"client": "$ctrl.client"
|
||||
},
|
||||
"menu": {
|
||||
"description": "Greuge",
|
||||
"icon": "work"
|
||||
}
|
||||
}, {
|
||||
"url": "/create",
|
||||
"state": "clientCard.greuge.create",
|
||||
"component": "vn-client-greuge-create",
|
||||
"params": {
|
||||
"client": "$ctrl.client"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
{
|
||||
"Addresses": "Consignatarios",
|
||||
"Set as default": "Establecer como predeterminado"
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"Basic data": "Datos básicos",
|
||||
"Comercial Name": "Nombre comercial",
|
||||
"Tax number": "NIF/CIF",
|
||||
"Social name": "Razón social",
|
||||
|
|
|
@ -21,10 +21,6 @@
|
|||
<vn-textfield vn-two label="IBAN" field="$ctrl.client.iban" vn-acl="administrative"></vn-textfield>
|
||||
<vn-textfield vn-one label="Vencimiento" field="$ctrl.client.dueDay" vn-acl="administrative"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Crédito" field="$ctrl.client.credit" vn-acl="administrative"></vn-textfield>
|
||||
<vn-textfield vn-one label="Crédito asegurado" field="$ctrl.client.creditInsurance" vn-acl="administrative"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal margin-medium-bottom>
|
||||
<vn-one>
|
||||
<vn-check label="Recibido core VNH" field="$ctrl.client.hasCoreVnh" vn-acl="administrative"></vn-check>
|
||||
|
|
|
@ -17,9 +17,6 @@ export default class Controller {
|
|||
this.billData.payMethodFk = this.client.payMethodFk;
|
||||
this.billData.iban = this.client.iban;
|
||||
this.billData.dueDay = this.client.dueDay;
|
||||
this.billData.discount = this.client.discount;
|
||||
this.billData.credit = this.client.credit;
|
||||
this.billData.creditInsurance = this.client.creditInsurance;
|
||||
}
|
||||
}
|
||||
submit() {
|
||||
|
@ -43,7 +40,7 @@ export default class Controller {
|
|||
}
|
||||
returnDialog(response) {
|
||||
if (response === 'ACCEPT') {
|
||||
this.$http.post(`/mailer/manuscript/payment-update/${this.client.id}`).then(
|
||||
this.$http.post(`/mailer/notification/payment-update/${this.client.id}`).then(
|
||||
() => {
|
||||
this.vnApp.showMessage(this.translate.instant('Notification sent!'));
|
||||
}
|
||||
|
|
|
@ -25,9 +25,6 @@ describe('Client', () => {
|
|||
describe('copyData()', () => {
|
||||
it(`should define billData using client's data`, () => {
|
||||
controller.client = {
|
||||
credit: 1000000000000,
|
||||
creditInsurance: null,
|
||||
discount: 99,
|
||||
dueDay: 0,
|
||||
iban: null,
|
||||
payMethodFk: 1
|
||||
|
@ -72,8 +69,8 @@ describe('Client', () => {
|
|||
describe('returnDialog()', () => {
|
||||
it('should request to send notification email', () => {
|
||||
controller.client = {id: '123'};
|
||||
$httpBackend.when('POST', `/mailer/manuscript/payment-update/${controller.client.id}`).respond('done');
|
||||
$httpBackend.expectPOST(`/mailer/manuscript/payment-update/${controller.client.id}`);
|
||||
$httpBackend.when('POST', `/mailer/notification/payment-update/${controller.client.id}`).respond('done');
|
||||
$httpBackend.expectPOST(`/mailer/notification/payment-update/${controller.client.id}`);
|
||||
controller.returnDialog('ACCEPT');
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
|
|
@ -14,3 +14,7 @@ import './address-edit/address-edit';
|
|||
import './notes/notes';
|
||||
import './note-create/note-create';
|
||||
import './web-access/web-access';
|
||||
import './credit-list/credit-list';
|
||||
import './credit-create/credit-create';
|
||||
import './greuge-list/greuge-list';
|
||||
import './greuge-create/greuge-create';
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<mg-ajax path="/client/api/Clients/{{patch.params.id}}" options="vnPatch"></mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.client"
|
||||
form="form"
|
||||
save="patch">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="watcher.submitGo('clientCard.credit.list')" pad-medium>
|
||||
<vn-card >
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Add credit</vn-title>
|
||||
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Credit" field="$ctrl.client.credit" type="number" vn-focus></vn-textfield>
|
||||
<vn-one></vn-one>
|
||||
</vn-horizontal>
|
||||
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Save"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -0,0 +1,8 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
ngModule.component('vnClientCreditCreate', {
|
||||
template: require('./credit-create.html'),
|
||||
bindings: {
|
||||
client: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"Add credit": "Añadir crédito"
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<mg-ajax path="/client/api/clientCredits/filter" options="vnIndexNonAuto"></mg-ajax>
|
||||
<vn-card pad-medium>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title vn-one margin-large-bottom>Credit</vn-title>
|
||||
|
||||
<vn-grid-header on-order="$ctrl.onOrder(field, order)">
|
||||
<vn-column-header vn-one pad-medium-h field="amount" text="Credit"></vn-column-header>
|
||||
<vn-column-header vn-two pad-medium-h field="created" text="Since" default-order="ASC"></vn-column-header>
|
||||
<vn-column-header vn-two pad-medium-h field="employee.name" text="Employee" order-locked></vn-column-header>
|
||||
</vn-grid-header>
|
||||
<vn-one class="list list-content">
|
||||
<vn-horizontal
|
||||
vn-one class="list list-element text-center"
|
||||
pad-small-bottom
|
||||
ng-repeat="credit in index.model.instances track by credit.id"
|
||||
>
|
||||
<vn-one pad-medium-h>{{::credit.amount | number:2}} €</vn-one>
|
||||
<vn-two pad-medium-h>{{::credit.created | date:'dd/MM/yyyy HH:mm' }}</vn-two>
|
||||
<vn-two pad-medium-h>{{::credit.employee.name}}</vn-two>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</vn-one>
|
||||
<vn-horizontal vn-one class="list list-footer"></vn-horizontal>
|
||||
<vn-paging vn-one margin-large-top index="index" total="index.model.count"></vn-paging>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<a ui-sref="clientCard.credit.create" fixed-bottom-right>
|
||||
<vn-float-button icon="add"></vn-float-button>
|
||||
</a>
|
|
@ -0,0 +1,9 @@
|
|||
import ngModule from '../module';
|
||||
import FilterClientList from '../filterClientList';
|
||||
|
||||
class ClientCreditList extends FilterClientList {}
|
||||
|
||||
ngModule.component('vnClientCreditList', {
|
||||
template: require('./credit-list.html'),
|
||||
controller: ClientCreditList
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Since" : "Desde",
|
||||
"Employee" : "Empleado",
|
||||
"No results": "Sin resultados"
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
export default class FilterClientList {
|
||||
constructor($scope, $timeout, $state) {
|
||||
this.$ = $scope;
|
||||
this.$timeout = $timeout;
|
||||
this.$state = $state;
|
||||
|
||||
this.waitingMgCrud = 0;
|
||||
this.clientFk = $state.params.id;
|
||||
}
|
||||
onOrder(field, order) {
|
||||
this.filter(`${field} ${order}`);
|
||||
}
|
||||
filter(order) {
|
||||
if (this.$.index && this.clientFk) {
|
||||
this.waitingMgCrud = 0;
|
||||
this.$.index.filter = {
|
||||
page: 1,
|
||||
size: 10,
|
||||
clientFk: this.clientFk
|
||||
};
|
||||
|
||||
if (order) {
|
||||
this.$.index.filter.order = order;
|
||||
}
|
||||
|
||||
this.$.index.accept();
|
||||
} else if (this.waitingMgCrud > 3) {
|
||||
throw new Error('Magic Crud is not loaded');
|
||||
} else {
|
||||
this.waitingMgCrud++;
|
||||
this.$timeout(() => {
|
||||
this.filter(order);
|
||||
}, 250);
|
||||
}
|
||||
}
|
||||
}
|
||||
FilterClientList.$inject = ['$scope', '$timeout', '$state'];
|
|
@ -0,0 +1,30 @@
|
|||
<mg-ajax path="/client/api/greuges" options="vnPost"></mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.greuge"
|
||||
form="form"
|
||||
save="post">
|
||||
</vn-watcher>
|
||||
<form pad-medium ng-submit="$ctrl.onSubmit()">
|
||||
<vn-card>
|
||||
<vn-vertical pad-medium>
|
||||
<vn-title vn-one margin-large-bottom>Add Greuge</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one margin-medium-right label="Importe" field="$ctrl.greuge.amount" type="number" vn-focus></vn-textfield>
|
||||
<vn-date-picker vn-one label="Date" model="$ctrl.greuge.shipped"></vn-date-picker>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one margin-medium-right label="Comment" field="$ctrl.greuge.description"></vn-textfield>
|
||||
<vn-autocomplete vn-one
|
||||
field="$ctrl.greuge.greugeTypeFk"
|
||||
url="/client/api/greugeTypes"
|
||||
label="Type"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Save"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -0,0 +1,23 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class ClientGreugeCreate {
|
||||
constructor($scope, $state) {
|
||||
this.$ = $scope;
|
||||
this.$state = $state;
|
||||
this.greuge = {};
|
||||
}
|
||||
onSubmit() {
|
||||
this.greuge.clientFk = this.$state.params.id;
|
||||
this.$.watcher.submit().then(
|
||||
() => {
|
||||
this.$state.go('clientCard.greuge.list');
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
ClientGreugeCreate.$inject = ['$scope', '$state'];
|
||||
|
||||
ngModule.component('vnClientGreugeCreate', {
|
||||
template: require('./greuge-create.html'),
|
||||
controller: ClientGreugeCreate
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
<mg-ajax path="/client/api/greuges/filter" options="vnIndexNonAuto"></mg-ajax>
|
||||
<mg-ajax path="/client/api/greuges/{{edit.params.id}}/sumAmount" options="mgEdit"></mg-ajax>
|
||||
<vn-card pad-medium>
|
||||
<vn-vertical pad-medium>
|
||||
<vn-title vn-one margin-large-bottom>Greuge</vn-title>
|
||||
<vn-grid-header on-order="$ctrl.onOrder(field, order)">
|
||||
<vn-column-header vn-one pad-medium-h field="shipped" text="Date" default-order="ASC"></vn-column-header>
|
||||
<vn-column-header vn-two pad-medium-h field="description" text="Comment"></vn-column-header>
|
||||
<vn-column-header vn-one pad-medium-h field="amount" text="Amount"></vn-column-header>
|
||||
<vn-column-header vn-one pad-medium-h field="greugeTypeFk" text="Type"></vn-column-header>
|
||||
</vn-grid-header>
|
||||
|
||||
<vn-one class="list list-content">
|
||||
<vn-horizontal
|
||||
class="list list-element text-center"
|
||||
pad-small-bottom
|
||||
ng-repeat="greuge in index.model.instances track by greuge.id"
|
||||
>
|
||||
<vn-one pad-medium-h>{{::greuge.shipped | date:'dd/MM/yyyy HH:mm' }}</vn-one>
|
||||
<vn-two pad-medium-h>{{::greuge.description}}</vn-two>
|
||||
<vn-one pad-medium-h>{{::greuge.amount | number:2}} €</vn-one>
|
||||
<vn-one pad-medium-h>{{::greuge.greugeType.name}}</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
|
||||
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</vn-one>
|
||||
<vn-horizontal vn-one class="list list-footer text-center">
|
||||
<vn-one pad-medium-h></vn-one>
|
||||
<vn-two pad-medium-h></vn-two>
|
||||
<vn-one pad-medium-h ng-if="index.model.count > 0">{{edit.model.sumAmount | number:2}} €</vn-one>
|
||||
<vn-one pad-medium-h></vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-paging margin-large-top vn-one index="index" total="index.model.count"></vn-paging>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<a ui-sref="clientCard.greuge.create" fixed-bottom-right>
|
||||
<vn-float-button icon="add"></vn-float-button>
|
||||
</a>
|
|
@ -0,0 +1,9 @@
|
|||
import ngModule from '../module';
|
||||
import FilterClientList from '../filterClientList';
|
||||
|
||||
class ClientGreugeList extends FilterClientList {}
|
||||
|
||||
ngModule.component('vnClientGreugeList', {
|
||||
template: require('./greuge-list.html'),
|
||||
controller: ClientGreugeList
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"Date" : "Fecha",
|
||||
"Comment" : "Comentario",
|
||||
"Amount" : "Importe",
|
||||
"Type": "Tipo",
|
||||
"Add Greuge": "Añadir Greuge"
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"Active": "Activo",
|
||||
"Client": "Cliente",
|
||||
"Clients": "Clientes",
|
||||
"Fiscal data": "Datos Fiscales",
|
||||
"Has to invoice": "Factura",
|
||||
"Invoice by mail": "Factura impresa",
|
||||
"Country": "País",
|
||||
"Street": "Domicilio fiscal",
|
||||
"City": "Municipio",
|
||||
"Postcode": "Código postal",
|
||||
"Province": "Provincia",
|
||||
"Save": "Guardar",
|
||||
"Pay method" : "Forma de pago",
|
||||
"Address": "Consignatario",
|
||||
"Credit": "Crédito"
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"Notes": "Notas"
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"User": "Usuario",
|
||||
"Enable web access": "Habilitar acceso web",
|
||||
"Web access": "Acceso web",
|
||||
"New password": "Nueva contraseña",
|
||||
"Repeat password": "Repetir contraseña",
|
||||
"Change password": "Cambiar contraseña"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="{{$ctrl.className}}" ng-mouseover="$ctrl.mouseIsOver = true" ng-mouseleave="$ctrl.mouseIsOver = false">
|
||||
<vn-horizontal ng-if="$ctrl.text" class="orderly" ng-click="$ctrl.onClick()">
|
||||
<vn-horizontal ng-if="$ctrl.text" class="orderly" ng-class="{'pointer' : !$ctrl.orderLocked}" ng-click="$ctrl.onClick()">
|
||||
<vn-none class="title" translate>
|
||||
{{::$ctrl.text}}
|
||||
</vn-none>
|
||||
|
|
|
@ -1,19 +1,25 @@
|
|||
import {module} from '../module';
|
||||
|
||||
export default class ColumnHeader {
|
||||
constructor() {
|
||||
constructor($attrs) {
|
||||
this.order = undefined;
|
||||
this.mouseIsOver = false;
|
||||
this.orderLocked = ($attrs.orderLocked !== undefined);
|
||||
}
|
||||
onClick() {
|
||||
if (this.order === 'ASC') {
|
||||
this.order = 'DESC';
|
||||
} else {
|
||||
this.order = 'ASC';
|
||||
if (!this.orderLocked) {
|
||||
if (this.order === 'ASC') {
|
||||
this.order = 'DESC';
|
||||
} else {
|
||||
this.order = 'ASC';
|
||||
}
|
||||
this.gridHeader.selectColum(this);
|
||||
}
|
||||
this.gridHeader.selectColum(this);
|
||||
}
|
||||
showArrow(type) {
|
||||
if (this.orderLocked)
|
||||
return false;
|
||||
|
||||
let showArrow = (this.gridHeader && this.gridHeader.currentColumn && this.gridHeader.currentColumn.field === this.field && this.order === type);
|
||||
let showOther = (this.gridHeader && this.gridHeader.currentColumn && this.gridHeader.currentColumn.field === this.field && this.order !== type);
|
||||
if (type === 'DESC' && this.mouseIsOver && !showOther) {
|
||||
|
@ -22,13 +28,13 @@ export default class ColumnHeader {
|
|||
return showArrow;
|
||||
}
|
||||
$onInit() {
|
||||
if (this.defaultOrder) {
|
||||
if (this.defaultOrder && !this.orderLocked) {
|
||||
this.order = this.defaultOrder;
|
||||
this.onClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnHeader.$inject = [];
|
||||
ColumnHeader.$inject = ['$attrs'];
|
||||
|
||||
module.component('vnColumnHeader', {
|
||||
template: require('./column-header.html'),
|
||||
|
|
|
@ -3,6 +3,7 @@ import './column-header.js';
|
|||
describe('Component vnColumnHeader', () => {
|
||||
let $componentController;
|
||||
let controller;
|
||||
let $attrs;
|
||||
|
||||
beforeEach(() => {
|
||||
angular.mock.module('client');
|
||||
|
@ -10,7 +11,8 @@ describe('Component vnColumnHeader', () => {
|
|||
|
||||
beforeEach(angular.mock.inject(_$componentController_ => {
|
||||
$componentController = _$componentController_;
|
||||
controller = $componentController('vnColumnHeader', {});
|
||||
$attrs = {};
|
||||
controller = $componentController('vnColumnHeader', {$attrs});
|
||||
}));
|
||||
|
||||
describe('onClick()', () => {
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
ng-focus="$ctrl.hasFocus = true"
|
||||
ng-blur="$ctrl.hasFocus = false"
|
||||
ng-mouseenter="$ctrl.hasMouseIn = true"
|
||||
ng-mouseleave="$ctrl.hasMouseIn = false"
|
||||
ng-mouseleave="$ctrl.hasMouseIn = false"
|
||||
ng-click="$ctrl.onClick()"
|
||||
>
|
||||
<input type="text"
|
||||
class="mdl-textfield__input"
|
||||
|
|
|
@ -59,6 +59,11 @@ class DatePicker extends Component {
|
|||
onClear() {
|
||||
this.modelView = null;
|
||||
}
|
||||
onClick() {
|
||||
if (this.vp) {
|
||||
this.vp.open();
|
||||
}
|
||||
}
|
||||
mdlUpdate() {
|
||||
let mdlField = this.element.firstChild.MaterialTextfield;
|
||||
if (mdlField)
|
||||
|
@ -167,14 +172,23 @@ class DatePicker extends Component {
|
|||
return this.iniOptions;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
initPicker() {
|
||||
this.iniOptions = this._getOptions();
|
||||
this.isTimePicker = (this.iniOptions && this.iniOptions.enableTime && this.iniOptions.noCalendar);
|
||||
this.vp = new Flatpickr(this.input, this.iniOptions);
|
||||
}
|
||||
$onDestroy() {
|
||||
destroyPicker() {
|
||||
if (this.vp)
|
||||
this.vp.destroy();
|
||||
this.vp = undefined;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.initPicker();
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
this.destroyPicker();
|
||||
}
|
||||
}
|
||||
DatePicker.$inject = ['$element', '$translate', '$filter', '$timeout'];
|
||||
|
|
|
@ -140,14 +140,6 @@ describe('Component vnDropDown', () => {
|
|||
});
|
||||
|
||||
describe('$onChanges()', () => {
|
||||
it(`should set the top css of the $element`, () => {
|
||||
let argumentObject = {show: true, top: {currentValue: 100}};
|
||||
spyOn(controller.$element, 'css');
|
||||
controller.$onChanges(argumentObject);
|
||||
|
||||
expect(controller.$element.css).toHaveBeenCalledWith('top', '100px');
|
||||
});
|
||||
|
||||
it(`should set the width css of the $element`, () => {
|
||||
let argumentObject = {show: true, itemWidth: {currentValue: 100}};
|
||||
spyOn(controller.$element, 'css');
|
||||
|
@ -295,26 +287,40 @@ describe('Component vnDropDown', () => {
|
|||
controller.selectItem(item);
|
||||
|
||||
expect(controller.selected).toEqual(item);
|
||||
expect(controller._show).toEqual(true);
|
||||
expect(controller._show).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadItems()', () => {
|
||||
it(`should set controller._show to true`, () => {
|
||||
it(`should set controller.show to true`, () => {
|
||||
controller.show = false;
|
||||
controller.itemsFiltered = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
|
||||
controller.loadItems();
|
||||
|
||||
expect(controller._show).toEqual(true);
|
||||
expect(controller.show).toEqual(true);
|
||||
});
|
||||
|
||||
it(`should call loadMore() and then set controller._show to true`, () => {
|
||||
it(`should call loadMore() and then set controller._show to true if there are items`, () => {
|
||||
controller.showLoadMore = () => {};
|
||||
controller.loadMore = () => {};
|
||||
spyOn(controller, 'loadMore');
|
||||
controller.itemsFiltered = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
|
||||
controller.loadItems();
|
||||
|
||||
expect(controller._show).toEqual(true);
|
||||
expect(controller.loadMore).toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
it(`should call loadMore() and then set controller._show to undefined if there are not items`, () => {
|
||||
controller.showLoadMore = () => {};
|
||||
controller.loadMore = () => {};
|
||||
spyOn(controller, 'loadMore');
|
||||
controller.itemsFiltered = [];
|
||||
controller.loadItems();
|
||||
|
||||
expect(controller._show).not.toBeDefined();
|
||||
expect(controller.loadMore).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('$onInit()', () => {
|
||||
|
|
|
@ -2,7 +2,6 @@ vn-grid-header {
|
|||
border-bottom: 3px solid #9D9D9D;
|
||||
font-weight: bold;
|
||||
.orderly{
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
justify-content: center;
|
||||
|
|
|
@ -68,9 +68,9 @@ export default class Watcher extends Component {
|
|||
*
|
||||
* @param {String} state The state name
|
||||
*/
|
||||
submitGo(state) {
|
||||
submitGo(state, params) {
|
||||
return this.submit().then(
|
||||
() => this.$state.go(state)
|
||||
() => this.$state.go(state, params || {})
|
||||
);
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -100,11 +100,11 @@ describe('Component vnWatcher', () => {
|
|||
it(`should call controller.$state.go() function after calling controllers submit() function`, done => {
|
||||
spyOn(controller, 'submit').and.returnValue(Promise.resolve());
|
||||
spyOn(controller.$state, 'go');
|
||||
let state = 'the state';
|
||||
let state = 'the.State';
|
||||
controller.submitGo(state)
|
||||
.then(() => {
|
||||
expect(controller.submit).toHaveBeenCalledWith();
|
||||
expect(controller.$state.go).toHaveBeenCalledWith(state);
|
||||
expect(controller.$state.go).toHaveBeenCalledWith(state, {});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,6 +13,8 @@ export class ProductionTable {
|
|||
},
|
||||
model: []
|
||||
};
|
||||
this.filteredField = null;
|
||||
this.filteredReverse = null;
|
||||
}
|
||||
get checkAll() {
|
||||
return this._checkAll;
|
||||
|
@ -21,7 +23,7 @@ export class ProductionTable {
|
|||
this._checkAll = value;
|
||||
}
|
||||
set tickets(value) {
|
||||
this._tickets = value;
|
||||
this._tickets = this.filteredField ? this.$filter('orderBy')(value, this.filteredField, this.filteredReverse) : value;
|
||||
this.totalFilter = this._tickets.length;
|
||||
this.pageTable.filter.page = 1;
|
||||
this.pageTickets();
|
||||
|
@ -30,8 +32,9 @@ export class ProductionTable {
|
|||
return this._tickets;
|
||||
}
|
||||
onOrder(field, order) {
|
||||
let reverse = order === 'DESC';
|
||||
this.tickets = this.$filter('orderBy')(this.tickets, field, reverse);
|
||||
this.filteredField = field;
|
||||
this.filteredReverse = order === 'DESC';
|
||||
this.tickets = this.tickets; // call tickets setter
|
||||
}
|
||||
pageTickets() {
|
||||
let init = (this.pageTable.filter.page - 1) * this.itemsDisplayedInList;
|
||||
|
|
|
@ -9,7 +9,7 @@ export default class MenuActions {
|
|||
switchItem() {
|
||||
if (!this.items || !this.items.length) return;
|
||||
|
||||
let stateName = this.$state.current.name.replace('create', 'list').replace('edit', 'list');
|
||||
let stateName = this.$state.current.name.replace('.create', '.list').replace('.edit', '.list');
|
||||
|
||||
for (let i = 0; i < this.items.length; i++) {
|
||||
this.items[i].active = (this.items[i].href === stateName);
|
||||
|
|
|
@ -47,9 +47,8 @@ function config($stateProvider, $urlRouterProvider, aclServiceProvider, modulesF
|
|||
for (let i = 0; i < count; i++) {
|
||||
let route = fileRoutes[i];
|
||||
if (aclService.routeHasPermission(route)) {
|
||||
$stateProvider.state(route.state, {
|
||||
let configRoute = {
|
||||
url: route.url,
|
||||
abstract: route.abstract || false,
|
||||
template: `<${route.component} ${getParams(route)}></${route.component}>`,
|
||||
resolve: {
|
||||
loader: loader(moduleName, validations)
|
||||
|
@ -57,7 +56,13 @@ function config($stateProvider, $urlRouterProvider, aclServiceProvider, modulesF
|
|||
data: {
|
||||
routes: fileRoutes
|
||||
}
|
||||
});
|
||||
};
|
||||
if (route.abstract)
|
||||
configRoute.abstract = true;
|
||||
if (route.routeParams)
|
||||
configRoute.params = route.routeParams;
|
||||
|
||||
$stateProvider.state(route.state, configRoute);
|
||||
} else if (route.state === mainModule.state) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -88,29 +88,4 @@ module.exports = function(app) {
|
|||
User.logout(req.accessToken.id,
|
||||
() => res.redirect('/'));
|
||||
});
|
||||
|
||||
app.get('/validateToken', function(req, res) {
|
||||
let token = req.headers.authorization;
|
||||
|
||||
validateToken(token, function(isValid) {
|
||||
if (isValid) {
|
||||
res.status(200);
|
||||
} else {
|
||||
res.status(401).json({
|
||||
message: 'Invalid token'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function validateToken(tokenId, cb) {
|
||||
app.models.AccessToken.findById(tokenId, function(err, token) {
|
||||
if (token) {
|
||||
token.validate(function (err, isValid) {
|
||||
cb(isValid === true, token);
|
||||
});
|
||||
} else
|
||||
cb(false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -49,7 +49,7 @@ module.exports = function(Client) {
|
|||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
'authorization': ctx.req.headers.authorization
|
||||
'Authorization': ctx.req.headers.authorization
|
||||
},
|
||||
json: {}
|
||||
};
|
||||
|
|
|
@ -116,12 +116,7 @@ module.exports = function(Client) {
|
|||
}
|
||||
|
||||
function maxCb(_, instances) {
|
||||
if (!instances) {
|
||||
done(generateErrorCredit());
|
||||
return;
|
||||
}
|
||||
|
||||
if (instances.length !== 1 || instances[0].employeeFk == userId || instances[0].amount > 0) {
|
||||
if (!instances || instances.length !== 1 || instances[0].employeeFk == userId || instances[0].amount > 0) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
module.exports = Self => {
|
||||
Self.installMethod('filter', filterParams);
|
||||
|
||||
function filterParams(params) {
|
||||
return {
|
||||
where: {
|
||||
clientFk: params.clientFk
|
||||
},
|
||||
skip: (params.page - 1) * params.size,
|
||||
limit: params.size,
|
||||
order: params.order || 'shipped DESC',
|
||||
include: {
|
||||
relation: "greugeType",
|
||||
scope: {
|
||||
fields: ["id", "name"]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('sumAmount', {
|
||||
description: 'returns sum greuge.ammount from client',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'clientFk',
|
||||
http: {source: 'path'}
|
||||
}],
|
||||
returns: {
|
||||
arg: 'sumAmount'
|
||||
},
|
||||
http: {
|
||||
path: `/:id/sumAmount`,
|
||||
verb: 'get'
|
||||
}
|
||||
});
|
||||
|
||||
Self.sumAmount = (clientFk, callback) => {
|
||||
let query = `SELECT sum(amount) as sumAmount FROM vn.greuge WHERE clientFk = ?`;
|
||||
Self.rawSql(query, [clientFk], callback).then(response => {
|
||||
if (response.length) {
|
||||
callback(null, response[0].sumAmount);
|
||||
} else {
|
||||
callback(null, 0);
|
||||
}
|
||||
})
|
||||
.catch(reject => {
|
||||
callback(reject, null);
|
||||
});
|
||||
};
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
module.exports = function(Self) {
|
||||
Self.installMethod('filter', filterParams, filterResults);
|
||||
|
||||
function filterParams(params) {
|
||||
return {
|
||||
where: {
|
||||
clientFk: params.clientFk
|
||||
},
|
||||
skip: (params.page - 1) * params.size,
|
||||
limit: params.size,
|
||||
order: params.order || 'created DESC',
|
||||
include: {
|
||||
relation: "employee",
|
||||
scope: {
|
||||
fields: ["id", "name", "surname"]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function filterResults(instances) {
|
||||
let result = JSON.parse(JSON.stringify(instances));
|
||||
if (result && result.instances && result.instances.length) {
|
||||
result.instances.forEach((element, i) => {
|
||||
result.instances[i].employee.name = `${element.employee.name} ${element.employee.surname}`;
|
||||
delete result.instances[i].employee.surname;
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "ClientCredit",
|
||||
"name": "clientCredit",
|
||||
"base": "VnModel",
|
||||
"validateUpsert": true,
|
||||
"properties": {
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "greugeType",
|
||||
"base": "VnModel",
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "Number",
|
||||
"description": "Identifier"
|
||||
},
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = function(Self) {
|
||||
require('../methods/greuge/filter.js')(Self);
|
||||
require('../methods/greuge/totalGreuge.js')(Self);
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "greuge",
|
||||
"base": "VnModel",
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "Number",
|
||||
"description": "Identifier"
|
||||
},
|
||||
"description": {
|
||||
"type": "String"
|
||||
},
|
||||
"amount": {
|
||||
"type": "Number"
|
||||
},
|
||||
"shipped": {
|
||||
"type": "date"
|
||||
},
|
||||
"created": {
|
||||
"type": "date"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"client": {
|
||||
"type": "belongsTo",
|
||||
"model": "Client",
|
||||
"foreignKey": "clientFk"
|
||||
},
|
||||
"greugeType": {
|
||||
"type": "belongsTo",
|
||||
"model": "greugeType",
|
||||
"foreignKey": "greugeTypeFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
module.exports = fi => {
|
||||
if (fi === undefined || fi === null) {
|
||||
return true;
|
||||
}
|
||||
let dni = fi;
|
||||
let getLetterDni = dni => {
|
||||
const regExpDni = 'TRWAGMYFPDXBNJZSQVHLCKE';
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
"Client": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ClientCredit": {
|
||||
"dataSource": "salix"
|
||||
"clientCredit": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ClientCreditLimit": {
|
||||
"dataSource": "salix"
|
||||
|
@ -59,5 +59,11 @@
|
|||
},
|
||||
"CreditClassification": {
|
||||
"dataSource": "salix"
|
||||
},
|
||||
"greuge": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"greugeType": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ module.exports = function(Self) {
|
|||
};
|
||||
};
|
||||
|
||||
Self.installMethod = function(methodName, filterCb) {
|
||||
Self.installMethod = function(methodName, filterCb, filterResult) {
|
||||
this.remoteMethod(methodName, {
|
||||
description: 'List items using a filter',
|
||||
accessType: 'READ',
|
||||
|
@ -161,8 +161,12 @@ module.exports = function(Self) {
|
|||
var response = {};
|
||||
|
||||
function returnValues() {
|
||||
if (response.instances !== undefined && response.count !== undefined)
|
||||
cb(null, response);
|
||||
if (response.instances !== undefined && response.count !== undefined) {
|
||||
if (filterResult)
|
||||
cb(null, filterResult(response));
|
||||
else
|
||||
cb(null, response);
|
||||
}
|
||||
}
|
||||
|
||||
function error() {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
var database = require('./database.js');
|
||||
let config = require('./config.js');
|
||||
|
||||
module.exports = {
|
||||
|
||||
|
@ -31,7 +32,23 @@ module.exports = {
|
|||
if (this.isTokenExpired(token.created, token.ttl))
|
||||
return this.response.status(401).send({message: 'Token expired'});
|
||||
|
||||
this.request.userId = token.userId;
|
||||
// Set proxy host
|
||||
let host = this.request.headers.host.split(':')[0];
|
||||
let proxy;
|
||||
|
||||
if (host == '127.0.0.1')
|
||||
proxy = config.proxy.localhost;
|
||||
else if (process.env.NODE_ENV == 'production')
|
||||
proxy = config.proxy.salix;
|
||||
else if (process.env.NODE_ENV == 'development')
|
||||
proxy = config.proxy.testSalix;
|
||||
|
||||
this.request.proxyHost = `http://${proxy.host}:${proxy.port}`;
|
||||
this.request.user = {
|
||||
id: token.userId,
|
||||
token: this.getToken()
|
||||
}
|
||||
|
||||
this.next();
|
||||
});
|
||||
},
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var config = {};
|
||||
|
||||
let devConfigPath = path.join(__dirname, '/config/datasources.development.json');
|
||||
let configPath = path.join(__dirname, '/config/datasources.json');
|
||||
|
||||
try {
|
||||
config = Object.assign(require(configPath), require(devConfigPath));
|
||||
} catch (e) {
|
||||
if (e.code == 'MODULE_NOT_FOUND')
|
||||
config = require(configPath);
|
||||
}
|
||||
|
||||
config.proxy = require('../../nginx/config.json');
|
||||
config.package = require('../package.json');
|
||||
|
||||
module.exports = config;
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "MailServer",
|
||||
"version": "1.0.0",
|
||||
"port": 3003,
|
||||
"debug": false,
|
||||
"defaultLanguage": "es",
|
||||
"senderMail": "noreply@localhost",
|
||||
"senderName": ""
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "MailServer",
|
||||
"version": "1.0.0",
|
||||
"port": 3003,
|
||||
"debug": false,
|
||||
"defaultLanguage": "es",
|
||||
"senderMail": "noreply@localhost",
|
||||
"senderName": ""
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"app": {
|
||||
"port": 3003,
|
||||
"debug": false,
|
||||
"defaultLanguage": "es",
|
||||
"senderMail": "noreply@localhost",
|
||||
"senderName": ""
|
||||
},
|
||||
"mysql": {
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"user": "reports",
|
||||
"password": "",
|
||||
"database": ""
|
||||
},
|
||||
"smtp": {
|
||||
"host": "localhost",
|
||||
"port": 465,
|
||||
"secure": true,
|
||||
"auth": {
|
||||
"user": "noreply",
|
||||
"pass": ""
|
||||
},
|
||||
"tls": {
|
||||
"rejectUnauthorized": false
|
||||
},
|
||||
"pool": true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"app": {
|
||||
"port": 3003,
|
||||
"debug": false,
|
||||
"defaultLanguage": "es",
|
||||
"senderMail": "noreply@localhost",
|
||||
"senderName": ""
|
||||
},
|
||||
"mysql": {
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"user": "reports",
|
||||
"password": "",
|
||||
"database": ""
|
||||
},
|
||||
"smtp": {
|
||||
"host": "localhost",
|
||||
"port": 465,
|
||||
"secure": true,
|
||||
"auth": {
|
||||
"user": "noreply",
|
||||
"pass": ""
|
||||
},
|
||||
"tls": {
|
||||
"rejectUnauthorized": false
|
||||
},
|
||||
"pool": true
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"user": "reports",
|
||||
"password": "",
|
||||
"database": ""
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"user": "root",
|
||||
"password": "",
|
||||
"database": "vn"
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"host": "localhost",
|
||||
"port": 465,
|
||||
"secure": true,
|
||||
"auth": {
|
||||
"user": "noreply",
|
||||
"pass": ""
|
||||
},
|
||||
"tls": {
|
||||
"rejectUnauthorized": false
|
||||
},
|
||||
"pool": true
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
var mysql = require('mysql');
|
||||
let settings = require('./settings.js');
|
||||
let config = require('./config.js');
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
|
@ -11,12 +11,12 @@ module.exports = {
|
|||
* Start database pool
|
||||
*/
|
||||
init: function() {
|
||||
this.pool = mysql.createPool(settings.mysql());
|
||||
this.pool = mysql.createPool(config.mysql);
|
||||
|
||||
this.pool.getConnection(function(error, connection) {
|
||||
if (error) {
|
||||
throw new Error('Can\'t connect to database: ' + error.code);
|
||||
} else if (settings.app().debug) {
|
||||
} else if (config.app.debug) {
|
||||
console.log('Database connection stablished');
|
||||
}
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ module.exports = {
|
|||
*/
|
||||
testEmail: function() {
|
||||
this.pool.query('SELECT fakeEmail as email FROM vn.config', function(error, qryRs) {
|
||||
settings.testEmail = qryRs[0].email;
|
||||
config.smtp.testEmail = qryRs[0].email;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
var fs = require('fs');
|
||||
var settings = require('./settings.js');
|
||||
var config = require('./config.js');
|
||||
var path = require('path');
|
||||
|
||||
module.exports = {
|
||||
|
@ -11,7 +11,7 @@ module.exports = {
|
|||
*/
|
||||
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`);
|
||||
var defaultLocaleFile = path.join(__dirname, 'template', `${template}`, 'locale', `${config.app.defaultLanguage}.json`);
|
||||
|
||||
fs.stat(localeFile, (error, stats) => {
|
||||
if (error) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
var nodemailer = require('nodemailer');
|
||||
var settings = require('./settings.js');
|
||||
var config = require('./config.js');
|
||||
var template = require('./template.js');
|
||||
var database = require('./database.js');
|
||||
|
||||
|
@ -9,15 +9,15 @@ var database = require('./database.js');
|
|||
module.exports = {
|
||||
transporter: null,
|
||||
/**
|
||||
* Load mail settings.
|
||||
* Load mail config.
|
||||
*/
|
||||
init: function() {
|
||||
this.transporter = nodemailer.createTransport(settings.smtp());
|
||||
this.transporter = nodemailer.createTransport(config.smtp);
|
||||
|
||||
this.transporter.verify(function(error, success) {
|
||||
if (error) {
|
||||
throw new Error(error);
|
||||
} else if (settings.app().debug) {
|
||||
} else if (config.app.debug) {
|
||||
console.log('SMTP connection stablished');
|
||||
}
|
||||
});
|
||||
|
@ -34,15 +34,15 @@ module.exports = {
|
|||
*/
|
||||
send: function(recipient, subject, body, attachments, params, cb) {
|
||||
let mailOptions = {
|
||||
from: '"' + settings.app().senderName + '" <' + settings.app().senderMail + '>',
|
||||
from: '"' + config.app.senderName + '" <' + config.app.senderMail + '>',
|
||||
to: recipient,
|
||||
subject: subject,
|
||||
html: body,
|
||||
attachments
|
||||
};
|
||||
|
||||
if (settings.app().debug) {
|
||||
mailOptions.to = settings.testEmail;
|
||||
if (config.app.debug) {
|
||||
mailOptions.to = config.smtp.testEmail;
|
||||
}
|
||||
|
||||
this.transporter.sendMail(mailOptions, (error, info) => {
|
||||
|
@ -53,7 +53,7 @@ module.exports = {
|
|||
if (error)
|
||||
return cb(new Error('Email not sent: ' + error));
|
||||
|
||||
if (settings.app().debug)
|
||||
if (config.app.debug)
|
||||
console.log('Mail sent ' + info.messageId + ' [' + info.response + ']');
|
||||
|
||||
cb();
|
||||
|
@ -70,10 +70,16 @@ module.exports = {
|
|||
* @param {Object} cb - Callback
|
||||
*/
|
||||
sendWithTemplate: function(tplName, params, cb) {
|
||||
template.get(tplName, params, false, (error, result) => {
|
||||
template.get(tplName, params, (error, result) => {
|
||||
if (error)
|
||||
return cb(error);
|
||||
|
||||
// Custom attachments
|
||||
if (params.attachments)
|
||||
params.attachments.forEach(function(attachment) {
|
||||
result.attachments.push(attachment);
|
||||
});
|
||||
|
||||
this.send(result.recipient, result.subject, result.body, result.attachments, params, error => {
|
||||
if (error)
|
||||
return cb(error);
|
||||
|
@ -96,10 +102,10 @@ module.exports = {
|
|||
log: function(senderId, recipientId, sender, subject, body, plainTextBody, status) {
|
||||
let qry = `INSERT INTO mail(senderFk, recipientFk, sender, replyTo, subject, body, plainTextBody, sent, status)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
||||
let qryParams = [senderId, recipientId, sender, settings.app().senderMail, subject, body, plainTextBody, 1, status];
|
||||
let qryParams = [senderId, recipientId, sender, config.app.senderMail, subject, body, plainTextBody, 1, status];
|
||||
|
||||
database.pool.query(qry, qryParams, function(error, result) {
|
||||
if (settings.app().debug && error)
|
||||
if (config.app.debug && error)
|
||||
console.log('Mail log: ' + error);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
var express = require('express');
|
||||
var router = new express.Router();
|
||||
var mail = require('../mail.js');
|
||||
var template = require('../template.js');
|
||||
var httpRequest = require('request');
|
||||
|
||||
// Payment method changes
|
||||
router.post('/payment-update/:clientId', function(request, response, next) {
|
||||
mail.sendWithTemplate('payment-update', {recipient: request.params.clientId}, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
|
||||
// Printer setup
|
||||
router.post('/printer-setup/:clientId', function(request, response, next) {
|
||||
mail.sendWithTemplate('printer-setup', {recipient: request.params.clientId}, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
|
||||
// Printer setup preview
|
||||
router.get('/printer-setup/:clientId', function(request, response, next) {
|
||||
template.get('printer-setup', {recipient: request.params.clientId}, true, (error, result) => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
response.send(result.body);
|
||||
});
|
||||
});
|
||||
|
||||
// Client welcome
|
||||
router.post('/client-welcome/:clientId', function(request, response, next) {
|
||||
mail.sendWithTemplate('client-welcome', {recipient: request.params.clientId}, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
|
||||
// Client welcome preview
|
||||
router.get('/client-welcome/:clientId', function(request, response, next) {
|
||||
template.get('client-welcome', {recipient: request.params.clientId}, true, (error, result) => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
response.send(result.body);
|
||||
});
|
||||
});
|
||||
|
||||
// Sepa core
|
||||
/* router.post('/sepa-core/:clientId', function(request, response, next) {
|
||||
var options = {
|
||||
url: 'http://localhost:3008/manuscript/sepa-core/7422',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'authorization': request.headers.authorization
|
||||
}
|
||||
}
|
||||
|
||||
let httpStream = httpRequest(options, function(error, httpResponse, body) {
|
||||
if (error)
|
||||
return response.status(400).json({message: httpResponse.message});
|
||||
});
|
||||
|
||||
if (httpStream)
|
||||
mail.send('joan@verdnatura.es', 'Correu de prova', 'test message', [{filename: 'test.pdf', content: httpStream}], function(error, result) {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
});
|
||||
/* mail.sendWithTemplate('sepa-core', {recipient: request.params.clientId}, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
}); */
|
||||
|
||||
module.exports = router;
|
|
@ -1,8 +1,92 @@
|
|||
var express = require('express');
|
||||
var router = new express.Router();
|
||||
var config = require('../config.js');
|
||||
var mail = require('../mail.js');
|
||||
var database = require('../database.js');
|
||||
var settings = require('../settings.js');
|
||||
var template = require('../template.js');
|
||||
var httpRequest = require('request');
|
||||
|
||||
|
||||
// Printer setup
|
||||
router.post('/printer-setup/:clientId', function(request, response) {
|
||||
mail.sendWithTemplate('printer-setup', {clientId: request.params.clientId}, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
|
||||
// Printer setup preview
|
||||
router.get('/printer-setup/:clientId', function(request, response) {
|
||||
template.get('printer-setup', {clientId: request.params.clientId, isPreview: true}, (error, result) => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
response.send(result.body);
|
||||
});
|
||||
});
|
||||
|
||||
// Client welcome
|
||||
router.post('/client-welcome/:clientId', function(request, response) {
|
||||
mail.sendWithTemplate('client-welcome', {clientId: request.params.clientId}, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
|
||||
// Client welcome preview
|
||||
router.get('/client-welcome/:clientId', function(request, response) {
|
||||
template.get('client-welcome', {clientId: request.params.clientId, isPreview: true}, (error, result) => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
response.send(result.body);
|
||||
});
|
||||
});
|
||||
|
||||
// Client SEPA CORE
|
||||
router.post('/sepa-core/:clientId', function(request, response) {
|
||||
let path = `${request.proxyHost}/print/manuscript/sepa-core/${request.params.clientId}`;
|
||||
let options = {
|
||||
url: path,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': request.headers.authorization
|
||||
}
|
||||
}
|
||||
|
||||
let httpStream = httpRequest(options, function(error, httpResponse, body) {
|
||||
if (error || httpResponse.statusCode != 200)
|
||||
return response.status(400).json({message: error.message});
|
||||
});
|
||||
|
||||
if (httpStream)
|
||||
mail.sendWithTemplate('sepa-core', {
|
||||
clientId: request.params.clientId,
|
||||
attachments: [{filename: 'sepa-core.pdf', content: httpStream}]
|
||||
}, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
|
||||
// Client SEPA CORE preview
|
||||
router.get('/sepa-core/:clientId', function(request, response) {
|
||||
template.get('sepa-core', {
|
||||
clientId: request.params.clientId,
|
||||
token: request.user.token,
|
||||
isPreview: true
|
||||
}, (error, result) => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
response.send(result.body);
|
||||
});
|
||||
});
|
||||
|
||||
// Single user notification
|
||||
/* router.post('/:recipient/noticeUserSend', function(request, response) {
|
||||
|
@ -64,6 +148,16 @@ var settings = require('../settings.js');
|
|||
});
|
||||
}); */
|
||||
|
||||
// Payment method changes
|
||||
router.post('/payment-update/:clientId', function(request, response) {
|
||||
mail.sendWithTemplate('payment-update', {clientId: request.params.clientId}, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
|
||||
// Send notification to alias creditInsurance on client deactivate
|
||||
router.post('/client-deactivate/:clientId', function(request, response) {
|
||||
var params = {
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
var express = require('express');
|
||||
var router = new express.Router();
|
||||
var settings = require('./settings.js');
|
||||
|
||||
// Mailer default page
|
||||
router.get('/', function(request, response) {
|
||||
response.json({});
|
||||
});
|
||||
|
||||
// Manuscripts
|
||||
router.use('/manuscript', require('./route/manuscript.js'));
|
||||
|
||||
// Notifications
|
||||
router.use('/notification', require('./route/notification.js'));
|
||||
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
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');
|
||||
},
|
||||
|
||||
testEmail: function() {
|
||||
return this.getConfig('app').testEmail;
|
||||
}
|
||||
};
|
|
@ -1,8 +1,8 @@
|
|||
var fs = require('fs');
|
||||
var mustache = require('mustache');
|
||||
var locale = require('./locale.js');
|
||||
var path = require('path');
|
||||
var inlineCss = require('inline-css');
|
||||
var path = require('path');
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
|
@ -12,10 +12,10 @@ module.exports = {
|
|||
* @param {Object} params - Params
|
||||
* @param {Object} cb - Callback
|
||||
*/
|
||||
get: function(template, params, isPreview, cb) {
|
||||
get: function(template, params, cb) {
|
||||
var templatePath = path.join(__dirname, 'template', `${template}`, `index.html`);
|
||||
var classPath = path.join(__dirname, 'template', `${template}`, `${template}.js`);
|
||||
var stylePath = path.join(__dirname, '../static', 'css', 'style.css');
|
||||
var stylePath = path.join(__dirname, 'template', `${template}`, 'static', 'css', 'style.css');
|
||||
|
||||
fs.stat(templatePath, (error, stat) => {
|
||||
if (error)
|
||||
|
@ -24,14 +24,26 @@ module.exports = {
|
|||
let TemplateClass = require(classPath);
|
||||
let instance = new TemplateClass();
|
||||
|
||||
let getRenderedStyles = body => {
|
||||
let getRenderedStyles = (error, body) => {
|
||||
if (error)
|
||||
return cb(error);
|
||||
|
||||
this.renderStyles(stylePath, body, (error, body) => {
|
||||
if (error)
|
||||
return cb(error);
|
||||
|
||||
// Check if has a subject param
|
||||
params.subject = params.subject || instance.subject;
|
||||
|
||||
if (params.subject == undefined)
|
||||
params.subject = body.match(new RegExp('<title>(.*?)</title>', 'i'))[1];
|
||||
if (params.subject == undefined) {
|
||||
// Try to find a subject from Html source
|
||||
let title = body.match(new RegExp('<title>(.*?)</title>', 'i'));
|
||||
|
||||
this.getAttachments(template, body, isPreview, (error, result) => {
|
||||
if (title)
|
||||
params.subject = title[1];
|
||||
}
|
||||
|
||||
this.getAttachments(template, body, params.isPreview, (error, result) => {
|
||||
if (error)
|
||||
return cb(error);
|
||||
|
||||
|
@ -41,7 +53,7 @@ module.exports = {
|
|||
};
|
||||
|
||||
let getDataCb = () => {
|
||||
this.render(templatePath, instance, (error, result) => getRenderedStyles(result));
|
||||
this.render(templatePath, instance, (error, result) => getRenderedStyles(error, result));
|
||||
};
|
||||
|
||||
instance.getData(params, (error, result) => {
|
||||
|
@ -66,9 +78,54 @@ module.exports = {
|
|||
* @param {Object} cb - Callback
|
||||
*/
|
||||
render: function(path, data, cb) {
|
||||
fs.readFile(path, 'utf8', function(error, body) {
|
||||
mustache.parse(body);
|
||||
cb(null, mustache.render(body, data));
|
||||
fs.readFile(path, 'utf8', (error, body) => {
|
||||
// Find matching sub-templates
|
||||
let regexp = new RegExp(/\{\{\$\.(.*?)\}\}/, 'ig');
|
||||
let subTpl = body.match(regexp);
|
||||
|
||||
if (!subTpl) {
|
||||
mustache.parse(body);
|
||||
return cb(null, mustache.render(body, data));
|
||||
}
|
||||
|
||||
let parentBody = body;
|
||||
this.renderSub(parentBody, subTpl, data, regexp, (error, body) => {
|
||||
if (error)
|
||||
return cb(error);
|
||||
|
||||
mustache.parse(body);
|
||||
cb(null, mustache.render(body, data));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Render sub-template
|
||||
* @param {String} body - Raw body
|
||||
* @param {Object} subTpl - Sub-template name
|
||||
* @param {Object} data - Params
|
||||
* @param {Object} regexp - Regexp
|
||||
* @param {Object} cb - Callback
|
||||
*/
|
||||
renderSub: function(body, subTpl, data, regexp, cb) {
|
||||
let index = 1;
|
||||
|
||||
subTpl.forEach(keyName => {
|
||||
subTplName = keyName.replace(regexp, '$1');
|
||||
|
||||
this.get(subTplName, data, (error, result) => {
|
||||
if (error)
|
||||
return cb(error);
|
||||
|
||||
let subTplBody = result.body;
|
||||
body = body.replace(keyName, subTplBody);
|
||||
|
||||
if (index === subTpl.length)
|
||||
cb(null, body);
|
||||
|
||||
index++;
|
||||
});
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -78,18 +135,25 @@ module.exports = {
|
|||
* @param {String} body - Rendered html
|
||||
* @param {Object} cb - Callback
|
||||
*/
|
||||
renderStyles: function(path, html, cb) {
|
||||
fs.stat(path, error => {
|
||||
if (error) return cb(new Error('Template stylesheet not found'));
|
||||
fs.readFile(path, 'utf8', (error, css) => {
|
||||
let style = '<style>' + css + '</style>';
|
||||
let body = style + html;
|
||||
let options = {url: ' '};
|
||||
renderStyles: function(stylePath, html, cb) {
|
||||
// Common components
|
||||
let comPath = path.join(__dirname, '../', 'static', 'css', 'component.css');
|
||||
|
||||
inlineCss(body, options)
|
||||
.then(function(body) {
|
||||
cb(null, body);
|
||||
});
|
||||
fs.readFile(comPath, 'utf8', (error, comCss) => {
|
||||
fs.stat(stylePath, error => {
|
||||
if (error)
|
||||
return cb(new Error('Template stylesheet not found'));
|
||||
|
||||
fs.readFile(stylePath, 'utf8', (error, css) => {
|
||||
let style = '<style>' + comCss + css + '</style>';
|
||||
let body = style + html;
|
||||
let options = {url: ' '};
|
||||
|
||||
inlineCss(body, options)
|
||||
.then(function(body) {
|
||||
cb(null, body);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -104,6 +168,9 @@ module.exports = {
|
|||
let attachments = [];
|
||||
let tplAttachments = body.match(new RegExp('src="cid:(.*?)"', 'ig'));
|
||||
|
||||
if (!tplAttachments)
|
||||
tplAttachments = {};
|
||||
|
||||
// Template default attachments
|
||||
for (var i = 0; i < tplAttachments.length; i++) {
|
||||
let name = tplAttachments[i].replace('src="cid:', '').replace('"', '');
|
||||
|
@ -125,7 +192,7 @@ module.exports = {
|
|||
|
||||
fs.stat(attachmentsPath, (error, stats) => {
|
||||
if (error)
|
||||
return cb(new Error(`Could not load attachments.js from template ${template}`));
|
||||
return cb(null, {body: body, attachments: attachments});
|
||||
|
||||
let attachObj = require(attachmentsPath);
|
||||
|
||||
|
@ -145,10 +212,10 @@ module.exports = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Check all template attachments
|
||||
* @param {Object} attachments - Attachments object
|
||||
* @param {Object} cb - Callback
|
||||
*/
|
||||
* Check all template attachments
|
||||
* @param {Object} attachments - Attachments object
|
||||
* @param {Object} cb - Callback
|
||||
*/
|
||||
checkAttachments: function(attachments, cb) {
|
||||
for (var i = 0; i < attachments.length; i++) {
|
||||
var attachment = attachments[i];
|
||||
|
@ -159,4 +226,4 @@ module.exports = {
|
|||
}
|
||||
cb();
|
||||
}
|
||||
};
|
||||
};
|
|
@ -5,6 +5,7 @@ var format = require(path.join(__dirname, '../../util/format.js'));
|
|||
module.exports = class ClientWelcome {
|
||||
getData(params, cb) {
|
||||
let query = `SELECT
|
||||
c.id clientId,
|
||||
CONCAT(w.name, ' ', w.firstName) name,
|
||||
w.phone AS phone,
|
||||
CONCAT(wu.name, '@verdnatura.es') AS email,
|
||||
|
@ -17,7 +18,7 @@ module.exports = class ClientWelcome {
|
|||
LEFT JOIN account.user wu ON wu.id = w.userFk
|
||||
JOIN country ct ON ct.id = c.countryFk
|
||||
WHERE c.id = ?`;
|
||||
database.pool.query(query, [params.recipient], (error, result) => {
|
||||
database.pool.query(query, [params.clientId], (error, result) => {
|
||||
if (error || result.length == 0)
|
||||
return cb(new Error('No template data found'));
|
||||
|
||||
|
|
|
@ -7,11 +7,9 @@
|
|||
<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 -->
|
||||
<!-- Header block -->
|
||||
{{$.header}}
|
||||
<!-- Header block end -->
|
||||
|
||||
<!-- Title block -->
|
||||
<div class="title">
|
||||
|
@ -21,108 +19,47 @@
|
|||
|
||||
<!-- 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">
|
||||
Sus datos para poder comprar en la web de verdnatura (<a href="https://www.verdnatura.es" title="Visitar Verdnatura" target="_blank" style="color:#8dba25">https://www.verdnatura.es</a>)
|
||||
o en nuestras aplicaciones para iOS (<a href="https://goo.gl/3hC2mG" title="App Store" target="_blank" style="color:#8dba25">https://goo.gl/3hC2mG</a>) y Android (<a href="https://goo.gl/8obvLc" title="Google Play" target="_blank" style="color:#8dba25">https://goo.gl/8obvLc</a>), son:
|
||||
</p>
|
||||
|
||||
<p>{{_.dear}}</p>
|
||||
<p>{{{_.bodyDescription}}}</p>
|
||||
<p>
|
||||
<div>Usuario: <strong>{{userName}}</strong></div>
|
||||
<div>Contraseña: <strong>********</strong> (Va a recibir un correo para establecer la contraseña)</div>
|
||||
<div>{{_.user}} <strong>{{userName}}</strong></div>
|
||||
<div>{{_.password}} <strong>********</strong> {{_.passwordResetText}}</div>
|
||||
</p>
|
||||
|
||||
<h1 style="color:#999">Cómo hacer un pedido</h1>
|
||||
|
||||
<p style="text-align: justify">Para realizar un pedido en nuestra web, debe configurarlo indicando:</p>
|
||||
|
||||
<h1>{{_.sectionHowToBuyTitle}}</h1>
|
||||
<p>{{_.sectionHowToBuyDescription}}</p>
|
||||
<ol>
|
||||
<li>Si quiere recibir el pedido (por agencia o por nuestro propio reparto) o si lo prefiere recoger en alguno de nuestros almacenes.</li>
|
||||
<li>La fecha en la que quiera recibir el pedido (se preparará el día anterior).</li>
|
||||
<li>La dirección de entrega o el almacén donde quiera recoger el pedido.</li>
|
||||
<li>{{_.sectionHowToBuyRequeriment1}}</li>
|
||||
<li>{{_.sectionHowToBuyRequeriment2}}</li>
|
||||
<li>{{_.sectionHowToBuyRequeriment3}}</li>
|
||||
</ol>
|
||||
|
||||
<p style="text-align: justify">En nuestra web y aplicaciones puedes visualizar el stock disponible de flor cortada, verdes, plantas, complementos y artificial.
|
||||
Tenga en cuenta que dicho stock puede variar en función de la fecha seleccionada al configurar el pedido. Es importante CONFIRMAR los pedidos para que la mercancía quede reservada.</p>
|
||||
|
||||
<p style="text-align: justify">El reparto se realiza de lunes a sábado según la zona en la que se encuentre. Por regla general, los pedidos que se entregan por agencia, deben estar confirmados y pagados antes de las 17h
|
||||
del día en que se preparan (el día anterior a recibirlos), aunque esto puede variar si el pedido se envía a través de nuestro reparto y según la zona. </p>
|
||||
|
||||
<h1 style="color:#999">Cómo pagar</h1>
|
||||
|
||||
<p style="text-align: justify">Las formas de pago admitidas en Verdnatura son</p>
|
||||
|
||||
<p>{{_.sectionHowToBuyStock}}</p>
|
||||
<p>{{_.sectionHowToBuyDelivery}}</p>
|
||||
|
||||
<h1>{{_.sectionHowToPayTitle}}</h1>
|
||||
<p>{{_.sectionHowToPayDescription}}</p>
|
||||
<ul>
|
||||
<li>Con <strong>tarjeta</strong> a través de nuestra plataforma web (al confirmar el pedido).</li>
|
||||
<li>Mediante <strong>giro bancario mensual</strong>, modalidad que hay que solicitar y tramitar.</li>
|
||||
<li>{{{_.sectionHowToPayOption1}}}</li>
|
||||
<li>{{{_.sectionHowToPayOption2}}}</li>
|
||||
</ul>
|
||||
|
||||
<h1 style="color:#999">Cosas a tener en cuenta</h1>
|
||||
|
||||
<p style="text-align: justify">Verdnatura vende EXCLUSIVAMENTE a profesionales, por lo que debe remitirnos el Modelo 036 ó 037,
|
||||
para comprobar que está dado/a de alta en el epígrafe correspondiente al comercio de flores.</p>
|
||||
|
||||
<h3 style="font-size:16px">POLÍTICA DE RECLAMACIONES</h3>
|
||||
|
||||
<p style="text-align: justify">Verdnatura aceptará las reclamaciones que se realicen dentro de los dos días naturales
|
||||
siguientes a la recepción del pedido (incluyendo el mismo día de la recepción). Pasado este plazo no se aceptará ninguna reclamación.</p>
|
||||
|
||||
<p style="text-align: justify">Cualquier duda que le surja, no dude en consultarla, <strong>¡estamos para atenderle!</strong></p>
|
||||
<h1>{{_.sectionToConsiderTitle}}</h1>
|
||||
<p>{{_.sectionToConsiderDescription}}</p>
|
||||
|
||||
<h3>{{_.sectionClaimsPolicyTitle}}</h3>
|
||||
<p>{{_.sectionClaimsPolicyDescription}}</p>
|
||||
<p>{{{_.doubtsText}}}</p>
|
||||
<p>
|
||||
{{{salesPersonName}}}
|
||||
{{{salesPersonPhone}}}
|
||||
{{{salesPersonEmail}}}
|
||||
</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 -->
|
||||
<!-- Footer block -->
|
||||
{{$.footer}}
|
||||
<!-- Footer block end -->
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -1,14 +1,28 @@
|
|||
{
|
||||
"subject": "¡Le damos la bienvenida!",
|
||||
"title": "¡LE DAMOS LA BIENVENIDA!",
|
||||
"dear": "Estimado cliente",
|
||||
"bodyDescription": "Siga las intrucciones especificadas en este correo para llevar a cabo la instalación de la impresora.",
|
||||
"dear": "Estimado cliente,",
|
||||
"bodyDescription": "Sus datos para poder comprar en la web de verdnatura (<a href=\"https://www.verdnatura.es\" title=\"Visitar Verdnatura\" target=\"_blank\">https://www.verdnatura.es</a>) o en nuestras aplicaciones para <a href=\"https://goo.gl/3hC2mG\" title=\"App Store\" target=\"_blank\">iOS</a> y <a href=\"https://goo.gl/8obvLc\" title=\"Google Play\" target=\"_blank\">Android</a> (<a href=\"https://www.youtube.com/watch?v=gGfEtFm8qkw\" target=\"_blank\"><strong>Ver tutorial de uso</strong></a>), son:",
|
||||
"user": "Usuario:",
|
||||
"password": "Contraseña:",
|
||||
"passwordResetText": "(Va a recibir un correo para establecer la contraseña)",
|
||||
"sectionHowToBuyTitle": "Cómo hacer un pedido",
|
||||
"sectionHowToBuyDescription": "Para realizar un pedido en nuestra web, debe configurarlo indicando:",
|
||||
"sectionHowToBuyRequeriment1": "Si quiere recibir el pedido (por agencia o por nuestro propio reparto) o si lo prefiere recoger en alguno de nuestros almacenes.",
|
||||
"sectionHowToBuyRequeriment2": "La fecha en la que quiera recibir el pedido (se preparará el día anterior).",
|
||||
"sectionHowToBuyRequeriment3": "La dirección de entrega o el almacén donde quiera recoger el pedido.",
|
||||
"sectionHowToBuyStock": "En nuestra web y aplicaciones puedes visualizar el stock disponible de flor cortada, verdes, plantas, complementos y artificial. Tenga en cuenta que dicho stock puede variar en función de la fecha seleccionada al configurar el pedido. Es importante CONFIRMAR los pedidos para que la mercancía quede reservada.",
|
||||
"sectionHowToBuyDelivery": "El reparto se realiza de lunes a sábado según la zona en la que se encuentre. Por regla general, los pedidos que se entregan por agencia, deben estar confirmados y pagados antes de las 17h del día en que se preparan (el día anterior a recibirlos), aunque esto puede variar si el pedido se envía a través de nuestro reparto y según la zona.",
|
||||
"sectionHowToPayTitle": "Cómo pagar",
|
||||
"sectionHowToPayDescription": "Las formas de pago admitidas en Verdnatura son:",
|
||||
"sectionHowToPayOption1": "Con <strong>tarjeta</strong> a través de nuestra plataforma web (al confirmar el pedido).",
|
||||
"sectionHowToPayOption2": "Mediante <strong>giro bancario mensual</strong>, modalidad que hay que solicitar y tramitar.",
|
||||
"sectionToConsiderTitle": "Cosas a tener en cuenta",
|
||||
"sectionToConsiderDescription": "Verdnatura vende EXCLUSIVAMENTE a profesionales, por lo que debe remitirnos el Modelo 036 ó 037, para comprobar que está dado/a de alta en el epígrafe correspondiente al comercio de flores.",
|
||||
"sectionClaimsPolicyTitle": "POLÍTICA DE RECLAMACIONES",
|
||||
"sectionClaimsPolicyDescription": "Verdnatura aceptará las reclamaciones que se realicen dentro de los dos días naturales siguientes a la recepción del pedido (incluyendo el mismo día de la recepción). Pasado este plazo no se aceptará ninguna reclamación.",
|
||||
"doubtsText": "Cualquier duda que le surja, no dude en consultarla, <strong>¡estamos para atenderle!</strong>",
|
||||
"salesPersonNameText": "Soy tu comercial y mi nombre es",
|
||||
"salesPersonPhoneText": "Teléfono y whatsapp",
|
||||
"salesPersonEmailText": "Dirección de e-mail",
|
||||
"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."
|
||||
"salesPersonEmailText": "Dirección de e-mail"
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
var path = require('path');
|
||||
var database = require(path.join(__dirname, '../../database.js'));
|
||||
var format = require(path.join(__dirname, '../../util/format.js'));
|
||||
|
||||
module.exports = class Footer {
|
||||
getData(params, cb) {
|
||||
let query = `SELECT
|
||||
socialName
|
||||
FROM client c
|
||||
JOIN country ct ON ct.id = c.countryFk
|
||||
WHERE c.id = ?`;
|
||||
database.pool.query(query, [params.clientId], (error, result) => {
|
||||
if (error || result.length == 0)
|
||||
return cb(new Error('No template data found'));
|
||||
|
||||
Object.assign(this, result[0]);
|
||||
cb();
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
<!-- 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>{{_.fiscalAddress}}</p>
|
||||
<p>{{_.privacy}}</p>
|
||||
<p>{{_.privacyLaw}}</p>
|
||||
</div>
|
||||
<!-- Privacy block end -->
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"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."
|
||||
}
|
|
@ -1,41 +1,3 @@
|
|||
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;
|
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: 8.4 KiB |
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" x="0px" y="0px" width="226.229px" height="31.038px" viewBox="0 0 226.229 31.038" enable-background="new 0 0 226.229 31.038" xml:space="preserve" id="svg2" inkscape:version="0.48.1 r9760" sodipodi:docname="logo.svg"><metadata id="metadata61"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata><defs id="defs59"/><sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1366" inkscape:window-height="710" id="namedview57" showgrid="false" inkscape:zoom="4.0755163" inkscape:cx="138.56745" inkscape:cy="16.509992" inkscape:window-x="0" inkscape:window-y="26" inkscape:window-maximized="1" inkscape:current-layer="svg2"/>
|
||||
<g id="Background">
|
||||
</g>
|
||||
<g id="Guides">
|
||||
</g>
|
||||
<g id="Foreground">
|
||||
<g id="g7">
|
||||
<g id="g9">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.417,30.321L0,0h8.233l4.26,15.582l0.349,1.276 c0.521,1.866,0.918,3.431,1.191,4.693c0.15-0.618,0.335-1.345,0.555-2.182c0.219-0.837,0.528-1.935,0.925-3.293L19.981,0h8.19 L17.671,30.321H10.417z" id="path11"/>
|
||||
</g>
|
||||
<g id="g13">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M139.809,19.787c-0.665,0.357-1.748,0.686-3.25,0.988 c-0.727,0.137-1.283,0.254-1.667,0.35c-0.95,0.247-1.661,0.563-2.134,0.947c-0.472,0.384-0.799,0.899-0.979,1.544 c-0.223,0.796-0.155,1.438,0.204,1.925c0.359,0.488,0.945,0.731,1.757,0.731c1.252,0,2.375-0.36,3.369-1.081 c0.994-0.721,1.653-1.665,1.98-2.831L139.809,19.787z M144.915,30.321h-7.458c0.017-0.356,0.048-0.726,0.094-1.11l0.159-1.192 c-1.318,1.026-2.627,1.786-3.927,2.279c-1.299,0.493-2.643,0.739-4.031,0.739c-2.158,0-3.7-0.593-4.625-1.779 c-0.925-1.187-1.106-2.788-0.542-4.804c0.519-1.851,1.431-3.356,2.737-4.515c1.307-1.159,3.021-1.972,5.142-2.438 c1.169-0.247,2.641-0.515,4.413-0.803c2.646-0.412,4.082-1.016,4.304-1.812l0.151-0.539c0.182-0.65,0.076-1.145-0.317-1.483 c-0.393-0.339-1.071-0.508-2.033-0.508c-1.045,0-1.934,0.214-2.666,0.643c-0.731,0.428-1.289,1.058-1.673,1.887h-6.748 c1.065-2.53,2.64-4.413,4.723-5.65s4.724-1.856,7.923-1.856c1.991,0,3.602,0.241,4.833,0.722s2.095,1.209,2.59,2.185 c0.339,0.701,0.483,1.536,0.432,2.504c-0.052,0.969-0.377,2.525-0.978,4.669l-2.375,8.483c-0.284,1.014-0.416,1.812-0.396,2.395 s0.188,0.962,0.503,1.141L144.915,30.321z" id="path15" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g17">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M185.7,30.321l6.27-22.393h7.049l-1.097,3.918 c1.213-1.537,2.502-2.659,3.867-3.366c1.365-0.707,2.951-1.074,4.758-1.101l-2.03,7.25c-0.304-0.042-0.608-0.072-0.912-0.093 c-0.303-0.02-0.592-0.03-0.867-0.03c-1.126,0-2.104,0.168-2.932,0.504c-0.829,0.336-1.561,0.854-2.197,1.555 c-0.406,0.467-0.789,1.136-1.149,2.007c-0.361,0.872-0.814,2.282-1.359,4.232l-2.104,7.516H185.7z" id="path19" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g21">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M217.631,19.787c-0.664,0.357-1.748,0.686-3.25,0.988 c-0.727,0.137-1.282,0.254-1.667,0.35c-0.95,0.247-1.661,0.563-2.134,0.947c-0.472,0.384-0.799,0.899-0.979,1.544 c-0.223,0.796-0.155,1.438,0.205,1.925c0.359,0.488,0.945,0.731,1.757,0.731c1.252,0,2.375-0.36,3.369-1.081 c0.994-0.721,1.654-1.665,1.98-2.831L217.631,19.787z M222.737,30.321h-7.458c0.017-0.356,0.048-0.726,0.094-1.11l0.159-1.192 c-1.318,1.026-2.627,1.786-3.927,2.279c-1.299,0.493-2.643,0.739-4.031,0.739c-2.158,0-3.7-0.593-4.625-1.779 c-0.926-1.187-1.106-2.788-0.542-4.804c0.519-1.851,1.431-3.356,2.737-4.515c1.306-1.159,3.02-1.972,5.142-2.438 c1.169-0.247,2.641-0.515,4.413-0.803c2.647-0.412,4.082-1.016,4.304-1.812l0.151-0.539c0.182-0.65,0.077-1.145-0.317-1.483 c-0.393-0.339-1.071-0.508-2.033-0.508c-1.045,0-1.934,0.214-2.666,0.643c-0.731,0.428-1.289,1.058-1.672,1.887h-6.748 c1.065-2.53,2.64-4.413,4.723-5.65s4.724-1.856,7.923-1.856c1.99,0,3.601,0.241,4.833,0.722s2.095,1.209,2.591,2.185 c0.339,0.701,0.483,1.536,0.431,2.504c-0.051,0.969-0.377,2.525-0.978,4.669l-2.375,8.483c-0.284,1.014-0.416,1.812-0.396,2.395 c0.02,0.583,0.188,0.962,0.503,1.141L222.737,30.321z" id="path23" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g25">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M188.386,7.928l-6.269,22.393h-7.174l0.864-3.085 c-1.227,1.246-2.476,2.163-3.746,2.751s-2.625,0.882-4.067,0.882c-2.471,0-4.154-0.634-5.048-1.901 c-0.895-1.268-0.993-3.149-0.294-5.644l4.31-15.396h7.338l-3.508,12.53c-0.516,1.842-0.641,3.109-0.375,3.803 s0.967,1.041,2.105,1.041c1.275,0,2.323-0.422,3.142-1.267c0.819-0.845,1.497-2.223,2.031-4.133l3.353-11.974H188.386z" id="path27" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g29">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M149.937,12.356l1.239-4.428h2.995l1.771-6.326h7.338 l-1.771,6.326h3.753l-1.24,4.428h-3.753l-2.716,9.702c-0.416,1.483-0.498,2.465-0.247,2.946c0.25,0.48,0.905,0.721,1.964,0.721 l0.549-0.011l0.39-0.031l-1.31,4.678c-0.811,0.148-1.596,0.263-2.354,0.344c-0.758,0.081-1.48,0.122-2.167,0.122 c-2.543,0-4.108-0.621-4.695-1.863c-0.587-1.242-0.313-3.887,0.82-7.936l2.428-8.672H149.937z" id="path31" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g33">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M73.875,18.896c-0.561,2.004-0.616,3.537-0.167,4.601 s1.375,1.595,2.774,1.595c1.399,0,2.605-0.524,3.62-1.574s1.806-2.59,2.375-4.622c0.526-1.879,0.556-3.334,0.09-4.363 c-0.466-1.029-1.393-1.543-2.778-1.543c-1.304,0-2.487,0.528-3.551,1.585S74.386,17.071,73.875,18.896z M96.513,0l-8.489,30.321 h-7.337l0.824-2.944c-1.166,1.22-2.369,2.121-3.61,2.703s-2.583,0.874-4.025,0.874c-2.802,0-4.772-1.081-5.912-3.243 c-1.139-2.162-1.218-4.993-0.238-8.493c0.988-3.528,2.668-6.404,5.042-8.627c2.374-2.224,4.927-3.336,7.661-3.336 c1.47,0,2.695,0.296,3.676,0.887c0.981,0.591,1.681,1.465,2.099,2.62L89.217,0H96.513z" id="path35"/>
|
||||
<g id="g37">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M73.875,18.896c-0.561,2.004-0.616,3.537-0.167,4.601s1.375,1.595,2.774,1.595 c1.399,0,2.605-0.524,3.62-1.574s1.806-2.59,2.375-4.622c0.526-1.879,0.556-3.334,0.09-4.363 c-0.466-1.029-1.393-1.543-2.778-1.543c-1.304,0-2.487,0.528-3.551,1.585S74.386,17.071,73.875,18.896z M96.513,0l-8.489,30.321 h-7.337l0.824-2.944c-1.166,1.22-2.369,2.121-3.61,2.703s-2.583,0.874-4.025,0.874c-2.802,0-4.772-1.081-5.912-3.243 c-1.139-2.162-1.218-4.993-0.238-8.493c0.988-3.528,2.668-6.404,5.042-8.627c2.374-2.224,4.927-3.336,7.661-3.336 c1.47,0,2.695,0.296,3.676,0.887c0.981,0.591,1.681,1.465,2.099,2.62L89.217,0H96.513z" id="path39"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="g41">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M46.488,30.321l6.269-22.393h7.049l-1.098,3.918 c1.213-1.537,2.502-2.659,3.868-3.366s6.015-1.074,7.822-1.101l-2.03,7.25c-0.304-0.042-0.608-0.072-0.911-0.093 c-0.304-0.02-0.592-0.03-0.867-0.03c-1.126,0-5.167,0.168-5.997,0.504c-0.829,0.336-1.561,0.854-2.196,1.555 c-0.406,0.467-0.789,1.136-1.149,2.007c-0.361,0.872-0.814,2.282-1.36,4.232l-2.104,7.516H46.488z" id="path43"/>
|
||||
</g>
|
||||
<g id="g45">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M32.673,16.742l8.351-0.021 c0.375-1.436,0.308-2.558-0.201-3.365s-1.402-1.211-2.68-1.211c-1.209,0-2.285,0.397-3.229,1.19S33.224,15.265,32.673,16.742z M38.817,23.278h7.043c-1.347,2.456-3.172,4.356-5.477,5.7c-2.305,1.345-4.885,2.017-7.74,2.017 c-3.473,0-5.923-1.054-7.351-3.161c-1.427-2.107-1.632-4.98-0.613-8.618c1.038-3.707,2.875-6.641,5.512-8.803 c2.637-2.163,5.678-3.244,9.123-3.244c3.555,0,6.04,1.099,7.456,3.298c1.417,2.198,1.582,5.234,0.498,9.109l-0.239,0.814 l-0.167,0.484H31.721c-0.441,1.575-0.438,2.777,0.01,3.606c0.448,0.829,1.332,1.244,2.65,1.244c0.975,0,1.836-0.206,2.583-0.617 S38.33,24.086,38.817,23.278z" id="path47"/>
|
||||
<g id="g49">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M32.673,16.742l8.351-0.021c0.375-1.436,0.308-2.558-0.201-3.365 s-1.402-1.211-2.68-1.211c-1.209,0-2.285,0.397-3.229,1.19S33.224,15.265,32.673,16.742z M38.817,23.278h7.043 c-1.347,2.456-3.172,4.356-5.477,5.7c-2.305,1.345-4.885,2.017-7.74,2.017c-3.473,0-5.923-1.054-7.351-3.161 c-1.427-2.107-1.632-4.98-0.613-8.618c1.038-3.707,2.875-6.641,5.512-8.803c2.637-2.163,5.678-3.244,9.123-3.244 c3.555,0,6.04,1.099,7.456,3.298c1.417,2.198,1.582,5.234,0.498,9.109l-0.239,0.814l-0.167,0.484H31.721 c-0.441,1.575-0.438,2.777,0.01,3.606c0.448,0.829,1.332,1.244,2.65,1.244c0.975,0,1.836-0.206,2.583-0.617 S38.33,24.086,38.817,23.278z" id="path51"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="g53">
|
||||
<path fill="#A0CE67" d="M112.881,30.643l-6.404-18.639l-6.455,18.639h-7.254l9.565-30.321h8.19l4.434,15.582l0.35,1.276 c0.521,1.866,0.917,3.431,1.191,4.693l0.555-2.182c0.219-0.837,0.528-1.935,0.925-3.293l4.468-16.076h8.19l-10.501,30.321 H112.881z" id="path55" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 9.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,20 @@
|
|||
var path = require('path');
|
||||
var database = require(path.join(__dirname, '../../database.js'));
|
||||
var format = require(path.join(__dirname, '../../util/format.js'));
|
||||
|
||||
module.exports = class Header {
|
||||
getData(params, cb) {
|
||||
let query = `SELECT
|
||||
c.name AS clientName
|
||||
FROM client c
|
||||
JOIN country ct ON ct.id = c.countryFk
|
||||
WHERE c.id = ?`;
|
||||
database.pool.query(query, [params.clientId], (error, result) => {
|
||||
if (error || result.length == 0)
|
||||
return cb(new Error('No template data found'));
|
||||
|
||||
Object.assign(this, result[0]);
|
||||
cb();
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
<div>
|
||||
<a href="https://www.verdnatura.es"/><img src="cid:header.png" alt="VerdNatura"/></a>
|
||||
</div>
|
|
@ -0,0 +1,2 @@
|
|||
{
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
.banner img {
|
||||
width: 100%
|
||||
}
|
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: 8.4 KiB |
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" x="0px" y="0px" width="226.229px" height="31.038px" viewBox="0 0 226.229 31.038" enable-background="new 0 0 226.229 31.038" xml:space="preserve" id="svg2" inkscape:version="0.48.1 r9760" sodipodi:docname="logo.svg"><metadata id="metadata61"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata><defs id="defs59"/><sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1366" inkscape:window-height="710" id="namedview57" showgrid="false" inkscape:zoom="4.0755163" inkscape:cx="138.56745" inkscape:cy="16.509992" inkscape:window-x="0" inkscape:window-y="26" inkscape:window-maximized="1" inkscape:current-layer="svg2"/>
|
||||
<g id="Background">
|
||||
</g>
|
||||
<g id="Guides">
|
||||
</g>
|
||||
<g id="Foreground">
|
||||
<g id="g7">
|
||||
<g id="g9">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.417,30.321L0,0h8.233l4.26,15.582l0.349,1.276 c0.521,1.866,0.918,3.431,1.191,4.693c0.15-0.618,0.335-1.345,0.555-2.182c0.219-0.837,0.528-1.935,0.925-3.293L19.981,0h8.19 L17.671,30.321H10.417z" id="path11"/>
|
||||
</g>
|
||||
<g id="g13">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M139.809,19.787c-0.665,0.357-1.748,0.686-3.25,0.988 c-0.727,0.137-1.283,0.254-1.667,0.35c-0.95,0.247-1.661,0.563-2.134,0.947c-0.472,0.384-0.799,0.899-0.979,1.544 c-0.223,0.796-0.155,1.438,0.204,1.925c0.359,0.488,0.945,0.731,1.757,0.731c1.252,0,2.375-0.36,3.369-1.081 c0.994-0.721,1.653-1.665,1.98-2.831L139.809,19.787z M144.915,30.321h-7.458c0.017-0.356,0.048-0.726,0.094-1.11l0.159-1.192 c-1.318,1.026-2.627,1.786-3.927,2.279c-1.299,0.493-2.643,0.739-4.031,0.739c-2.158,0-3.7-0.593-4.625-1.779 c-0.925-1.187-1.106-2.788-0.542-4.804c0.519-1.851,1.431-3.356,2.737-4.515c1.307-1.159,3.021-1.972,5.142-2.438 c1.169-0.247,2.641-0.515,4.413-0.803c2.646-0.412,4.082-1.016,4.304-1.812l0.151-0.539c0.182-0.65,0.076-1.145-0.317-1.483 c-0.393-0.339-1.071-0.508-2.033-0.508c-1.045,0-1.934,0.214-2.666,0.643c-0.731,0.428-1.289,1.058-1.673,1.887h-6.748 c1.065-2.53,2.64-4.413,4.723-5.65s4.724-1.856,7.923-1.856c1.991,0,3.602,0.241,4.833,0.722s2.095,1.209,2.59,2.185 c0.339,0.701,0.483,1.536,0.432,2.504c-0.052,0.969-0.377,2.525-0.978,4.669l-2.375,8.483c-0.284,1.014-0.416,1.812-0.396,2.395 s0.188,0.962,0.503,1.141L144.915,30.321z" id="path15" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g17">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M185.7,30.321l6.27-22.393h7.049l-1.097,3.918 c1.213-1.537,2.502-2.659,3.867-3.366c1.365-0.707,2.951-1.074,4.758-1.101l-2.03,7.25c-0.304-0.042-0.608-0.072-0.912-0.093 c-0.303-0.02-0.592-0.03-0.867-0.03c-1.126,0-2.104,0.168-2.932,0.504c-0.829,0.336-1.561,0.854-2.197,1.555 c-0.406,0.467-0.789,1.136-1.149,2.007c-0.361,0.872-0.814,2.282-1.359,4.232l-2.104,7.516H185.7z" id="path19" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g21">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M217.631,19.787c-0.664,0.357-1.748,0.686-3.25,0.988 c-0.727,0.137-1.282,0.254-1.667,0.35c-0.95,0.247-1.661,0.563-2.134,0.947c-0.472,0.384-0.799,0.899-0.979,1.544 c-0.223,0.796-0.155,1.438,0.205,1.925c0.359,0.488,0.945,0.731,1.757,0.731c1.252,0,2.375-0.36,3.369-1.081 c0.994-0.721,1.654-1.665,1.98-2.831L217.631,19.787z M222.737,30.321h-7.458c0.017-0.356,0.048-0.726,0.094-1.11l0.159-1.192 c-1.318,1.026-2.627,1.786-3.927,2.279c-1.299,0.493-2.643,0.739-4.031,0.739c-2.158,0-3.7-0.593-4.625-1.779 c-0.926-1.187-1.106-2.788-0.542-4.804c0.519-1.851,1.431-3.356,2.737-4.515c1.306-1.159,3.02-1.972,5.142-2.438 c1.169-0.247,2.641-0.515,4.413-0.803c2.647-0.412,4.082-1.016,4.304-1.812l0.151-0.539c0.182-0.65,0.077-1.145-0.317-1.483 c-0.393-0.339-1.071-0.508-2.033-0.508c-1.045,0-1.934,0.214-2.666,0.643c-0.731,0.428-1.289,1.058-1.672,1.887h-6.748 c1.065-2.53,2.64-4.413,4.723-5.65s4.724-1.856,7.923-1.856c1.99,0,3.601,0.241,4.833,0.722s2.095,1.209,2.591,2.185 c0.339,0.701,0.483,1.536,0.431,2.504c-0.051,0.969-0.377,2.525-0.978,4.669l-2.375,8.483c-0.284,1.014-0.416,1.812-0.396,2.395 c0.02,0.583,0.188,0.962,0.503,1.141L222.737,30.321z" id="path23" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g25">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M188.386,7.928l-6.269,22.393h-7.174l0.864-3.085 c-1.227,1.246-2.476,2.163-3.746,2.751s-2.625,0.882-4.067,0.882c-2.471,0-4.154-0.634-5.048-1.901 c-0.895-1.268-0.993-3.149-0.294-5.644l4.31-15.396h7.338l-3.508,12.53c-0.516,1.842-0.641,3.109-0.375,3.803 s0.967,1.041,2.105,1.041c1.275,0,2.323-0.422,3.142-1.267c0.819-0.845,1.497-2.223,2.031-4.133l3.353-11.974H188.386z" id="path27" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g29">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#A0CE67" d="M149.937,12.356l1.239-4.428h2.995l1.771-6.326h7.338 l-1.771,6.326h3.753l-1.24,4.428h-3.753l-2.716,9.702c-0.416,1.483-0.498,2.465-0.247,2.946c0.25,0.48,0.905,0.721,1.964,0.721 l0.549-0.011l0.39-0.031l-1.31,4.678c-0.811,0.148-1.596,0.263-2.354,0.344c-0.758,0.081-1.48,0.122-2.167,0.122 c-2.543,0-4.108-0.621-4.695-1.863c-0.587-1.242-0.313-3.887,0.82-7.936l2.428-8.672H149.937z" id="path31" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
<g id="g33">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M73.875,18.896c-0.561,2.004-0.616,3.537-0.167,4.601 s1.375,1.595,2.774,1.595c1.399,0,2.605-0.524,3.62-1.574s1.806-2.59,2.375-4.622c0.526-1.879,0.556-3.334,0.09-4.363 c-0.466-1.029-1.393-1.543-2.778-1.543c-1.304,0-2.487,0.528-3.551,1.585S74.386,17.071,73.875,18.896z M96.513,0l-8.489,30.321 h-7.337l0.824-2.944c-1.166,1.22-2.369,2.121-3.61,2.703s-2.583,0.874-4.025,0.874c-2.802,0-4.772-1.081-5.912-3.243 c-1.139-2.162-1.218-4.993-0.238-8.493c0.988-3.528,2.668-6.404,5.042-8.627c2.374-2.224,4.927-3.336,7.661-3.336 c1.47,0,2.695,0.296,3.676,0.887c0.981,0.591,1.681,1.465,2.099,2.62L89.217,0H96.513z" id="path35"/>
|
||||
<g id="g37">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M73.875,18.896c-0.561,2.004-0.616,3.537-0.167,4.601s1.375,1.595,2.774,1.595 c1.399,0,2.605-0.524,3.62-1.574s1.806-2.59,2.375-4.622c0.526-1.879,0.556-3.334,0.09-4.363 c-0.466-1.029-1.393-1.543-2.778-1.543c-1.304,0-2.487,0.528-3.551,1.585S74.386,17.071,73.875,18.896z M96.513,0l-8.489,30.321 h-7.337l0.824-2.944c-1.166,1.22-2.369,2.121-3.61,2.703s-2.583,0.874-4.025,0.874c-2.802,0-4.772-1.081-5.912-3.243 c-1.139-2.162-1.218-4.993-0.238-8.493c0.988-3.528,2.668-6.404,5.042-8.627c2.374-2.224,4.927-3.336,7.661-3.336 c1.47,0,2.695,0.296,3.676,0.887c0.981,0.591,1.681,1.465,2.099,2.62L89.217,0H96.513z" id="path39"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="g41">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M46.488,30.321l6.269-22.393h7.049l-1.098,3.918 c1.213-1.537,2.502-2.659,3.868-3.366s6.015-1.074,7.822-1.101l-2.03,7.25c-0.304-0.042-0.608-0.072-0.911-0.093 c-0.304-0.02-0.592-0.03-0.867-0.03c-1.126,0-5.167,0.168-5.997,0.504c-0.829,0.336-1.561,0.854-2.196,1.555 c-0.406,0.467-0.789,1.136-1.149,2.007c-0.361,0.872-0.814,2.282-1.36,4.232l-2.104,7.516H46.488z" id="path43"/>
|
||||
</g>
|
||||
<g id="g45">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M32.673,16.742l8.351-0.021 c0.375-1.436,0.308-2.558-0.201-3.365s-1.402-1.211-2.68-1.211c-1.209,0-2.285,0.397-3.229,1.19S33.224,15.265,32.673,16.742z M38.817,23.278h7.043c-1.347,2.456-3.172,4.356-5.477,5.7c-2.305,1.345-4.885,2.017-7.74,2.017 c-3.473,0-5.923-1.054-7.351-3.161c-1.427-2.107-1.632-4.98-0.613-8.618c1.038-3.707,2.875-6.641,5.512-8.803 c2.637-2.163,5.678-3.244,9.123-3.244c3.555,0,6.04,1.099,7.456,3.298c1.417,2.198,1.582,5.234,0.498,9.109l-0.239,0.814 l-0.167,0.484H31.721c-0.441,1.575-0.438,2.777,0.01,3.606c0.448,0.829,1.332,1.244,2.65,1.244c0.975,0,1.836-0.206,2.583-0.617 S38.33,24.086,38.817,23.278z" id="path47"/>
|
||||
<g id="g49">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M32.673,16.742l8.351-0.021c0.375-1.436,0.308-2.558-0.201-3.365 s-1.402-1.211-2.68-1.211c-1.209,0-2.285,0.397-3.229,1.19S33.224,15.265,32.673,16.742z M38.817,23.278h7.043 c-1.347,2.456-3.172,4.356-5.477,5.7c-2.305,1.345-4.885,2.017-7.74,2.017c-3.473,0-5.923-1.054-7.351-3.161 c-1.427-2.107-1.632-4.98-0.613-8.618c1.038-3.707,2.875-6.641,5.512-8.803c2.637-2.163,5.678-3.244,9.123-3.244 c3.555,0,6.04,1.099,7.456,3.298c1.417,2.198,1.582,5.234,0.498,9.109l-0.239,0.814l-0.167,0.484H31.721 c-0.441,1.575-0.438,2.777,0.01,3.606c0.448,0.829,1.332,1.244,2.65,1.244c0.975,0,1.836-0.206,2.583-0.617 S38.33,24.086,38.817,23.278z" id="path51"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="g53">
|
||||
<path fill="#A0CE67" d="M112.881,30.643l-6.404-18.639l-6.455,18.639h-7.254l9.565-30.321h8.19l4.434,15.582l0.35,1.276 c0.521,1.866,0.917,3.431,1.191,4.693l0.555-2.182c0.219-0.837,0.528-1.935,0.925-3.293l4.468-16.076h8.19l-10.501,30.321 H112.881z" id="path55" style="fill:#8ed300;fill-opacity:1"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 9.5 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.4 KiB |
|
@ -5,70 +5,29 @@
|
|||
<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 -->
|
||||
<div class="wrapper">
|
||||
<div class="container">
|
||||
<!-- Header block -->
|
||||
{{$.header}}
|
||||
<!-- Header 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 -->
|
||||
<!-- Title block -->
|
||||
<div class="title">
|
||||
<h1>{{_.title}}</h1>
|
||||
</div>
|
||||
<!-- Title block end -->
|
||||
|
||||
<!-- Mail body block -->
|
||||
<div style="padding: 20px 0">
|
||||
<p style="text-align: justify">{{_.hello}}, <strong>#{{alias}}</strong></p>
|
||||
<p style="text-align: justify;font-size: 22px">{{message}}<p>
|
||||
</div>
|
||||
<!-- Mail body block end -->
|
||||
<!-- Mail body block -->
|
||||
<div class="body">
|
||||
<p>{{_.hello}} <strong>#{{alias}}</strong></p>
|
||||
<p>{{message}}</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>
|
||||
<!-- Footer block -->
|
||||
{{$.footer}}
|
||||
<!-- Footer block end -->
|
||||
</div>
|
||||
</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>
|