Merge branch 'dev' of http://git.verdnatura.es/salix into dev
|
@ -1,5 +1,5 @@
|
|||
import ngModule from '../module';
|
||||
import './style.scss';
|
||||
|
||||
export default class Controller {
|
||||
constructor() {
|
||||
this.client = null;
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
vn-main-block {
|
||||
display:block;
|
||||
max-width: 1920px;
|
||||
width:100%;
|
||||
margin: 0 auto;
|
||||
|
||||
.left-block {
|
||||
min-width: 18em;
|
||||
padding-left: 1em;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ export default class App {
|
|||
this.$rootScope = $rootScope;
|
||||
}
|
||||
show(message) {
|
||||
if (this.snackbar) this.snackbar.show({message: message});
|
||||
if (this.snackbar) this.snackbar.show({message: message, timeout: 400});
|
||||
}
|
||||
showMessage(message) {
|
||||
this.show(message);
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import {module} from '../module';
|
||||
|
||||
const isFullEmpty = item => {
|
||||
return (!item && item !== 0) || (typeof item === 'object' && !Object.keys(item).length);
|
||||
};
|
||||
|
||||
export default isFullEmpty;
|
||||
export const NAME = 'isFullEmpty';
|
||||
module.value(NAME, isFullEmpty);
|
|
@ -7,13 +7,18 @@ vn-textfield {
|
|||
width: auto;
|
||||
top: 0px;
|
||||
right: -6px;
|
||||
margin: 22px 0px;
|
||||
background: transparent;
|
||||
margin: 21px 0px;
|
||||
background: white;
|
||||
opacity: 1;
|
||||
z-index: 9999;
|
||||
color: #aaa;
|
||||
}
|
||||
.material-icons {
|
||||
font-size: 18px;
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.material-icons:hover {
|
||||
color: rgba(0,0,0, .87);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ import Component from '../lib/component';
|
|||
import getModifiedData from '../lib/modified';
|
||||
import copyObject from '../lib/copy';
|
||||
import isEqual from '../lib/equals';
|
||||
import isFullEmpty from '../lib/fullEmpty';
|
||||
|
||||
/**
|
||||
* Component that checks for changes on a specific model property and
|
||||
|
@ -95,7 +96,7 @@ export default class Watcher extends Component {
|
|||
let changedData = getModifiedData(this.data, this.orgData);
|
||||
|
||||
if (this.save) {
|
||||
this.save.model = changedData;
|
||||
this.save.model = this.copyInNewObject(changedData);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.save.accept().then(
|
||||
json => this.writeData({data: json}, resolve),
|
||||
|
@ -154,7 +155,7 @@ export default class Watcher extends Component {
|
|||
if (data && typeof data === 'object') {
|
||||
Object.keys(data).forEach(
|
||||
val => {
|
||||
if (data[val] !== "" && data[val] !== undefined && data[val] !== null) {
|
||||
if (!isFullEmpty(data[val])) {
|
||||
if (typeof data[val] === 'object') {
|
||||
newCopy[val] = this.copyInNewObject(data[val]);
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './src/item';
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"module": "item",
|
||||
"name": "Items",
|
||||
"icon": "/static/images/icon_item.png",
|
||||
"routes": [
|
||||
{
|
||||
"url": "/item",
|
||||
"state": "item",
|
||||
"abstract": true,
|
||||
"component": "ui-view"
|
||||
},
|
||||
{
|
||||
"url": "/list",
|
||||
"state": "item.index",
|
||||
"component": "vn-item-list"
|
||||
}, {
|
||||
"url": "/create",
|
||||
"state": "item.create",
|
||||
"component": "vn-item-create"
|
||||
}, {
|
||||
"url": "/:id",
|
||||
"state": "item.card",
|
||||
"abstract": true,
|
||||
"component": "vn-item-card"
|
||||
}, {
|
||||
"url" : "/data",
|
||||
"state": "item.card.data",
|
||||
"component": "vn-item-data",
|
||||
"params": {
|
||||
"item": "$ctrl.item"
|
||||
},
|
||||
"menu": {
|
||||
"description": "Basic data",
|
||||
"icon": "folder"
|
||||
}
|
||||
}, {
|
||||
"url" : "/image",
|
||||
"state": "item.card.image",
|
||||
"component": "vn-item-image",
|
||||
"params": {
|
||||
"item": "$ctrl.item"
|
||||
},
|
||||
"menu": {
|
||||
"description": "Images",
|
||||
"icon": "image"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<vn-main-block>
|
||||
<vn-horizontal>
|
||||
<vn-auto class="left-block">
|
||||
<vn-card margin-medium-v>
|
||||
<a class="item-product-link pad-large text-center" ui-sref="item.index">
|
||||
<b>{{$ctrl.item.name}}</b>
|
||||
<img ng-src="http://verdnatura.es/vn-image-data/catalog/200x200/{{$ctrl.item.image}}" />
|
||||
</a>
|
||||
</vn-card>
|
||||
<vn-left-menu></vn-left-menu>
|
||||
</vn-auto>
|
||||
<vn-one>
|
||||
<vn-vertical margin-medium ui-view></vn-vertical>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-main-block>
|
|
@ -0,0 +1,32 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class ItemCard {
|
||||
constructor($http, $state) {
|
||||
this.$http = $http;
|
||||
this.$state = $state;
|
||||
this.item = {};
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
let filter = {
|
||||
include: [
|
||||
{relation: "itemType"},
|
||||
{relation: "origin"},
|
||||
{relation: "ink"},
|
||||
{relation: "producer"},
|
||||
{relation: "intrastat"}
|
||||
]
|
||||
};
|
||||
this.$http.get(`/item/api/Items/${this.$state.params.id}?filter=${JSON.stringify(filter)}`).then(
|
||||
res => {
|
||||
this.item = res.data;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
ItemCard.$inject = ['$http', '$state'];
|
||||
|
||||
ngModule.component('vnItemCard', {
|
||||
template: require('./item-card.html'),
|
||||
controller: ItemCard
|
||||
});
|
|
@ -0,0 +1,66 @@
|
|||
<mg-ajax path="/item/api/Items" options="vnPost"></mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.item"
|
||||
form="form"
|
||||
save="post">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()" margin-medium>
|
||||
<div style="max-width: 70em; margin: 0 auto;">
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Create item</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Size" field="$ctrl.item.size" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-five label="Category" field="$ctrl.item.category"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Stems" field="$ctrl.item.stems"></vn-textfield>
|
||||
<vn-textfield vn-five label="Description" field="$ctrl.item.description"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/ItemTypes"
|
||||
label="Type"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.item.typeFk"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Inks"
|
||||
label="Ink"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.item.inkFk"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Origins"
|
||||
label="Origin"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.item.originFk"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Producers"
|
||||
label="Producer"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.item.producerFk"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Create"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,18 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class ItemCreate {
|
||||
constructor() {
|
||||
this.item = {};
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.$.watcher.submit().then(
|
||||
json => this.$state.go('item.card.basic', {id: json.data.id})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnItemCreate', {
|
||||
template: require('./item-create.html'),
|
||||
controller: ItemCreate
|
||||
});
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
<mg-ajax
|
||||
path="/item/api/Items/{{patch.params.id}}"
|
||||
options="vnPatch"
|
||||
override="{filter: {include: [{relation: 'itemType'}, {relation: 'origin'}, {relation: 'ink'}, {relation: 'producer'}]}}"
|
||||
>
|
||||
</mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.item"
|
||||
form="form"
|
||||
save="patch">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="watcher.submit()" ng-cloak>
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Basic data</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-three label="Name" field="$ctrl.item.name" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Size" field="$ctrl.item.size"></vn-textfield>
|
||||
<vn-textfield vn-one label="Stems" field="$ctrl.item.stems"></vn-textfield>
|
||||
<vn-textfield vn-one label="Category" field="$ctrl.item.category"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Description" field="$ctrl.item.description"></vn-textfield>
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Intrastats"
|
||||
label="Intrastat"
|
||||
show-field="description"
|
||||
value-field="id"
|
||||
field="$ctrl.item.intrastatFk"
|
||||
initial-data="$ctrl.item.intrastat"
|
||||
order = "description DESC"
|
||||
filter-search="{where: {description: {regexp: 'search'}}}"
|
||||
>
|
||||
<tpl-item>{{$parent.$parent.item.description}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/ItemTypes"
|
||||
label="Type"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.item.typeFk"
|
||||
initial-data="$ctrl.item.itemType"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Inks"
|
||||
label="Ink"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.item.inkFk"
|
||||
initial-data="$ctrl.item.ink"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Origins"
|
||||
label="Origin"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.item.originFk"
|
||||
initial-data="$ctrl.item.origin"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Producers"
|
||||
label="Producer"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.item.producer"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
</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('vnItemData', {
|
||||
template: require('./item-data.html'),
|
||||
bindings: {
|
||||
item: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,58 @@
|
|||
<div pad-large style="min-width: 30em">
|
||||
<form ng-submit="$ctrl.onSearch()">
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Id" model="$ctrl.filter.id" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-three label="Description" model="$ctrl.filter.description"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Category" type="number" model="$ctrl.filter.category"></vn-textfield>
|
||||
<vn-textfield vn-one label="Size" type="number" model="$ctrl.filter.itemSize"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/ItemTypes"
|
||||
label="Type"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.filter.typeFk"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Inks"
|
||||
label="Ink"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.filter.inkFk"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Origins"
|
||||
label="Origin"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.filter.originFk"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Producers"
|
||||
label="Producer"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
field="$ctrl.filter.producerFk"
|
||||
>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
|
||||
|
||||
<vn-horizontal margin-large-top>
|
||||
<vn-submit label="Search"></vn-submit>
|
||||
</vn-horizontal>
|
||||
</form>
|
||||
</div>
|
|
@ -0,0 +1,16 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class ItemFilterPanel {
|
||||
constructor() {
|
||||
this.onSubmit = () => {};
|
||||
}
|
||||
|
||||
onSearch() {
|
||||
this.onSubmit(this.filter);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnItemFilterPanel', {
|
||||
template: require('./filter-panel.html'),
|
||||
controller: ItemFilterPanel
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Ink": "Tinta",
|
||||
"Origin": "Origen",
|
||||
"Producer": "Productor"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
export * from './module';
|
||||
|
||||
import './list/list';
|
||||
import './filter-panel/filter-panel';
|
||||
import './create/item-create';
|
||||
import './card/item-card';
|
||||
import './data/item-data';
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
<vn-horizontal pad-medium border-solid-bottom>
|
||||
<vn-auto margin-medium-right ng-if="$ctrl.item.image">
|
||||
<img ng-src="http://verdnatura.es/vn-image-data/catalog/200x200/{{$ctrl.item.image}}" />
|
||||
</vn-auto>
|
||||
<vn-one>
|
||||
<div><span translate>Id</span>: <b>{{$ctrl.item.id}}</b></div>
|
||||
<div><span translate>Name</span>: <b>{{$ctrl.item.name}}</b></div>
|
||||
<div><span translate>Description</span>: <b>{{$ctrl.item.description}}</b></div>
|
||||
<div><span translate>Size</span>: <b>{{$ctrl.item.size}}</b></div>
|
||||
<div><span translate>Type</span>: <b>{{$ctrl.item.itemType.name}}</b></div>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
ngModule.component('vnItemProduct', {
|
||||
template: require('./item-product.html'),
|
||||
bindings: {
|
||||
item: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
<mg-ajax path="/item/api/Items/filter" options="mgIndex"></mg-ajax>
|
||||
<div margin-medium>
|
||||
<div style="max-width: 40em; margin: 0 auto;">
|
||||
<vn-card>
|
||||
<vn-horizontal pad-medium>
|
||||
<vn-searchbar vn-one
|
||||
index="index"
|
||||
on-search="$ctrl.search(index)"
|
||||
advanced="true"
|
||||
popover="vn-item-filter-panel"
|
||||
ignore-keys = "['page', 'size', 'search']"
|
||||
>
|
||||
</vn-searchbar>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-card margin-medium-top>
|
||||
<a class="item-product-link" ng-repeat="item in index.model.instances" ui-sref="item.card.data({ id: {{item.id}} })" >
|
||||
<vn-item-product title="View item" item="item"></vn-item-product>
|
||||
</a>
|
||||
</vn-card>
|
||||
<vn-paging index="index" total="index.model.count"></vn-paging>
|
||||
</div>
|
||||
<a ui-sref="item.create" fixed-bottom-right>
|
||||
<vn-float-button icon="add"></vn-float-button>
|
||||
</a>
|
||||
</div>
|
|
@ -0,0 +1,17 @@
|
|||
import ngModule from '../module';
|
||||
import './item-product';
|
||||
import './style.css';
|
||||
|
||||
class ItemList {
|
||||
constructor() {
|
||||
this.model = {};
|
||||
}
|
||||
search(index) {
|
||||
index.accept();
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnItemList', {
|
||||
template: require('./list.html'),
|
||||
controller: ItemList
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
vn-item-product {
|
||||
display: block;
|
||||
}
|
||||
a.item-product-link {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
a.item-product-link:hover {
|
||||
color: white;
|
||||
background-color: #424242;
|
||||
}
|
||||
|
||||
vn-item-product img {
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.vn-item-product-name {
|
||||
font-family: vn-font-bold;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"Items": "Artículos",
|
||||
"Item": "Artículo",
|
||||
"Category": "Categoría",
|
||||
"Description": "Descripción",
|
||||
"Size": "Tamaño",
|
||||
"Type": "Tipo"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import {ng} from 'vendor';
|
||||
import 'core';
|
||||
|
||||
const ngModule = ng.module('item', ['vnCore']);
|
||||
export default ngModule;
|
|
@ -5,5 +5,6 @@
|
|||
"client": [],
|
||||
"production": [],
|
||||
"route": [],
|
||||
"locator": []
|
||||
"locator": [],
|
||||
"item": []
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
"Production" : "Producción",
|
||||
"Modules access" : "Acceso a módulos",
|
||||
"Locator": "Localizador",
|
||||
"Items": "Artículos",
|
||||
"name": "Nombre",
|
||||
"credit": "Crédito",
|
||||
"phone": "Teléfono",
|
||||
|
|
|
@ -43,3 +43,14 @@ export const locator = () => {
|
|||
};
|
||||
|
||||
core.splitingRegister.register('locator', locator);
|
||||
|
||||
export const item = () => {
|
||||
return new Promise(resolve => {
|
||||
require.ensure([], () => {
|
||||
require('item');
|
||||
resolve('item');
|
||||
}, 'item');
|
||||
});
|
||||
};
|
||||
|
||||
core.splitingRegister.register('item', item);
|
||||
|
|
|
@ -99,3 +99,17 @@ html [pointer], .pointer{
|
|||
html [noDrop], .noDrop{
|
||||
cursor: no-drop;
|
||||
}
|
||||
|
||||
vn-main-block {
|
||||
display:block;
|
||||
max-width: 1920px;
|
||||
width:100%;
|
||||
margin: 0 auto;
|
||||
|
||||
.left-block {
|
||||
max-width: 20em;
|
||||
min-width: 18em;
|
||||
padding-left: 1em;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,19 @@ services:
|
|||
expose:
|
||||
- "3006"
|
||||
ports:
|
||||
- "3006:3006"
|
||||
- "3006:3006"
|
||||
item:
|
||||
environment:
|
||||
- NODE_ENV=${NODE_ENV}
|
||||
container_name: "${BRANCH_NAME}-item"
|
||||
image: "item:${TAG}"
|
||||
build:
|
||||
context: ./services
|
||||
dockerfile: /item/Dockerfile
|
||||
expose:
|
||||
- "3007"
|
||||
ports:
|
||||
- "3007:3007"
|
||||
nginx:
|
||||
container_name: "${BRANCH_NAME}-nginx"
|
||||
image: "nginx:${TAG}"
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
FROM node:6.9.1
|
||||
|
||||
COPY item /app
|
||||
|
||||
COPY loopback /loopback
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm install
|
||||
|
||||
RUN npm -g install pm2
|
||||
|
||||
CMD ["pm2-docker", "./server/server.js"]
|
||||
|
||||
EXPOSE 3007
|
|
@ -0,0 +1,31 @@
|
|||
module.exports = Self => {
|
||||
Self.installMethod('filter', filterParams);
|
||||
|
||||
function filterParams(params) {
|
||||
let filter = {
|
||||
where: {},
|
||||
skip: (params.page - 1) * params.size,
|
||||
limit: params.size,
|
||||
order: params.order || 'relevancy DESC',
|
||||
include: {
|
||||
relation: "itemType",
|
||||
scope: {
|
||||
fields: ["id", "name"]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
delete params.page;
|
||||
delete params.size;
|
||||
delete params.order;
|
||||
|
||||
if (params.itemSize) {
|
||||
filter.where.size = params.itemSize;
|
||||
delete params.itemSize;
|
||||
}
|
||||
|
||||
Object.assign(filter.where, params);
|
||||
|
||||
return filter;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "Ink",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "ink",
|
||||
"database": "vn"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"name": {
|
||||
"type": "String"
|
||||
},
|
||||
"showOrder": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "Intrastat",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "intrastat",
|
||||
"database": "vn"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"description": {
|
||||
"type": "String"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"taxGroup": {
|
||||
"type": "belongsTo",
|
||||
"model": "TaxGroup",
|
||||
"foreignKey": "taxGroupFk"
|
||||
},
|
||||
"taxCode": {
|
||||
"type": "belongsTo",
|
||||
"model": "TaxCode",
|
||||
"foreignKey": "taxCodeFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "ItemType",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "itemType",
|
||||
"database": "vn"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"name": {
|
||||
"type": "String"
|
||||
},
|
||||
"life": {
|
||||
"type": "Number"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = function(Self) {
|
||||
require('../methods/item/filter.js')(Self);
|
||||
};
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"name": "Item",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "item",
|
||||
"database": "vn"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"name": {
|
||||
"type": "String"
|
||||
},
|
||||
"size": {
|
||||
"type": "Number"
|
||||
},
|
||||
"category": {
|
||||
"type": "String"
|
||||
},
|
||||
"stems": {
|
||||
"type": "Number"
|
||||
},
|
||||
"description": {
|
||||
"type": "String"
|
||||
},
|
||||
"isOnOffer": {
|
||||
"type": "Boolean"
|
||||
},
|
||||
"isBargain": {
|
||||
"type": "Boolean"
|
||||
},
|
||||
"comment": {
|
||||
"type": "String"
|
||||
},
|
||||
"relevancy": {
|
||||
"type": "Number"
|
||||
},
|
||||
"image": {
|
||||
"type": "String"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"itemType": {
|
||||
"type": "belongsTo",
|
||||
"model": "ItemType",
|
||||
"foreignKey": "typeFk"
|
||||
},
|
||||
"ink": {
|
||||
"type": "belongsTo",
|
||||
"model": "Ink",
|
||||
"foreignKey": "inkFk"
|
||||
},
|
||||
"origin": {
|
||||
"type": "belongsTo",
|
||||
"model": "Origin",
|
||||
"foreignKey": "originFk"
|
||||
},
|
||||
"producer": {
|
||||
"type": "belongsTo",
|
||||
"model": "Producer",
|
||||
"foreignKey": "producerFk"
|
||||
},
|
||||
"intrastat": {
|
||||
"type": "belongsTo",
|
||||
"model": "Intrastat",
|
||||
"foreignKey": "intrastatFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "Origin",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "origin",
|
||||
"database": "vn"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"code": {
|
||||
"type": "String"
|
||||
},
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "Producer",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "producer",
|
||||
"database": "vn"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"name": "TaxCode",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "taxCode",
|
||||
"database": "vn"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"dated": {
|
||||
"type": "date"
|
||||
},
|
||||
"code": {
|
||||
"type": "String"
|
||||
},
|
||||
"rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"equalizationTax": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "String"
|
||||
},
|
||||
"isActive": {
|
||||
"type": "Boolean"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"taxType": {
|
||||
"type": "belongsTo",
|
||||
"model": "TaxType",
|
||||
"foreignKey": "taxTypeFk"
|
||||
},
|
||||
"link": {
|
||||
"type": "belongsTo",
|
||||
"model": "Link",
|
||||
"foreignKey": "linkFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "TaxGroup",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "taxGroup",
|
||||
"database": "vn"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"description": {
|
||||
"type": "String"
|
||||
},
|
||||
"code": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "TaxType",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "taxType",
|
||||
"database": "vn"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"nickname": {
|
||||
"type": "String"
|
||||
},
|
||||
"serial": {
|
||||
"type": "String"
|
||||
},
|
||||
"TIPOOPE": {
|
||||
"type": "String"
|
||||
},
|
||||
"description": {
|
||||
"type": "String"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"country": {
|
||||
"type": "belongsTo",
|
||||
"model": "Country",
|
||||
"foreignKey": "countryFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "vn-item",
|
||||
"version": "1.0.0",
|
||||
"main": "server/server.js",
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"start": "node .",
|
||||
"posttest": "npm run lint && nsp check"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.verdnatura.es/salix"
|
||||
},
|
||||
"license": "GPL-3.0",
|
||||
"description": "vn-item",
|
||||
"dependencies": {
|
||||
"uuid": "^3.1.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"port": 3007
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"user": {
|
||||
"dataSource": "salix"
|
||||
},
|
||||
"AccessToken": {
|
||||
"dataSource": "salix",
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "user",
|
||||
"foreignKey": "userId"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ACL": {
|
||||
"dataSource": "salix"
|
||||
},
|
||||
"RoleMapping": {
|
||||
"dataSource": "salix"
|
||||
},
|
||||
"Role": {
|
||||
"dataSource": "salix"
|
||||
},
|
||||
"Account": {
|
||||
"dataSource": "salix"
|
||||
},
|
||||
"Item": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ItemType": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Ink": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Origin": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Producer": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Intrastat": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"TaxGroup": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"TaxCode": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"TaxType": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Country": {
|
||||
"dataSource": "salix"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
var vnLoopback = require('../../loopback/server/server.js');
|
||||
|
||||
var app = module.exports = vnLoopback.loopback();
|
||||
vnLoopback.boot(app, __dirname, module);
|
|
@ -1,15 +1,20 @@
|
|||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var config = {};
|
||||
let defaultFile = 'datasources.json';
|
||||
|
||||
let devConfigPath = path.join(__dirname, '/config/datasources.development.json');
|
||||
let configPath = path.join(__dirname, '/config/datasources.json');
|
||||
function getFile(fileName) {
|
||||
return require(path.join(__dirname, `/config/${fileName}`));
|
||||
}
|
||||
|
||||
try {
|
||||
config = Object.assign(require(configPath), require(devConfigPath));
|
||||
let envFile = 'datasources.development.json';
|
||||
|
||||
if (process.env.NODE_ENV === 'test')
|
||||
envFile = 'datasources.test.json';
|
||||
|
||||
config = getFile(envFile);
|
||||
} catch (e) {
|
||||
if (e.code == 'MODULE_NOT_FOUND')
|
||||
config = require(configPath);
|
||||
config = getFile(defaultFile);
|
||||
}
|
||||
|
||||
config.proxy = require('../../nginx/config.json');
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
"debug": false,
|
||||
"defaultLanguage": "es",
|
||||
"senderMail": "noreply@localhost",
|
||||
"senderName": ""
|
||||
"senderName": "VerdNatura"
|
||||
},
|
||||
"mysql": {
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"user": "reports",
|
||||
"user": "root",
|
||||
"password": "",
|
||||
"database": ""
|
||||
"database": "vn"
|
||||
},
|
||||
"smtp": {
|
||||
"host": "localhost",
|
||||
|
|
|
@ -12,15 +12,17 @@ module.exports = {
|
|||
* Load mail config.
|
||||
*/
|
||||
init: function() {
|
||||
|
||||
this.transporter = nodemailer.createTransport(config.smtp);
|
||||
|
||||
this.transporter.verify(function(error, success) {
|
||||
if (error) {
|
||||
throw new Error(error);
|
||||
console.error(error);
|
||||
} else if (config.app.debug) {
|
||||
console.log('SMTP connection stablished');
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,10 +4,15 @@ var config = require('../config.js');
|
|||
var mail = require('../mail.js');
|
||||
var template = require('../template.js');
|
||||
var httpRequest = require('request');
|
||||
var auth = require('../auth.js');
|
||||
|
||||
// Auth middleware
|
||||
var requestToken = function(request, response, next) {
|
||||
auth.init(request, response, next);
|
||||
};
|
||||
|
||||
// Printer setup
|
||||
router.post('/printer-setup/:clientId', function(request, response) {
|
||||
router.get('/printer-setup/:clientId', requestToken, function(request, response) {
|
||||
mail.sendWithTemplate('printer-setup', {clientId: request.params.clientId}, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
@ -17,7 +22,7 @@ router.post('/printer-setup/:clientId', function(request, response) {
|
|||
});
|
||||
|
||||
// Printer setup preview
|
||||
router.get('/printer-setup/:clientId', function(request, response) {
|
||||
router.get('/printer-setup/:clientId/preview', requestToken, 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});
|
||||
|
@ -27,7 +32,7 @@ router.get('/printer-setup/:clientId', function(request, response) {
|
|||
});
|
||||
|
||||
// Client welcome
|
||||
router.post('/client-welcome/:clientId', function(request, response) {
|
||||
router.get('/client-welcome/:clientId', requestToken, function(request, response) {
|
||||
mail.sendWithTemplate('client-welcome', {clientId: request.params.clientId}, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
@ -37,7 +42,7 @@ router.post('/client-welcome/:clientId', function(request, response) {
|
|||
});
|
||||
|
||||
// Client welcome preview
|
||||
router.get('/client-welcome/:clientId', function(request, response) {
|
||||
router.get('/client-welcome/:clientId/preview', requestToken, 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});
|
||||
|
@ -47,8 +52,13 @@ router.get('/client-welcome/:clientId', function(request, response) {
|
|||
});
|
||||
|
||||
// Client SEPA CORE
|
||||
router.post('/sepa-core/:clientId', function(request, response) {
|
||||
let path = `${request.proxyHost}/print/manuscript/sepa-core/${request.params.clientId}`;
|
||||
router.get('/sepa-core/:companyId/:clientId', requestToken, function(request, response) {
|
||||
let params = {
|
||||
clientId: request.params.clientId,
|
||||
companyId: request.params.companyId
|
||||
};
|
||||
|
||||
let path = `${request.proxyHost}/print/manuscript/sepa-core/${params.companyId}/${params.clientId}`;
|
||||
let options = {
|
||||
url: path,
|
||||
method: 'GET',
|
||||
|
@ -59,25 +69,75 @@ router.post('/sepa-core/:clientId', function(request, response) {
|
|||
|
||||
let httpStream = httpRequest(options, function(error, httpResponse, body) {
|
||||
if (error || httpResponse.statusCode != 200)
|
||||
return response.status(400).json({message: error.message});
|
||||
return response.status(400).json({message: error});
|
||||
});
|
||||
|
||||
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();
|
||||
params.attachments = [{filename: 'sepa-core.pdf', content: httpStream}];
|
||||
|
||||
mail.sendWithTemplate('sepa-core', params, 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', {
|
||||
router.get('/sepa-core/:companyId/:clientId/preview', requestToken, function(request, response) {
|
||||
let params = {
|
||||
clientId: request.params.clientId,
|
||||
companyId: request.params.companyId,
|
||||
token: request.user.token,
|
||||
isPreview: true
|
||||
};
|
||||
|
||||
template.get('sepa-core', params, (error, result) => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
response.send(result.body);
|
||||
});
|
||||
});
|
||||
|
||||
// First debtor letter
|
||||
router.get('/letter-debtor-st/:companyId/:clientId', requestToken, function(request, response) {
|
||||
let params = {
|
||||
clientId: request.params.clientId,
|
||||
companyId: request.params.companyId,
|
||||
token: request.user.token
|
||||
};
|
||||
|
||||
let path = `${request.proxyHost}/print/manuscript/letter-debtor/${params.companyId}/${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});
|
||||
});
|
||||
|
||||
if (httpStream)
|
||||
params.attachments = [{filename: 'extracto.pdf', content: httpStream}];
|
||||
|
||||
mail.sendWithTemplate('letter-debtor-st', params, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
|
||||
// First debtor letter preview
|
||||
router.get('/letter-debtor-st/:companyId/:clientId/preview', requestToken, function(request, response) {
|
||||
template.get('letter-debtor-st', {
|
||||
clientId: request.params.clientId,
|
||||
companyId: request.params.companyId,
|
||||
token: request.user.token,
|
||||
isPreview: true
|
||||
}, (error, result) => {
|
||||
|
@ -88,6 +148,85 @@ router.get('/sepa-core/:clientId', function(request, response) {
|
|||
});
|
||||
});
|
||||
|
||||
// Second debtor letter
|
||||
router.get('/letter-debtor-nd/:companyId/:clientId', requestToken, function(request, response) {
|
||||
let params = {
|
||||
clientId: request.params.clientId,
|
||||
companyId: request.params.companyId,
|
||||
token: request.user.token
|
||||
};
|
||||
|
||||
let path = `${request.proxyHost}/print/manuscript/letter-debtor/${params.companyId}/${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});
|
||||
});
|
||||
|
||||
if (httpStream)
|
||||
params.attachments = [{filename: 'extracto.pdf', content: httpStream}];
|
||||
|
||||
mail.sendWithTemplate('letter-debtor-nd', params, error => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
|
||||
// Second debtor letter preview
|
||||
router.get('/letter-debtor-nd/:companyId/:clientId/preview', requestToken, function(request, response) {
|
||||
template.get('letter-debtor-nd', {
|
||||
clientId: request.params.clientId,
|
||||
companyId: request.params.companyId,
|
||||
token: request.user.token,
|
||||
isPreview: true
|
||||
}, (error, result) => {
|
||||
if (error)
|
||||
return response.status(400).json({message: error.message});
|
||||
|
||||
response.send(result.body);
|
||||
});
|
||||
});
|
||||
|
||||
// Payment method changes
|
||||
router.get('/payment-update/:clientId', requestToken, 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.get('/client-deactivate/:clientId', requestToken, function(request, response) {
|
||||
var params = {
|
||||
alias: 'creditInsurance',
|
||||
code: 'clientDeactivate',
|
||||
bodyParams: {
|
||||
clientId: request.params.clientId
|
||||
}
|
||||
};
|
||||
|
||||
mail.sendWithTemplate('notification-alias', params, error => {
|
||||
if (error)
|
||||
response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
|
||||
// Single user notification
|
||||
/* router.post('/:recipient/noticeUserSend', function(request, response) {
|
||||
var params = {
|
||||
|
@ -146,34 +285,4 @@ router.get('/sepa-core/:clientId', function(request, response) {
|
|||
mail.sendWithTemplate('notification-notice', params, result => {
|
||||
return response.json(result);
|
||||
});
|
||||
}); */
|
||||
|
||||
// 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 = {
|
||||
alias: 'creditInsurance',
|
||||
code: 'clientDeactivate',
|
||||
bodyParams: {
|
||||
clientId: request.params.clientId
|
||||
}
|
||||
};
|
||||
|
||||
mail.sendWithTemplate('notification-alias', params, error => {
|
||||
if (error)
|
||||
response.status(400).json({message: error.message});
|
||||
|
||||
return response.json();
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
}); */
|
|
@ -1,5 +1,7 @@
|
|||
var express = require('express');
|
||||
var router = new express.Router();
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
// Mailer default page
|
||||
router.get('/', function(request, response) {
|
||||
|
@ -9,4 +11,20 @@ router.get('/', function(request, response) {
|
|||
// Notifications
|
||||
router.use('/notification', require('./route/notification.js'));
|
||||
|
||||
// Serve static images
|
||||
router.use('/static/:template/:image', function(request, response) {
|
||||
let imagePath = path.join(__dirname, '/template/', request.params.template, '/image/', request.params.image);
|
||||
|
||||
fs.stat(imagePath, function(error) {
|
||||
if (error)
|
||||
return response.json({message: 'Image not found'});
|
||||
|
||||
let readStream = fs.createReadStream(imagePath);
|
||||
|
||||
readStream.on('open', function() {
|
||||
readStream.pipe(response);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
@ -15,7 +15,7 @@ module.exports = {
|
|||
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, 'template', `${template}`, 'static', 'css', 'style.css');
|
||||
var stylePath = path.join(__dirname, 'template', `${template}`, 'style.css');
|
||||
|
||||
fs.stat(templatePath, (error, stat) => {
|
||||
if (error)
|
||||
|
@ -65,6 +65,8 @@ module.exports = {
|
|||
return cb(error);
|
||||
|
||||
instance._ = result.locale;
|
||||
instance.isPreview = params.isPreview;
|
||||
|
||||
getDataCb(null, result);
|
||||
});
|
||||
});
|
||||
|
@ -173,14 +175,17 @@ module.exports = {
|
|||
|
||||
// Template default attachments
|
||||
for (var i = 0; i < tplAttachments.length; i++) {
|
||||
let name = tplAttachments[i].replace('src="cid:', '').replace('"', '');
|
||||
let src = tplAttachments[i].replace('src="cid:', '').replace('"', '').split('/');
|
||||
let attachmentTpl = src[0];
|
||||
let attachment = src[1];
|
||||
|
||||
if (isPreview) {
|
||||
let attachmentPath = `/mailer/static/images/${name}`;
|
||||
let attachmentPath = `/mailer/static/${attachmentTpl}/${attachment}`;
|
||||
body = body.replace(tplAttachments[i], `src="${attachmentPath}"`);
|
||||
} else {
|
||||
let attachmentPath = path.join(__dirname, '../static', 'images', name);
|
||||
attachments.push({filename: name, path: attachmentPath, cid: name});
|
||||
let attachmentPath = path.join(__dirname, 'template', `${attachmentTpl}`, 'image', attachment);
|
||||
let attachmentName = attachmentTpl + '/' + attachment;
|
||||
attachments.push({filename: attachmentName, path: attachmentPath, cid: attachmentName});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,10 +14,11 @@ module.exports = class ClientWelcome {
|
|||
c.email recipient
|
||||
FROM client c
|
||||
JOIN account.user u ON u.id = c.id
|
||||
LEFT JOIN worker w ON w.id = c.workerFk
|
||||
LEFT JOIN worker w ON w.id = c.salesPersonFk
|
||||
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.clientId], (error, result) => {
|
||||
if (error || result.length == 0)
|
||||
return cb(new Error('No template data found'));
|
||||
|
|
|
@ -22,8 +22,9 @@
|
|||
<p>{{_.dear}}</p>
|
||||
<p>{{{_.bodyDescription}}}</p>
|
||||
<p>
|
||||
<div>{{_.clientNumber}} <strong>{{clientId}}</strong></div>
|
||||
<div>{{_.user}} <strong>{{userName}}</strong></div>
|
||||
<div>{{_.password}} <strong>********</strong> {{_.passwordResetText}}</div>
|
||||
<div>{{_.password}} <strong>********</strong> {{{_.passwordResetText}}}</div>
|
||||
</p>
|
||||
|
||||
<h1>{{_.sectionHowToBuyTitle}}</h1>
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
"title": "¡LE DAMOS LA BIENVENIDA!",
|
||||
"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:",
|
||||
"clientNumber": "Identificador de cliente:",
|
||||
"user": "Usuario:",
|
||||
"password": "Contraseña:",
|
||||
"passwordResetText": "(Va a recibir un correo para establecer la contraseña)",
|
||||
"passwordResetText": "(<a href=\"https://verdnatura.es\">Haga clic en \"¿Has olvidado tu contraseña?\"</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.",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<svg fill="#000000" height="48" viewBox="0 0 24 24" width="48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
After Width: | Height: | Size: 205 B |
|
@ -0,0 +1,4 @@
|
|||
<svg fill="#000000" height="48" viewBox="0 0 24 24" width="48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M11.5 9C10.12 9 9 10.12 9 11.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5S12.88 9 11.5 9zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-3.21 14.21l-2.91-2.91c-.69.44-1.51.7-2.39.7C9.01 16 7 13.99 7 11.5S9.01 7 11.5 7 16 9.01 16 11.5c0 .88-.26 1.69-.7 2.39l2.91 2.9-1.42 1.42z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 461 B |
|
@ -5,7 +5,8 @@ var format = require(path.join(__dirname, '../../util/format.js'));
|
|||
module.exports = class Footer {
|
||||
getData(params, cb) {
|
||||
let query = `SELECT
|
||||
socialName
|
||||
socialName,
|
||||
LOWER(ct.code) countryCode
|
||||
FROM client c
|
||||
JOIN country ct ON ct.id = c.countryFk
|
||||
WHERE c.id = ?`;
|
||||
|
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
@ -2,10 +2,10 @@
|
|||
<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>
|
||||
<span class="icon"><img src="cid:footer/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>
|
||||
<span class="icon"><img src="cid:footer/info.png"/></span>
|
||||
</div></a>
|
||||
</div>
|
||||
<!-- Action button block -->
|
||||
|
@ -13,22 +13,22 @@
|
|||
<!-- Networks block -->
|
||||
<div class="footer">
|
||||
<a href="https://www.facebook.com/Verdnatura" target="_blank">
|
||||
<img src="cid:facebook.png" alt="Facebook"/>
|
||||
<img src="cid:footer/facebook.png" alt="Facebook"/>
|
||||
</a>
|
||||
<a href="https://www.twitter.com/Verdnatura" target="_blank">
|
||||
<img src="cid:twitter.png" alt="Twitter"/>
|
||||
<img src="cid:footer/twitter.png" alt="Twitter"/>
|
||||
</a>
|
||||
<a href="https://www.youtube.com/Verdnatura" target="_blank">
|
||||
<img src="cid:youtube.png" alt="Youtube"/>
|
||||
<img src="cid:footer/youtube.png" alt="Youtube"/>
|
||||
</a>
|
||||
<a href="https://www.pinterest.com/Verdnatura" target="_blank">
|
||||
<img src="cid:pinterest.png" alt="Pinterest"/>
|
||||
<img src="cid:footer/pinterest.png" alt="Pinterest"/>
|
||||
</a>
|
||||
<a href="https://www.instagram.com/Verdnatura" target="_blank">
|
||||
<img src="cid:instagram.png" alt="Instagram"/>
|
||||
<img src="cid:footer/instagram.png" alt="Instagram"/>
|
||||
</a>
|
||||
<a href="https://www.linkedin.com/company/verdnatura" target="_blank">
|
||||
<img src="cid:linkedin.png" alt="Linkedin"/>
|
||||
<img src="cid:footer/linkedin.png" alt="Linkedin"/>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Networks block end -->
|
||||
|
|
|
@ -5,7 +5,8 @@ var format = require(path.join(__dirname, '../../util/format.js'));
|
|||
module.exports = class Header {
|
||||
getData(params, cb) {
|
||||
let query = `SELECT
|
||||
c.name AS clientName
|
||||
c.name AS clientName,
|
||||
LOWER(ct.code) countryCode
|
||||
FROM client c
|
||||
JOIN country ct ON ct.id = c.countryFk
|
||||
WHERE c.id = ?`;
|
||||
|
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
@ -1,3 +1,3 @@
|
|||
<div>
|
||||
<a href="https://www.verdnatura.es"/><img src="cid:header.png" alt="VerdNatura"/></a>
|
||||
<a href="https://www.verdnatura.es"/><img src="cid:header/logo.png" alt="VerdNatura"/></a>
|
||||
</div>
|
||||
|
|
Before Width: | Height: | Size: 8.4 KiB |
|
@ -0,0 +1 @@
|
|||
[]
|
|
@ -0,0 +1,87 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<title>{{_.subject}}</title>
|
||||
<meta charset="utf8"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<div class="container">
|
||||
<!-- Header block -->
|
||||
{{$.header}}
|
||||
<!-- Header block end -->
|
||||
|
||||
<!-- Title block -->
|
||||
<div class="title">
|
||||
<h1>{{_.title}}</h1>
|
||||
</div>
|
||||
<!-- Title block end -->
|
||||
|
||||
<!-- Mail body block -->
|
||||
<div class="body">
|
||||
<p>{{_.dear}}</p>
|
||||
|
||||
<p>{{_.bodyDescription}}</p>
|
||||
<p>{{_.termLimits}}</p>
|
||||
<p>
|
||||
{{_.payMethod}}
|
||||
|
||||
<ol>
|
||||
<li>{{_.payMethodOption1}}</li>
|
||||
<li>{{_.payMethodOption2}}</li>
|
||||
</ol>
|
||||
</p>
|
||||
<p>
|
||||
{{_.legalActions}}
|
||||
<ol type="a">
|
||||
<li>{{_.legalActionsOption1}}</li>
|
||||
<li>{{_.legalActionsOption2}}</li>
|
||||
<li>{{_.legalActionsOption3}}</li>
|
||||
</ol>
|
||||
</p>
|
||||
|
||||
<p>{{_.contact}}</p>
|
||||
|
||||
<p>{{_.waitingForNews}}</p>
|
||||
<p>{{_.conclusion}}</p>
|
||||
|
||||
<p>
|
||||
<div class="row">
|
||||
<div class="text">{{bankName}}</div>
|
||||
<div class="control">{{iban}}</div>
|
||||
<div class="description">
|
||||
<div class="line"><span>{{_.accountTransferData}}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
{{#isPreview}}
|
||||
<a href="/print/manuscript/letter-debtor/{{companyId}}/{{clientId}}/preview?token={{token}}" target="_blank" title="Ver adjunto">
|
||||
<div class="attachment">
|
||||
<div class="attachment-icon">
|
||||
<img src="cid:default/preview.svg" alt="Ver adjunto"/>
|
||||
</div>
|
||||
<span>Ver adjunto</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/print/manuscript/letter-debtor/{{companyId}}/{{clientId}}?token={{token}}" target="_blank" title="Descargar adjunto">
|
||||
<div class="attachment">
|
||||
<div class="attachment-icon">
|
||||
<img src="cid:default/download.svg" alt="Descargar adjunto"/>
|
||||
</div>
|
||||
<span>Descargar PDF</span>
|
||||
</div>
|
||||
</a>
|
||||
{{/isPreview}}
|
||||
</div>
|
||||
|
||||
<!-- Mail body block end -->
|
||||
|
||||
<!-- Footer block -->
|
||||
{{$.footer}}
|
||||
<!-- Footer block end -->
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
var path = require('path');
|
||||
var database = require(path.join(__dirname, '../../database.js'));
|
||||
var format = require(path.join(__dirname, '../../util/format.js'));
|
||||
|
||||
module.exports = class LetterDebtorNd {
|
||||
getData(params, cb) {
|
||||
let query = `SELECT
|
||||
sa.iban,
|
||||
be.name AS bankName,
|
||||
LOWER(ct.code) countryCode,
|
||||
c.email recipient
|
||||
FROM client c
|
||||
JOIN company AS cny
|
||||
JOIN supplierAccount AS sa ON sa.id = cny.supplierAccountFk
|
||||
JOIN bankEntity be ON be.id = sa.bankEntityFk
|
||||
JOIN country ct ON ct.id = c.countryFk
|
||||
WHERE c.id = ? AND cny.id = ?`;
|
||||
|
||||
this.clientId = params.clientId;
|
||||
this.companyId = params.companyId;
|
||||
this.token = params.token;
|
||||
|
||||
database.pool.query(query, [params.clientId, params.companyId], (error, result) => {
|
||||
if (error || result.length == 0)
|
||||
return cb(new Error('No template data found'));
|
||||
|
||||
Object.assign(this, result[0]);
|
||||
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
get previewAttachments() {
|
||||
if (this.isPreview)
|
||||
return `<a href="/print/manuscript/letter-debtor/${this.companyId}/${this.clientId}/preview?token=${this.token}" target="_blank" title="Ver extracto.pdf">` +
|
||||
'<div class="attachment"><div class="attachment-icon"><img src="cid:attachment.png" alt="Descargar adjunto"/></div>' +
|
||||
'<span>extracto.pdf</span></div></a>';
|
||||
}
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"subject": "Reiteración de aviso por saldo deudor",
|
||||
"title": "AVISO REITERADO",
|
||||
"dear": "Estimado cliente,",
|
||||
"bodyDescription": "Nos dirigimos a Vd. nuevamente para informarle que sigue pendiente su deuda con nuestra empresa, tal y como puede comprobar en el extracto adjunto.",
|
||||
"termLimits": "Dado que los plazos de pago acordados están ampliamente superados, no procede mayor dilación en la liquidación del importe adeudado.",
|
||||
"payMethod": "Para ello dispone de las siguientes formas de pago:",
|
||||
"payMethodOption1": "Pago online desde nuestra web",
|
||||
"payMethodOption2": "Ingreso o transferencia al número de cuenta que detallamos al pie de esta carta, indicando el número de cliente.",
|
||||
"legalActions": "En caso de no ser atendido este apremio de pago, nos veremos obligados a iniciar las acciones legales que procedan, entre las que están:",
|
||||
"legalActionsOption1": "Inclusión en ficheros negativos sobre solvencia patrimonial y crédito.",
|
||||
"legalActionsOption2": "Reclamación judicial",
|
||||
"legalActionsOption3": "Cesión de deuda a una empresa de gestión de cobro",
|
||||
"contact": "Para consultas, puede ponerse en contacto con nosotros en el 96 324 21 00.",
|
||||
"waitingForNews": "En espera de sus noticias",
|
||||
"conclusion": "Gracias por su atención.",
|
||||
"accountTransferData": "Datos para transferencia bancaria"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
[]
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<title>{{_.subject}}</title>
|
||||
<meta charset="utf8"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<div class="container">
|
||||
<!-- Header block -->
|
||||
{{$.header}}
|
||||
<!-- Header block end -->
|
||||
|
||||
<!-- Title block -->
|
||||
<div class="title">
|
||||
<h1>{{_.title}}</h1>
|
||||
</div>
|
||||
<!-- Title block end -->
|
||||
|
||||
<!-- Mail body block -->
|
||||
<div class="body">
|
||||
<p>{{_.dear}}</p>
|
||||
|
||||
<p>{{_.bodyDescription}}</p>
|
||||
<p>{{_.viewExtract}}</p>
|
||||
<p>{{_.validData}}</p>
|
||||
<p>{{_.payMethod}}</p>
|
||||
<p>{{_.conclusion}}</p>
|
||||
|
||||
<p>
|
||||
<div class="row">
|
||||
<div class="text">{{bankName}}</div>
|
||||
<div class="control">{{iban}}</div>
|
||||
<div class="description">
|
||||
<div class="line"><span>{{_.accountTransferData}}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
{{#isPreview}}
|
||||
<a href="/print/manuscript/letter-debtor/{{companyId}}/{{clientId}}/preview?token={{token}}" target="_blank" title="Ver adjunto">
|
||||
<div class="attachment">
|
||||
<div class="attachment-icon">
|
||||
<img src="cid:default/preview.svg" alt="Ver adjunto"/>
|
||||
</div>
|
||||
<span>Ver adjunto</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/print/manuscript/letter-debtor/{{companyId}}/{{clientId}}?token={{token}}" target="_blank" title="Descargar adjunto">
|
||||
<div class="attachment">
|
||||
<div class="attachment-icon">
|
||||
<img src="cid:default/download.svg" alt="Descargar adjunto"/>
|
||||
</div>
|
||||
<span>Descargar PDF</span>
|
||||
</div>
|
||||
</a>
|
||||
{{/isPreview}}
|
||||
</div>
|
||||
|
||||
<!-- Mail body block end -->
|
||||
|
||||
<!-- Footer block -->
|
||||
{{$.footer}}
|
||||
<!-- Footer block end -->
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
var path = require('path');
|
||||
var database = require(path.join(__dirname, '../../database.js'));
|
||||
var format = require(path.join(__dirname, '../../util/format.js'));
|
||||
|
||||
module.exports = class LetterDebtorSt {
|
||||
getData(params, cb) {
|
||||
let query = `SELECT
|
||||
sa.iban,
|
||||
be.name AS bankName,
|
||||
LOWER(ct.code) countryCode,
|
||||
c.email recipient
|
||||
FROM client c
|
||||
JOIN company AS cny
|
||||
JOIN supplierAccount AS sa ON sa.id = cny.supplierAccountFk
|
||||
JOIN bankEntity be ON be.id = sa.bankEntityFk
|
||||
JOIN country ct ON ct.id = c.countryFk
|
||||
WHERE c.id = ? AND cny.id = ?`;
|
||||
|
||||
this.clientId = params.clientId;
|
||||
this.companyId = params.companyId;
|
||||
this.token = params.token;
|
||||
|
||||
database.pool.query(query, [params.clientId, params.companyId], (error, result) => {
|
||||
if (error || result.length == 0)
|
||||
return cb(new Error('No template data found'));
|
||||
|
||||
Object.assign(this, result[0]);
|
||||
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
get previewAttachments() {
|
||||
if (this.isPreview)
|
||||
return `<a href="/print/manuscript/letter-debtor/${this.companyId}/${this.clientId}/preview?token=${this.token}" target="_blank" title="Ver extracto.pdf">` +
|
||||
'<div class="attachment"><div class="attachment-icon"><img src="cid:attachment.png" alt="Descargar adjunto"/></div>' +
|
||||
'<span>extracto.pdf</span></div></a>';
|
||||
}
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"subject": "Aviso inicial por saldo deudor",
|
||||
"title": "AVISO INICIAL",
|
||||
"dear": "Estimado cliente,",
|
||||
"bodyDescription": "Por el presente escrito le comunicamos que, según nuestros datos contables, su cuenta tiene un saldo pendiente de liquidar.",
|
||||
"viewExtract": "Le solicitamos compruebe que el extracto adjunto corresponde con los datos de que Vd. dispone. Nuestro departamento de administración le aclarará gustosamente cualquier duda que pueda tener, e igualmente le facilitará cualquier documento que solicite.",
|
||||
"validData": "Si al comprobar los datos aportados resultaran correctos, le rogamos proceda a regularizar su situación.",
|
||||
"payMethod": "Si no desea desplazarse personalmente hasta nuestras oficinas, puede realizar el pago mediante transferencia bancaria a la cuenta que figura al pie del comunicado, indicando su número de cliente, o bien puede realizar el pago online desde nuestra página web.",
|
||||
"conclusion": "De antemano le agradecemos su amable colaboración.",
|
||||
"accountTransferData": "Datos para transferencia bancaria"
|
||||
}
|
|
@ -4,8 +4,7 @@ var format = require(path.join(__dirname, '../../util/format.js'));
|
|||
|
||||
module.exports = class PaymentUpdate {
|
||||
getData(params, cb) {
|
||||
let query = `SELECT
|
||||
c.id clientId,
|
||||
let query = `SELECT
|
||||
pm.id payMethodFk,
|
||||
pm.name payMethodName,
|
||||
c.dueDay,
|
||||
|
@ -13,9 +12,12 @@ module.exports = class PaymentUpdate {
|
|||
LOWER(ct.code) countryCode,
|
||||
c.email recipient
|
||||
FROM client c
|
||||
JOIN payMethod pm ON pm.id = c.paymentMethodFk
|
||||
JOIN payMethod pm ON pm.id = c.payMethodFk
|
||||
JOIN country ct ON ct.id = c.countryFk
|
||||
WHERE c.id = ?`;
|
||||
|
||||
this.clientId = params.clientId;
|
||||
|
||||
database.pool.query(query, [params.clientId], (error, result) => {
|
||||
if (error || result.length == 0)
|
||||
return cb(new Error('No template data found'));
|
||||
|
|
|
@ -4,19 +4,21 @@ var format = require(path.join(__dirname, '../../util/format.js'));
|
|||
|
||||
module.exports = class PrinterSetup {
|
||||
getData(params, cb) {
|
||||
let query = `SELECT
|
||||
c.id clientId,
|
||||
let query = `SELECT
|
||||
CONCAT(w.name, ' ', w.firstName) name,
|
||||
w.phone AS phone,
|
||||
CONCAT(u.name, '@verdnatura.es') AS email,
|
||||
LOWER(ct.code) countryCode,
|
||||
c.email recipient
|
||||
FROM client c
|
||||
LEFT JOIN worker w ON w.id = c.workerFk
|
||||
LEFT JOIN worker w ON w.id = c.salesPersonFk
|
||||
LEFT JOIN account.user u ON u.id = w.userFk
|
||||
JOIN country ct ON ct.id = c.countryFk
|
||||
WHERE c.id = ?`;
|
||||
|
||||
|
||||
this.clientId = params.clientId;
|
||||
this.isPreview = params.isPreview;
|
||||
|
||||
database.pool.query(query, [params.clientId], (error, result) => {
|
||||
if (error || result.length == 0)
|
||||
return cb(new Error('No template data found'));
|
||||
|
|
|
@ -22,7 +22,26 @@
|
|||
<p>{{_.dear}}</p>
|
||||
<p>{{_.bodyDescription}}</p>
|
||||
<p>{{_.conclusion}}</p>
|
||||
{{{previewAttachments}}}
|
||||
|
||||
{{#isPreview}}
|
||||
<a href="/print/manuscript/sepa-core/{{companyId}}/{{clientId}}/preview?token={{token}}" target="_blank" title="Ver adjunto">
|
||||
<div class="attachment">
|
||||
<div class="attachment-icon">
|
||||
<img src="cid:default/preview.svg" alt="Ver adjunto"/>
|
||||
</div>
|
||||
<span>Ver adjunto</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/print/manuscript/sepa-core/{{companyId}}/{{clientId}}?token={{token}}" target="_blank" title="Descargar adjunto">
|
||||
<div class="attachment">
|
||||
<div class="attachment-icon">
|
||||
<img src="cid:default/download.svg" alt="Descargar adjunto"/>
|
||||
</div>
|
||||
<span>Descargar PDF</span>
|
||||
</div>
|
||||
</a>
|
||||
{{/isPreview}}
|
||||
</div>
|
||||
<!-- Mail body block end -->
|
||||
|
||||
|
|
|
@ -5,19 +5,19 @@ var format = require(path.join(__dirname, '../../util/format.js'));
|
|||
module.exports = class SepaCore {
|
||||
getData(params, cb) {
|
||||
let query = `SELECT
|
||||
c.id clientId,
|
||||
CONCAT(w.name, ' ', w.firstName) name,
|
||||
w.phone AS phone,
|
||||
CONCAT(u.name, '@verdnatura.es') AS email,
|
||||
LOWER(ct.code) countryCode,
|
||||
c.email recipient
|
||||
FROM client c
|
||||
LEFT JOIN worker w ON w.id = c.workerFk
|
||||
LEFT JOIN worker w ON w.id = c.salesPersonFk
|
||||
LEFT JOIN account.user u ON u.id = w.userFk
|
||||
JOIN country ct ON ct.id = c.countryFk
|
||||
WHERE c.id = ?`;
|
||||
|
||||
this.isPreview = params.isPreview;
|
||||
this.clientId = params.clientId;
|
||||
this.companyId = params.companyId;
|
||||
this.token = params.token;
|
||||
|
||||
database.pool.query(query, [params.clientId], (error, result) => {
|
||||
|
@ -29,11 +29,4 @@ module.exports = class SepaCore {
|
|||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
get previewAttachments() {
|
||||
if (this.isPreview)
|
||||
return `<a href="/print/manuscript/sepa-core/${this.clientId}/?token=${this.token}" target="_blank" title="Ver sepa-core.pdf">` +
|
||||
'<div class="attachment"><div class="attachment-icon"><img src="cid:attachment.png" alt="Descargar adjunto"/></div>' +
|
||||
'<span>sepa-core.pdf</span></div></a>';
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,13 +13,8 @@ app.use(bodyParser.urlencoded({extended: true}));
|
|||
|
||||
app.use('/static', express.static(path.join(__dirname, '../static')));
|
||||
|
||||
// Auth middleware
|
||||
var requestToken = function(request, response, next) {
|
||||
auth.init(request, response, next);
|
||||
};
|
||||
|
||||
// Load routes
|
||||
app.use('/', requestToken, require('../application/router.js'));
|
||||
app.use('/', require('../application/router.js'));
|
||||
|
||||
app.start = function() {
|
||||
var listener = app.listen(config.app.port, function() {
|
||||
|
|
|
@ -1,137 +1,221 @@
|
|||
img {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: justify
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
background-color: #EEE
|
||||
}
|
||||
|
||||
.container {
|
||||
font-family: arial, sans-serif;
|
||||
max-width: 600px;
|
||||
min-width: 320px;
|
||||
font-size: 16px;
|
||||
margin: 0 auto;
|
||||
color: #555
|
||||
}
|
||||
|
||||
.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
|
||||
}
|
||||
|
||||
.body a {
|
||||
color: #8dba25
|
||||
}
|
||||
|
||||
.body h1 {
|
||||
color: #999
|
||||
}
|
||||
|
||||
.body h3 {
|
||||
font-size: 16px
|
||||
}
|
||||
|
||||
.panel {
|
||||
border: 1px solid #DDD;
|
||||
margin-bottom: 10px;
|
||||
padding:10px
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-bottom: 15px;
|
||||
overflow: hidden;
|
||||
content: '';
|
||||
clear: both
|
||||
}
|
||||
|
||||
.row .text {
|
||||
margin-bottom: 5px
|
||||
}
|
||||
|
||||
.row .control {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box
|
||||
}
|
||||
|
||||
.row .description {
|
||||
font-size: 8px;
|
||||
color: #999
|
||||
}
|
||||
|
||||
.row .v-align {
|
||||
padding-top: 5px;
|
||||
line-height: 21px
|
||||
}
|
||||
|
||||
.row:last-child {
|
||||
margin-bottom: 0
|
||||
}
|
||||
|
||||
.row.inline .text {
|
||||
margin-bottom: 0;
|
||||
width: 40%;
|
||||
float: left
|
||||
}
|
||||
|
||||
.row.inline .control {
|
||||
font-weight: bold;
|
||||
padding-left: 20px;
|
||||
color: #000;
|
||||
width: 60%;
|
||||
float: left
|
||||
}
|
||||
|
||||
.box {
|
||||
border-top: 1px solid #CCC;
|
||||
border-right: 1px solid #CCC;
|
||||
border-bottom: 1px solid #CCC;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
padding-top: 4px;
|
||||
width: 25px;
|
||||
height: 21px;
|
||||
color: #000;
|
||||
float: left
|
||||
}
|
||||
|
||||
.row .control .box:first-child {
|
||||
border-left: 1px solid #CCC;
|
||||
}
|
||||
|
||||
.attachment {
|
||||
overflow: hidden;
|
||||
margin-top: 10px
|
||||
}
|
||||
|
||||
.attachment:after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
clear: both
|
||||
}
|
||||
|
||||
.attachment-icon {
|
||||
float: left
|
||||
}
|
||||
|
||||
.attachment span {
|
||||
padding: 16px 0 0 10px;
|
||||
float: left
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
img {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: justify
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
background-color: #EEE
|
||||
}
|
||||
|
||||
.container {
|
||||
font-family: arial, sans-serif;
|
||||
max-width: 600px;
|
||||
min-width: 320px;
|
||||
font-size: 16px;
|
||||
margin: 0 auto;
|
||||
color: #555
|
||||
}
|
||||
|
||||
.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
|
||||
}
|
||||
|
||||
.body a {
|
||||
color: #8dba25
|
||||
}
|
||||
|
||||
.body h1 {
|
||||
color: #999
|
||||
}
|
||||
|
||||
.body h3 {
|
||||
font-size: 16px
|
||||
}
|
||||
|
||||
.panel {
|
||||
border: 1px solid #DDD;
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
padding:10px
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-bottom: 15px;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.row .text {
|
||||
margin-bottom: 5px
|
||||
}
|
||||
|
||||
.row .control {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box
|
||||
}
|
||||
|
||||
.row .text, .row .control {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.row .description {
|
||||
position: relative;
|
||||
padding-top: 2px;
|
||||
overflow: hidden;
|
||||
font-size: 11px;
|
||||
display: block;
|
||||
color: #999
|
||||
}
|
||||
|
||||
.row .line {
|
||||
border-bottom: 1px solid #DDD;
|
||||
border-right: 1px solid #DDD;
|
||||
border-left: 1px solid #DDD;
|
||||
margin-top: 10px;
|
||||
color: #999;
|
||||
padding: 5px
|
||||
}
|
||||
|
||||
.row .description span {
|
||||
background-color: #FFF;
|
||||
margin: -5px 0 0 50px;
|
||||
display: block;
|
||||
padding: 5px;
|
||||
float: left
|
||||
}
|
||||
|
||||
.row:last-child {
|
||||
margin-bottom: 0
|
||||
}
|
||||
|
||||
.row.inline .text {
|
||||
margin-bottom: 0;
|
||||
width: 40%;
|
||||
float: left
|
||||
}
|
||||
|
||||
.row.inline .control {
|
||||
font-weight: bold;
|
||||
padding-left: 20px;
|
||||
color: #000;
|
||||
width: 60%;
|
||||
float: left
|
||||
}
|
||||
|
||||
.row.inline .description {
|
||||
position: static;
|
||||
overflow: visible
|
||||
}
|
||||
|
||||
.box {
|
||||
border-top: 1px solid #CCC;
|
||||
border-right: 1px solid #CCC;
|
||||
border-bottom: 1px solid #CCC;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
padding-top: 4px;
|
||||
width: 25px;
|
||||
height: 21px;
|
||||
color: #000;
|
||||
float: left
|
||||
}
|
||||
|
||||
.box.crossed {
|
||||
font-weight: 100;
|
||||
font-size: 16px
|
||||
}
|
||||
|
||||
.row .control .box:first-child {
|
||||
border-left: 1px solid #CCC;
|
||||
}
|
||||
|
||||
.font.small {
|
||||
font-size: 10px
|
||||
}
|
||||
|
||||
.font.verticalAlign {
|
||||
height: 27px;
|
||||
line-height: 27px
|
||||
}
|
||||
|
||||
.font.centered {
|
||||
height: 27px;
|
||||
line-height: 27px;
|
||||
text-align: center
|
||||
}
|
||||
|
||||
.verticalText {
|
||||
-moz-transform: rotate(90deg);
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
font-size: .65em;
|
||||
width: 200px;
|
||||
right: -115px;
|
||||
top: 50%
|
||||
}
|
||||
|
||||
.attachment {
|
||||
overflow: hidden;
|
||||
margin-top: 10px
|
||||
}
|
||||
|
||||
.attachment-icon {
|
||||
float: left
|
||||
}
|
||||
|
||||
.attachment span {
|
||||
padding: 16px 0 0 10px;
|
||||
float: left
|
||||
}
|
||||
|
||||
.columns {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.columns .size100 {
|
||||
width: 100%;
|
||||
float: left
|
||||
}
|
||||
|
||||
.columns .size75 {
|
||||
width: 75%;
|
||||
float: left
|
||||
}
|
||||
|
||||
.columns .size50 {
|
||||
width: 50%;
|
||||
float: left
|
||||
}
|
||||
|
||||
.columns .size33 {
|
||||
width: 33.33%;
|
||||
float: left
|
||||
}
|
||||
|
||||
.columns .size25 {
|
||||
width: 25%;
|
||||
float: left
|
||||
}
|
Before Width: | Height: | Size: 18 KiB |
|
@ -46,6 +46,9 @@ http {
|
|||
location ~ ^/print(?:/(.*))?$ {
|
||||
proxy_pass http://127.0.0.1:3006/$1$is_args$args;
|
||||
}
|
||||
location ~ ^/item(?:/(.*))?$ {
|
||||
proxy_pass http://127.0.0.1:3007/$1$is_args$args;
|
||||
}
|
||||
# Este tiene que ser el último
|
||||
location ~ ^(?:/(.*))?$ {
|
||||
proxy_pass http://127.0.0.1:3001/$1$is_args$args;
|
||||
|
|
|
@ -41,6 +41,9 @@ http {
|
|||
location ~ ^/print(?:/(.*))?$ {
|
||||
proxy_pass http://print:3006/$1$is_args$args;
|
||||
}
|
||||
location ~ ^/item(?:/(.*))?$ {
|
||||
proxy_pass http://item:3007/$1$is_args$args;
|
||||
}
|
||||
# Este tiene que ser el último
|
||||
location ~ ^(?:/(.*))?$ {
|
||||
proxy_pass http://salix:3001/$1$is_args$args;
|
||||
|
|
After Width: | Height: | Size: 2.9 KiB |
|
@ -1,15 +1,20 @@
|
|||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var config = {};
|
||||
let defaultFile = 'datasources.json';
|
||||
|
||||
let devConfigPath = path.join(__dirname, '/config/datasources.development.json');
|
||||
let configPath = path.join(__dirname, '/config/datasources.json');
|
||||
function getFile(fileName) {
|
||||
return require(path.join(__dirname, `/config/${fileName}`));
|
||||
}
|
||||
|
||||
try {
|
||||
config = Object.assign(require(configPath), require(devConfigPath));
|
||||
let envFile = 'datasources.development.json';
|
||||
|
||||
if (process.env.NODE_ENV === 'test')
|
||||
envFile = 'datasources.test.json';
|
||||
|
||||
config = getFile(envFile);
|
||||
} catch (e) {
|
||||
if (e.code == 'MODULE_NOT_FOUND')
|
||||
config = require(configPath);
|
||||
config = getFile(defaultFile);
|
||||
}
|
||||
|
||||
config.proxy = require('../../nginx/config.json');
|
||||
|
|