Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into dev
|
@ -46,7 +46,7 @@ module.exports = Self => {
|
||||||
let filter = {where: {name: user}};
|
let filter = {where: {name: user}};
|
||||||
let instance = await Self.findOne(filter);
|
let instance = await Self.findOne(filter);
|
||||||
|
|
||||||
if (!instance || instance.password !== md5(password))
|
if (!instance || instance.password !== md5(password || ''))
|
||||||
throw err;
|
throw err;
|
||||||
|
|
||||||
let where = {id: instance.id};
|
let where = {id: instance.id};
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethod('validateToken', {
|
Self.remoteMethod('validateToken', {
|
||||||
description: 'Get the user information and permissions',
|
description: 'Validates the current logged user token',
|
||||||
accepts: [
|
|
||||||
{
|
|
||||||
arg: 'token',
|
|
||||||
type: 'String',
|
|
||||||
description: 'The token to validate',
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
returns: {
|
returns: {
|
||||||
type: 'Boolean',
|
type: 'Boolean',
|
||||||
root: true
|
root: true
|
||||||
|
@ -19,13 +11,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.validateToken = function(tokenId, cb) {
|
Self.validateToken = async function() {
|
||||||
Self.app.models.AccessToken.findById(tokenId, (err, token) => {
|
return true;
|
||||||
if (err) return cb(err);
|
|
||||||
if (token)
|
|
||||||
token.validate((_, isValid) => cb(null, isValid === true));
|
|
||||||
else
|
|
||||||
cb(null, false);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
"property": "validateToken",
|
"property": "validateToken",
|
||||||
"accessType": "EXECUTE",
|
"accessType": "EXECUTE",
|
||||||
"principalType": "ROLE",
|
"principalType": "ROLE",
|
||||||
"principalId": "$everyone",
|
"principalId": "$authenticated",
|
||||||
"permission": "ALLOW"
|
"permission": "ALLOW"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -169,9 +169,9 @@ export default class Watcher extends Component {
|
||||||
*/
|
*/
|
||||||
check() {
|
check() {
|
||||||
if (this.form && this.form.$invalid)
|
if (this.form && this.form.$invalid)
|
||||||
throw new UserError(this._.instant('Some fields are invalid'));
|
throw new UserError('Some fields are invalid');
|
||||||
if (!this.dirty)
|
if (!this.dirty)
|
||||||
throw new UserError(this._.instant('No changes to save'));
|
throw new UserError('No changes to save');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import './module-loader';
|
import './module-loader';
|
||||||
import './crud';
|
import './crud';
|
||||||
import './app';
|
|
||||||
import './acl-service';
|
import './acl-service';
|
||||||
import './storage-services';
|
import './storage-services';
|
||||||
import './template';
|
import './template';
|
||||||
|
|
|
@ -41,7 +41,7 @@ export function factory($http, $window, $ocLazyLoad, $translatePartialLoader, $t
|
||||||
|
|
||||||
if (validations) {
|
if (validations) {
|
||||||
promises.push(new Promise(resolve => {
|
promises.push(new Promise(resolve => {
|
||||||
$http.get(`/${moduleName}/validations`).then(
|
$http.get(`/${moduleName}/api/modelInfo`).then(
|
||||||
json => this.onValidationsReady(json, resolve),
|
json => this.onValidationsReady(json, resolve),
|
||||||
() => resolve()
|
() => resolve()
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,18 +13,18 @@ export default class App {
|
||||||
}
|
}
|
||||||
|
|
||||||
showMessage(message) {
|
showMessage(message) {
|
||||||
if (this.snackbar)
|
if (this.logger)
|
||||||
this.snackbar.show({message: message});
|
this.logger.showMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
showSuccess(message) {
|
showSuccess(message) {
|
||||||
if (this.snackbar)
|
if (this.logger)
|
||||||
this.snackbar.showSuccess({message: message});
|
this.logger.showSuccess(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
showError(message) {
|
showError(message) {
|
||||||
if (this.snackbar)
|
if (this.logger)
|
||||||
this.snackbar.showError({message: message});
|
this.logger.showError(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
pushLoader() {
|
pushLoader() {
|
|
@ -7,99 +7,89 @@ import UserError from 'core/lib/user-error';
|
||||||
* @property {Boolean} loggedIn Whether the user is currently logged
|
* @property {Boolean} loggedIn Whether the user is currently logged
|
||||||
*/
|
*/
|
||||||
export default class Auth {
|
export default class Auth {
|
||||||
constructor($http, $state, $transitions, $window, vnToken, vnModules, aclService) {
|
constructor($http, $q, $state, $transitions, $window, vnToken, vnModules, aclService) {
|
||||||
Object.assign(this, {
|
Object.assign(this, {
|
||||||
$http,
|
$http,
|
||||||
|
$q,
|
||||||
$state,
|
$state,
|
||||||
$transitions,
|
$transitions,
|
||||||
$window,
|
$window,
|
||||||
vnToken,
|
vnToken,
|
||||||
vnModules,
|
vnModules,
|
||||||
aclService,
|
aclService,
|
||||||
token: null,
|
loggedIn: false
|
||||||
loggedIn: false,
|
|
||||||
dataLoaded: false
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
initialize() {
|
initialize() {
|
||||||
this.loggedIn = this.vnToken.token != null;
|
|
||||||
|
|
||||||
let criteria = {
|
let criteria = {
|
||||||
to: state => state.name != 'login'
|
to: state => state.name != 'login'
|
||||||
};
|
};
|
||||||
this.$transitions.onStart(criteria, transition => {
|
this.$transitions.onStart(criteria, transition => {
|
||||||
if (!this.loggedIn) {
|
if (this.loggedIn)
|
||||||
let params = {continue: this.$window.location.hash};
|
|
||||||
return transition.router.stateService.target('login', params);
|
|
||||||
}
|
|
||||||
if (!this.dataLoaded) {
|
|
||||||
this.resetData();
|
|
||||||
this.dataLoaded = true;
|
|
||||||
return this.aclService.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
let redirectToLogin = () => {
|
||||||
|
return transition.router.stateService.target('login', {
|
||||||
|
continue: this.$window.location.hash
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.vnToken.token) {
|
||||||
|
return this.loadAcls()
|
||||||
|
.then(() => true)
|
||||||
|
.catch(redirectToLogin);
|
||||||
|
} else
|
||||||
|
return redirectToLogin();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
login(user, password, remember) {
|
login(user, password, remember) {
|
||||||
if (!user)
|
if (!user)
|
||||||
throw new UserError('Please insert your user and password');
|
return this.$q.reject(new UserError('Please enter your username'));
|
||||||
|
|
||||||
let params = {
|
let params = {
|
||||||
user,
|
user,
|
||||||
password: password || undefined
|
password: password || undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.$http.post('/api/Accounts/login', params).then(
|
return this.$http.post('/api/Accounts/login', params).then(
|
||||||
json => this.onLoginOk(json, remember),
|
json => this.onLoginOk(json, remember));
|
||||||
json => this.onLoginErr(json)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
onLoginOk(json, remember) {
|
onLoginOk(json, remember) {
|
||||||
this.resetData();
|
|
||||||
this.vnToken.set(json.data.token, remember);
|
this.vnToken.set(json.data.token, remember);
|
||||||
this.loggedIn = true;
|
|
||||||
|
|
||||||
|
return this.loadAcls().then(() => {
|
||||||
let continueHash = this.$state.params.continue;
|
let continueHash = this.$state.params.continue;
|
||||||
|
|
||||||
if (continueHash)
|
if (continueHash)
|
||||||
this.$window.location = continueHash;
|
this.$window.location = continueHash;
|
||||||
else
|
else
|
||||||
this.$state.go('home');
|
this.$state.go('home');
|
||||||
}
|
});
|
||||||
onLoginErr(json) {
|
|
||||||
let message;
|
|
||||||
|
|
||||||
switch (json.status) {
|
|
||||||
case 401:
|
|
||||||
message = 'Invalid credentials';
|
|
||||||
break;
|
|
||||||
case -1:
|
|
||||||
message = 'Can\'t contact with server';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
message = 'Something went wrong';
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new UserError(message);
|
|
||||||
}
|
}
|
||||||
logout() {
|
logout() {
|
||||||
let promise = this.$http.post('/api/Accounts/logout', null, {
|
let promise = this.$http.post('/api/Accounts/logout', null, {
|
||||||
headers: {Authorization: this.vnToken.token}
|
headers: {Authorization: this.vnToken.token}
|
||||||
});
|
}).catch(() => {});
|
||||||
|
|
||||||
this.vnToken.unset();
|
this.vnToken.unset();
|
||||||
this.loggedIn = false;
|
this.loggedIn = false;
|
||||||
this.resetData();
|
this.vnModules.reset();
|
||||||
|
this.aclService.reset();
|
||||||
this.$state.go('login');
|
this.$state.go('login');
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
resetData() {
|
loadAcls() {
|
||||||
this.aclService.reset();
|
return this.aclService.load()
|
||||||
|
.then(() => {
|
||||||
|
this.loggedIn = true;
|
||||||
this.vnModules.reset();
|
this.vnModules.reset();
|
||||||
this.dataLoaded = false;
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.vnToken.unset();
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Auth.$inject = ['$http', '$state', '$transitions', '$window', 'vnToken', 'vnModules', 'aclService'];
|
Auth.$inject = ['$http', '$q', '$state', '$transitions', '$window', 'vnToken', 'vnModules', 'aclService'];
|
||||||
|
|
||||||
ngModule.service('vnAuth', Auth);
|
ngModule.service('vnAuth', Auth);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
|
||||||
|
import './app';
|
||||||
import './auth';
|
import './auth';
|
||||||
import './token';
|
import './token';
|
||||||
import './modules';
|
import './modules';
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
Invalid login: Invalid login, remember that distinction is made between uppercase and lowercase
|
||||||
|
Could not contact the server: Could not contact the server, make sure you have a connection to the network
|
||||||
|
Please enter your username: Please enter your username
|
||||||
|
It seems that the server has fall down: It seems that the server has fall down, wait a few minutes and try again
|
||||||
|
Session has expired: Your session has expired, please login again
|
||||||
|
Access denied: Access denied
|
|
@ -0,0 +1,6 @@
|
||||||
|
Invalid login: Usuario o contraseña incorrectos, recuerda que se hace distinción entre mayúsculas y minúsculas
|
||||||
|
Could not contact the server: No se ha podido contactar con el servidor, asegurate de que dispones de conexión con la red
|
||||||
|
Please enter your username: Por favor introduce tu nombre de usuario
|
||||||
|
It seems that the server has fall down: Parece que el servidor se ha caído, espera unos minutos e inténtalo de nuevo
|
||||||
|
Session has expired: Tu sesión ha expirado, por favor vuelve a iniciar sesión
|
||||||
|
Access denied: Acción no permitida
|
|
@ -6,17 +6,12 @@ import ngModule from '../module';
|
||||||
* @property {String} token The current login token or %null
|
* @property {String} token The current login token or %null
|
||||||
*/
|
*/
|
||||||
export default class Token {
|
export default class Token {
|
||||||
constructor($cookies) {
|
constructor() {
|
||||||
this.$cookies = $cookies;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.token = sessionStorage.getItem('vnToken');
|
this.token = sessionStorage.getItem('vnToken');
|
||||||
if (!this.token)
|
if (!this.token)
|
||||||
this.token = localStorage.getItem('vnToken');
|
this.token = localStorage.getItem('vnToken');
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
if (!this.token)
|
|
||||||
this.token = this.$cookies.get('vnToken');
|
|
||||||
}
|
}
|
||||||
set(value, remember) {
|
set(value, remember) {
|
||||||
this.unset();
|
this.unset();
|
||||||
|
@ -25,27 +20,15 @@ export default class Token {
|
||||||
localStorage.setItem('vnToken', value);
|
localStorage.setItem('vnToken', value);
|
||||||
else
|
else
|
||||||
sessionStorage.setItem('vnToken', value);
|
sessionStorage.setItem('vnToken', value);
|
||||||
} catch (e) {
|
} catch (e) {}
|
||||||
let options = {};
|
|
||||||
|
|
||||||
if (location.protocol == 'https:')
|
|
||||||
options.secure = true;
|
|
||||||
if (remember) {
|
|
||||||
let now = new Date().getTime();
|
|
||||||
options.expires = new Date(now + 7 * 86400000);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$cookies.put('vnToken', value, options);
|
|
||||||
}
|
|
||||||
this.token = value;
|
this.token = value;
|
||||||
}
|
}
|
||||||
unset() {
|
unset() {
|
||||||
localStorage.removeItem('vnToken');
|
localStorage.removeItem('vnToken');
|
||||||
sessionStorage.removeItem('vnToken');
|
sessionStorage.removeItem('vnToken');
|
||||||
this.$cookies.remove('vnToken');
|
|
||||||
this.token = null;
|
this.token = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token.$inject = ['$cookies'];
|
|
||||||
|
|
||||||
ngModule.service('vnToken', Token);
|
ngModule.service('vnToken', Token);
|
||||||
|
|
|
@ -3,7 +3,6 @@ import '@babel/polyfill';
|
||||||
import * as ng from 'angular';
|
import * as ng from 'angular';
|
||||||
export {ng};
|
export {ng};
|
||||||
|
|
||||||
import 'angular-cookies';
|
|
||||||
import 'angular-translate';
|
import 'angular-translate';
|
||||||
import 'angular-translate-loader-partial';
|
import 'angular-translate-loader-partial';
|
||||||
import '@uirouter/angularjs';
|
import '@uirouter/angularjs';
|
||||||
|
@ -11,7 +10,6 @@ import 'mg-crud';
|
||||||
import 'oclazyload';
|
import 'oclazyload';
|
||||||
|
|
||||||
export const ngDeps = [
|
export const ngDeps = [
|
||||||
'ngCookies',
|
|
||||||
'pascalprecht.translate',
|
'pascalprecht.translate',
|
||||||
'ui.router',
|
'ui.router',
|
||||||
'mgCrud',
|
'mgCrud',
|
||||||
|
|
|
@ -31,11 +31,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/angular/-/angular-1.7.5.tgz",
|
"resolved": "https://registry.npmjs.org/angular/-/angular-1.7.5.tgz",
|
||||||
"integrity": "sha512-760183yxtGzni740IBTieNuWLtPNAoMqvmC0Z62UoU0I3nqk+VJuO3JbQAXOyvo3Oy/ZsdNQwrSTh/B0OQZjNw=="
|
"integrity": "sha512-760183yxtGzni740IBTieNuWLtPNAoMqvmC0Z62UoU0I3nqk+VJuO3JbQAXOyvo3Oy/ZsdNQwrSTh/B0OQZjNw=="
|
||||||
},
|
},
|
||||||
"angular-cookies": {
|
|
||||||
"version": "1.7.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.7.5.tgz",
|
|
||||||
"integrity": "sha512-/8xvvSl/Z9Vwu8ChRm+OQE3vmli8Icwl8uTYkHqD7j7cknJP9kNaf7SgsENlsLVtOqLE/I7TCFYrSx3bmSeNQA=="
|
|
||||||
},
|
|
||||||
"angular-translate": {
|
"angular-translate": {
|
||||||
"version": "2.18.1",
|
"version": "2.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.18.1.tgz",
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
"@babel/polyfill": "^7.2.5",
|
"@babel/polyfill": "^7.2.5",
|
||||||
"@uirouter/angularjs": "^1.0.20",
|
"@uirouter/angularjs": "^1.0.20",
|
||||||
"angular": "^1.7.5",
|
"angular": "^1.7.5",
|
||||||
"angular-cookies": "^1.7.5",
|
|
||||||
"angular-translate": "^2.18.1",
|
"angular-translate": "^2.18.1",
|
||||||
"angular-translate-loader-partial": "^2.18.1",
|
"angular-translate-loader-partial": "^2.18.1",
|
||||||
"flatpickr": "^4.5.2",
|
"flatpickr": "^4.5.2",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<vn-topbar ng-if="$ctrl.inApp">
|
<vn-topbar ng-if="$ctrl.showTopbar">
|
||||||
<a class="logo" ui-sref="home" title="{{'Home' | translate}}">
|
<a class="logo" ui-sref="home" title="{{'Home' | translate}}">
|
||||||
<img src="./logo.svg" alt="Logo"></img>
|
<img src="./logo.svg" alt="Logo"></img>
|
||||||
</a>
|
</a>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
</vn-topbar>
|
</vn-topbar>
|
||||||
<div ui-view
|
<div ui-view
|
||||||
class="main-view"
|
class="main-view"
|
||||||
ng-class="{'padding': $ctrl.inApp}">
|
ng-class="{'padding': $ctrl.showTopbar}">
|
||||||
<vn-home></vn-home>
|
<vn-home></vn-home>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -2,42 +2,63 @@ import ngModule from '../../module';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
export default class App {
|
export default class App {
|
||||||
constructor($element, $scope, vnApp, $state, $transitions) {
|
constructor($, $element, vnApp, $state, $transitions) {
|
||||||
this.$element = $element;
|
Object.assign(this, {
|
||||||
this.$ = $scope;
|
$,
|
||||||
this.vnApp = vnApp;
|
$element,
|
||||||
this.$state = $state;
|
vnApp,
|
||||||
|
$state
|
||||||
|
});
|
||||||
|
|
||||||
$transitions.onStart({}, () => {
|
$transitions.onStart({}, () => {
|
||||||
if (this.menuShown) this.hideMenu();
|
if (this.menuShown) this.hideMenu();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$postLink() {
|
$postLink() {
|
||||||
this.background = this.$element[0].querySelector('.background');
|
this.vnApp.logger = this;
|
||||||
this.vnApp.snackbar = this.$.snackbar;
|
|
||||||
}
|
}
|
||||||
// TODO: Temporary fix to hide the topbar when login is displayed
|
|
||||||
get inApp() {
|
$onDestroy() {
|
||||||
|
this.vnApp.logger = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get showTopbar() {
|
||||||
let state = this.$state.current.name;
|
let state = this.$state.current.name;
|
||||||
return state && state != 'login';
|
return state && state != 'login';
|
||||||
}
|
}
|
||||||
|
|
||||||
get leftBlock() {
|
get leftBlock() {
|
||||||
return this.$element[0].querySelector('.left-block');
|
return this.$element[0].querySelector('.left-block');
|
||||||
}
|
}
|
||||||
|
|
||||||
showMenu() {
|
showMenu() {
|
||||||
let leftBlock = this.leftBlock;
|
let leftBlock = this.leftBlock;
|
||||||
if (!leftBlock) return;
|
if (!leftBlock) return;
|
||||||
leftBlock.classList.add('shown');
|
leftBlock.classList.add('shown');
|
||||||
this.menuShown = true;
|
this.menuShown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
hideMenu() {
|
hideMenu() {
|
||||||
this.menuShown = false;
|
this.menuShown = false;
|
||||||
let leftBlock = this.leftBlock;
|
let leftBlock = this.leftBlock;
|
||||||
if (!leftBlock) return;
|
if (!leftBlock) return;
|
||||||
leftBlock.classList.remove('shown');
|
leftBlock.classList.remove('shown');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showMessage(message) {
|
||||||
|
this.$.snackbar.show({message: message});
|
||||||
}
|
}
|
||||||
App.$inject = ['$element', '$scope', 'vnApp', '$state', '$transitions'];
|
|
||||||
|
showSuccess(message) {
|
||||||
|
this.$.snackbar.showSuccess({message: message});
|
||||||
|
}
|
||||||
|
|
||||||
|
showError(message) {
|
||||||
|
this.$.snackbar.showError({message: message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
App.$inject = ['$scope', '$element', 'vnApp', '$state', '$transitions'];
|
||||||
|
|
||||||
ngModule.component('vnApp', {
|
ngModule.component('vnApp', {
|
||||||
template: require('./app.html'),
|
template: require('./app.html'),
|
||||||
|
|
|
@ -5,11 +5,14 @@ import './style.scss';
|
||||||
* A simple login form.
|
* A simple login form.
|
||||||
*/
|
*/
|
||||||
export default class Controller {
|
export default class Controller {
|
||||||
constructor($element, $scope, vnAuth) {
|
constructor($, $element, vnAuth) {
|
||||||
this.$element = $element;
|
Object.assign(this, {
|
||||||
this.$ = $scope;
|
$,
|
||||||
this.vnAuth = vnAuth;
|
$element,
|
||||||
this.user = localStorage.getItem('lastUser');
|
vnAuth,
|
||||||
|
user: localStorage.getItem('lastUser'),
|
||||||
|
remember: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
submit() {
|
submit() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
@ -18,11 +21,11 @@ export default class Controller {
|
||||||
localStorage.setItem('lastUser', this.user);
|
localStorage.setItem('lastUser', this.user);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(err => {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.password = '';
|
this.password = '';
|
||||||
this.focusUser();
|
this.focusUser();
|
||||||
throw error;
|
throw err;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
focusUser() {
|
focusUser() {
|
||||||
|
@ -30,7 +33,7 @@ export default class Controller {
|
||||||
this.$.userField.focus();
|
this.$.userField.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Controller.$inject = ['$element', '$scope', 'vnAuth'];
|
Controller.$inject = ['$scope', '$element', 'vnAuth'];
|
||||||
|
|
||||||
ngModule.component('vnLogin', {
|
ngModule.component('vnLogin', {
|
||||||
template: require('./login.html'),
|
template: require('./login.html'),
|
||||||
|
|
|
@ -41,7 +41,9 @@
|
||||||
data="banksData"
|
data="banksData"
|
||||||
select-fields="['id','bank']"
|
select-fields="['id','bank']"
|
||||||
show-field="bank"
|
show-field="bank"
|
||||||
|
order="id"
|
||||||
value-field="id">
|
value-field="id">
|
||||||
|
<tpl-item>{{id}}: {{bank}}</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
|
|
|
@ -43,6 +43,9 @@ class Controller {
|
||||||
|
|
||||||
set warehouseFk(value) {
|
set warehouseFk(value) {
|
||||||
this.warehouse = value;
|
this.warehouse = value;
|
||||||
|
if (value &&
|
||||||
|
(!window.localStorage.localWarehouseFk || window.localStorage.localWarehouseFk === 'null'))
|
||||||
|
window.localStorage.defaultWarehouseFk = value;
|
||||||
this.setUserConfig('warehouseFk', value);
|
this.setUserConfig('warehouseFk', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +55,9 @@ class Controller {
|
||||||
|
|
||||||
set companyFk(value) {
|
set companyFk(value) {
|
||||||
this.company = value;
|
this.company = value;
|
||||||
|
if (value &&
|
||||||
|
(!window.localStorage.localCompanyFk || window.localStorage.localCompanyFk === 'null'))
|
||||||
|
window.localStorage.defaultCompanyFk = value;
|
||||||
this.setUserConfig('companyFk', value);
|
this.setUserConfig('companyFk', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,14 +82,14 @@ class Controller {
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.data && res.data.warehouseFk) {
|
if (res.data && res.data.warehouseFk) {
|
||||||
this.warehouse = res.data.warehouseFk;
|
this.warehouse = res.data.warehouseFk;
|
||||||
if (!localStorage.getItem('localWarehouseFk'))
|
if (res.data.warehouseFk && !window.localStorage.localWarehouseFk)
|
||||||
localStorage.setItem('defaultWarehouseFk', res.data.warehouseFk);
|
window.localStorage.defaultWarehouseFk = res.data.warehouseFk;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.data && res.data.companyFk) {
|
if (res.data && res.data.companyFk) {
|
||||||
this.company = res.data.companyFk;
|
this.company = res.data.companyFk;
|
||||||
if (!localStorage.getItem('localCompanyFk'))
|
if (res.data.companyFk && !window.localStorage.localCompanyFk)
|
||||||
localStorage.setItem('defaultCompanyFk', res.data.companyFk);
|
window.localStorage.defaultCompanyFk = res.data.companyFk;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -99,8 +105,10 @@ class Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
$onInit() {
|
$onInit() {
|
||||||
if (localStorage.getItem('localBankFk'))
|
if (window.localStorage.localBankFk && window.localStorage.localBankFk !== 'null')
|
||||||
window.localStorage.defaultBankFk = localStorage.getItem('localBankFk');
|
window.localStorage.defaultBankFk = window.localStorage.localBankFk;
|
||||||
|
else
|
||||||
|
localStorage.removeItem('defaultBankFk');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html ng-app="salix">
|
<html ng-app="salix">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=no"/>
|
||||||
|
<meta name="mobile-web-app-capable" content="yes"/>
|
||||||
<title vn-title translate></title>
|
<title vn-title translate></title>
|
||||||
<script src="/acl"></script>
|
<script src="/acl"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -5,7 +5,6 @@ Logout: Logout
|
||||||
Change language: Change language
|
Change language: Change language
|
||||||
Profile: Profile
|
Profile: Profile
|
||||||
Data saved!: Data saved!
|
Data saved!: Data saved!
|
||||||
Can't contact with server: Can't contact with server
|
|
||||||
Push on applications menu: To open a module push on applications menu
|
Push on applications menu: To open a module push on applications menu
|
||||||
Clients: Clients
|
Clients: Clients
|
||||||
Modules access: Modules access
|
Modules access: Modules access
|
|
@ -1,5 +1,4 @@
|
||||||
Applications: Aplicaciones
|
Applications: Aplicaciones
|
||||||
Can't contact with server: No se pudo contactar con el servidor
|
|
||||||
Change language: Cambiar idioma
|
Change language: Cambiar idioma
|
||||||
Client Frozen: Cliente congelado
|
Client Frozen: Cliente congelado
|
||||||
Client has debt: Cliente con riesgo
|
Client has debt: Cliente con riesgo
|
||||||
|
@ -25,6 +24,6 @@ Return to module index: Volver a la página principal del módulo
|
||||||
Routes: Rutas
|
Routes: Rutas
|
||||||
What is new: Novedades de la versión
|
What is new: Novedades de la versión
|
||||||
Web Account inactive: Sin acceso Web
|
Web Account inactive: Sin acceso Web
|
||||||
Orders: Pedidos
|
Orders: Cesta
|
||||||
Agencies: Agencias
|
Agencies: Agencias
|
||||||
Travels: Envíos
|
Travels: Envíos
|
||||||
|
|
|
@ -66,10 +66,12 @@ ngModule.config(config);
|
||||||
|
|
||||||
// Unhandled exceptions
|
// Unhandled exceptions
|
||||||
|
|
||||||
$exceptionHandler.$inject = ['vnApp', '$window', '$state'];
|
$exceptionHandler.$inject = ['vnApp', '$window', '$state', '$injector'];
|
||||||
function $exceptionHandler(vnApp, $window, $state) {
|
function $exceptionHandler(vnApp, $window, $state, $injector) {
|
||||||
return function(exception, cause) {
|
return function(exception, cause) {
|
||||||
let message;
|
let message;
|
||||||
|
let messageT;
|
||||||
|
let $translate = $injector.get('$translate');
|
||||||
|
|
||||||
if (exception.name == 'HttpError') {
|
if (exception.name == 'HttpError') {
|
||||||
switch (exception.xhrStatus) {
|
switch (exception.xhrStatus) {
|
||||||
|
@ -78,27 +80,44 @@ function $exceptionHandler(vnApp, $window, $state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (exception.status) {
|
||||||
|
case 401:
|
||||||
|
if ($state.current.name != 'login') {
|
||||||
|
messageT = 'Session has expired';
|
||||||
|
let params = {continue: $window.location.hash};
|
||||||
|
$state.go('login', params);
|
||||||
|
} else
|
||||||
|
messageT = 'Invalid login';
|
||||||
|
break;
|
||||||
|
case 403:
|
||||||
|
messageT = 'Access denied';
|
||||||
|
break;
|
||||||
|
case 502:
|
||||||
|
messageT = 'It seems that the server has fall down';
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
messageT = 'Could not contact the server';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!messageT) {
|
||||||
let data = exception.data;
|
let data = exception.data;
|
||||||
|
|
||||||
if (data && data.error instanceof Object)
|
if (data && data.error instanceof Object)
|
||||||
message = data.error.message;
|
message = data.error.message;
|
||||||
else if (exception.status === -1)
|
|
||||||
message = `Can't contact with server`;
|
|
||||||
else
|
else
|
||||||
message = `${exception.status}: ${exception.statusText}`;
|
message = `${exception.status}: ${exception.statusText}`;
|
||||||
|
|
||||||
if (exception.status === 401 && $state.current.name != 'login') {
|
|
||||||
let params = {continue: $window.location.hash};
|
|
||||||
$state.go('login', params);
|
|
||||||
}
|
}
|
||||||
} else if (exception.name == 'UserError')
|
} else if (exception.name == 'UserError')
|
||||||
message = exception.message;
|
messageT = exception.message;
|
||||||
else {
|
else {
|
||||||
vnApp.showError('Ups! Something went wrong');
|
vnApp.showError('Ups! Something went wrong');
|
||||||
console.error(exception);
|
console.error(exception);
|
||||||
throw exception;
|
throw exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (messageT)
|
||||||
|
message = $translate.instant(messageT);
|
||||||
vnApp.showError(message);
|
vnApp.showError(message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,9 +91,12 @@ dockerAndBackTest.description = `Restarts database and runs the backend tests`;
|
||||||
|
|
||||||
function backTest(done) {
|
function backTest(done) {
|
||||||
const nodemon = require('gulp-nodemon');
|
const nodemon = require('gulp-nodemon');
|
||||||
|
let gulpBin = isWindows
|
||||||
|
? 'node_modules/.bin/gulp.cmd'
|
||||||
|
: 'node_modules/.bin/gulp';
|
||||||
|
|
||||||
nodemon({
|
nodemon({
|
||||||
script: 'node_modules/.bin/gulp',
|
exec: gulpBin,
|
||||||
args: ['dockerAndBackTest'],
|
args: ['dockerAndBackTest'],
|
||||||
watch: ['loopback', 'modules/*/back/**', 'back'],
|
watch: ['loopback', 'modules/*/back/**', 'back'],
|
||||||
done: done
|
done: done
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<html ng-app="salix">
|
<html ng-app="salix">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=no"/>
|
||||||
|
<meta name="mobile-web-app-capable" content="yes"/>
|
||||||
<title vn-title translate></title>
|
<title vn-title translate></title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -1,4 +1,63 @@
|
||||||
module.exports = function(app) {
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('modelInfo', {
|
||||||
|
description: 'Gets all models information',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'ctx',
|
||||||
|
type: 'Object',
|
||||||
|
http: {source: 'context'}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: 'Object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/modelInfo`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.modelInfo = async function(ctx) {
|
||||||
|
let json = {};
|
||||||
|
let models = Self.app.models;
|
||||||
|
|
||||||
|
for (let modelName in models) {
|
||||||
|
let model = models[modelName];
|
||||||
|
let validations = model.validations;
|
||||||
|
let jsonValidations = {};
|
||||||
|
|
||||||
|
for (let fieldName in validations) {
|
||||||
|
let jsonField = [];
|
||||||
|
|
||||||
|
for (let validation of validations[fieldName]) {
|
||||||
|
let options = validation.options;
|
||||||
|
|
||||||
|
if ((options && options.async) ||
|
||||||
|
(validation.validation == 'custom' && !validation.isExportable))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let validationCp = Object.assign({}, validation);
|
||||||
|
|
||||||
|
if (validationCp.message)
|
||||||
|
validationCp.message = ctx.req.__(validationCp.message);
|
||||||
|
|
||||||
|
jsonField.push(toJson(validationCp));
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonValidations[fieldName] = jsonField;
|
||||||
|
}
|
||||||
|
|
||||||
|
json[modelName] = {
|
||||||
|
properties: model.definition.rawProperties,
|
||||||
|
validations: jsonValidations
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return json;
|
||||||
|
};
|
||||||
|
|
||||||
function toJson(object) {
|
function toJson(object) {
|
||||||
let json = {};
|
let json = {};
|
||||||
|
|
||||||
|
@ -20,44 +79,4 @@ module.exports = function(app) {
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get('/validations', function(req, res) {
|
|
||||||
let json = {};
|
|
||||||
let models = app.models;
|
|
||||||
|
|
||||||
for (let modelName in models) {
|
|
||||||
let model = models[modelName];
|
|
||||||
let validations = model.validations;
|
|
||||||
let jsonValidations = {};
|
|
||||||
|
|
||||||
for (let fieldName in validations) {
|
|
||||||
let jsonField = [];
|
|
||||||
|
|
||||||
for (let validation of validations[fieldName]) {
|
|
||||||
let options = validation.options;
|
|
||||||
|
|
||||||
if ((options && options.async) ||
|
|
||||||
(validation.validation == 'custom' && !validation.isExportable))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let validationCp = Object.assign({}, validation);
|
|
||||||
|
|
||||||
if (validationCp.message)
|
|
||||||
validationCp.message = req.__(validationCp.message);
|
|
||||||
|
|
||||||
jsonField.push(toJson(validationCp));
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonValidations[fieldName] = jsonField;
|
|
||||||
}
|
|
||||||
|
|
||||||
json[modelName] = {
|
|
||||||
properties: model.definition.rawProperties,
|
|
||||||
validations: jsonValidations
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
res.set('Content-Type', 'application/json');
|
|
||||||
res.send(JSON.stringify(json));
|
|
||||||
});
|
|
||||||
};
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
module.exports = function(Self) {
|
||||||
|
require('../methods/schema/model-info')(Self);
|
||||||
|
};
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"name": "Schema",
|
||||||
|
"base": "PersistedModel",
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"property": "validations",
|
||||||
|
"accessType": "EXECUTE",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"permission": "ALLOW"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"default": "/login",
|
|
||||||
"salix": "/login"
|
|
||||||
}
|
|
|
@ -7,4 +7,12 @@ module.exports = function(app) {
|
||||||
version: bootTimestamp
|
version: bootTimestamp
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// FIXME: Fix until the original can be used
|
||||||
|
app.get('/api/modelInfo', function(req, res) {
|
||||||
|
app.models.Schema.modelInfo({req}).then(json => {
|
||||||
|
res.set('Content-Type', 'application/json');
|
||||||
|
res.send(JSON.stringify(json));
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,5 +43,8 @@
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"Schema": {
|
||||||
|
"dataSource": "vn"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,11 +36,6 @@ let buildDir = `${appDir}/dist`;
|
||||||
let servicesDir = `${appDir}/modules`;
|
let servicesDir = `${appDir}/modules`;
|
||||||
let modulesPath = `${appDir}/modules.yml`;
|
let modulesPath = `${appDir}/modules.yml`;
|
||||||
|
|
||||||
// TODO: It should be stored at some config file
|
|
||||||
app.set('api key', 'salix');
|
|
||||||
app.set('url auth', '/auth');
|
|
||||||
app.set('applications', require('./application.json'));
|
|
||||||
|
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
|
|
||||||
// Internationalization
|
// Internationalization
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('getLanded', {
|
||||||
|
description: 'Returns the first shipped and landed possible for params',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [{
|
||||||
|
arg: 'params',
|
||||||
|
type: 'object',
|
||||||
|
required: true,
|
||||||
|
description: 'shipped, addressFk, agencyModeFk, warehouseFk'
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
type: 'object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/getLanded`,
|
||||||
|
verb: 'get'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.getLanded = async params => {
|
||||||
|
let query = `CALL vn.agencyHourGetLanded(?, ?, ?, ?);
|
||||||
|
SELECT * FROM tmp.agencyHourGetLanded`;
|
||||||
|
let result = await Self.rawSql(query, [params.shipped, params.addressFk || null, params.agencyModeFk, params.warehouseFk]);
|
||||||
|
|
||||||
|
return result[1][0].landed;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,28 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('getShipped', {
|
||||||
|
description: 'Returns the first shipped possible for params',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [{
|
||||||
|
arg: 'params',
|
||||||
|
type: 'object',
|
||||||
|
required: true,
|
||||||
|
description: 'landed, addressFk, agencyModeFk'
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
type: 'object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/getShipped`,
|
||||||
|
verb: 'get'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.getShipped = async params => {
|
||||||
|
let query = `CALL vn.agencyHourGetShipped(?, ?, ?);
|
||||||
|
SELECT * FROM tmp.agencyHourGetShipped`;
|
||||||
|
let result = await Self.rawSql(query, [params.landed, params.addressFk, params.agencyModeFk]);
|
||||||
|
|
||||||
|
return result[1][0].shipped;
|
||||||
|
};
|
||||||
|
};
|
|
@ -2,4 +2,6 @@ module.exports = Self => {
|
||||||
require('../methods/agency/landsThatDay')(Self);
|
require('../methods/agency/landsThatDay')(Self);
|
||||||
require('../methods/agency/getFirstShipped')(Self);
|
require('../methods/agency/getFirstShipped')(Self);
|
||||||
require('../methods/agency/getAgenciesWithWarehouse')(Self);
|
require('../methods/agency/getAgenciesWithWarehouse')(Self);
|
||||||
|
require('../methods/agency/getLanded')(Self);
|
||||||
|
require('../methods/agency/getShipped')(Self);
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,6 +24,7 @@ class Controller {
|
||||||
this.$state.go('zone.index');
|
this.$state.go('zone.index');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
console.log('res', response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,15 @@
|
||||||
<a translate-attr="{title: 'Preview'}" ui-sref="claim.card.summary({id: $ctrl.claim.id})">
|
<a translate-attr="{title: 'Preview'}" ui-sref="claim.card.summary({id: $ctrl.claim.id})">
|
||||||
<vn-icon icon="desktop_windows"></vn-icon>
|
<vn-icon icon="desktop_windows"></vn-icon>
|
||||||
</a>
|
</a>
|
||||||
<div></div>
|
<vn-icon-menu
|
||||||
|
vn-id="more-button"
|
||||||
|
icon="more_vert"
|
||||||
|
show-filter="false"
|
||||||
|
value-field="callback"
|
||||||
|
translate-fields="['name']"
|
||||||
|
data="$ctrl.moreOptions"
|
||||||
|
on-change="$ctrl.onMoreChange(value)">
|
||||||
|
</vn-icon-menu>
|
||||||
</div>
|
</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="attributes">
|
<div class="attributes">
|
||||||
|
@ -58,3 +66,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<vn-confirm
|
||||||
|
vn-id="confirm-dialog"
|
||||||
|
on-response="$ctrl.returnDialog(response)"
|
||||||
|
question="Pickup order"
|
||||||
|
message="Do you want to send it directly?">
|
||||||
|
</vn-confirm>
|
|
@ -1,8 +1,15 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
|
|
||||||
class Controller {
|
class Controller {
|
||||||
constructor($state) {
|
constructor($scope, $state, $http, $translate, vnApp) {
|
||||||
|
this.$scope = $scope;
|
||||||
this.$state = $state;
|
this.$state = $state;
|
||||||
|
this.$http = $http;
|
||||||
|
this.$translate = $translate;
|
||||||
|
this.vnApp = vnApp;
|
||||||
|
this.moreOptions = [
|
||||||
|
{callback: this.showConfirmDialog, name: 'Pickup order'}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
get claim() {
|
get claim() {
|
||||||
|
@ -30,9 +37,28 @@ class Controller {
|
||||||
get quicklinks() {
|
get quicklinks() {
|
||||||
return this._quicklinks;
|
return this._quicklinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMoreChange(callback) {
|
||||||
|
callback.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.$inject = ['$state'];
|
showConfirmDialog() {
|
||||||
|
this.$scope.confirmDialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
returnDialog(response) {
|
||||||
|
if (response === 'CANCEL') {
|
||||||
|
let url = `/report/rpt-claim-pickup-order?claimFk=${this.claim.id}`;
|
||||||
|
window.open(url);
|
||||||
|
} else if (response === 'ACCEPT') {
|
||||||
|
this.$http.post(`/email/claim-pickup-order`, {claimFk: this.claim.id}).then(
|
||||||
|
() => this.vnApp.showMessage(this.$translate.instant('Notification sent!'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.$inject = ['$scope', '$state', '$http', '$translate', 'vnApp'];
|
||||||
|
|
||||||
ngModule.component('vnClaimDescriptor', {
|
ngModule.component('vnClaimDescriptor', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
|
|
|
@ -7,6 +7,8 @@ Remove sale: Borrar linea
|
||||||
Claim Id: Id reclamación
|
Claim Id: Id reclamación
|
||||||
Created: Creado
|
Created: Creado
|
||||||
Enter a new search: Introduce una nueva búsqueda
|
Enter a new search: Introduce una nueva búsqueda
|
||||||
|
Pickup order: Orden de recogida
|
||||||
|
Do you want to send it directly?: ¿Quieres enviarlo directamente?
|
||||||
|
|
||||||
#sections
|
#sections
|
||||||
Claims: Reclamaciones
|
Claims: Reclamaciones
|
||||||
|
|
|
@ -23,10 +23,9 @@ class Controller {
|
||||||
if (this.$stateParams.amountPaid)
|
if (this.$stateParams.amountPaid)
|
||||||
this.receipt.amountPaid = this.$stateParams.amountPaid;
|
this.receipt.amountPaid = this.$stateParams.amountPaid;
|
||||||
|
|
||||||
if (this.$stateParams.companyFk) {
|
if (this.$stateParams.companyFk)
|
||||||
this.receipt.companyFk = this.$stateParams.companyFk;
|
this.receipt.companyFk = this.$stateParams.companyFk;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$onInit() {
|
$onInit() {
|
||||||
let filter = {
|
let filter = {
|
||||||
|
|
|
@ -3,12 +3,13 @@
|
||||||
url="/client/api/receipts/filter"
|
url="/client/api/receipts/filter"
|
||||||
params="$ctrl.params"
|
params="$ctrl.params"
|
||||||
limit="20"
|
limit="20"
|
||||||
data="$ctrl.risks">
|
data="$ctrl.risks"
|
||||||
|
auto-load="true">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<vn-crud-model
|
<vn-crud-model
|
||||||
vn-id="riskModel"
|
vn-id="riskModel"
|
||||||
url="/client/api/ClientRisks"
|
url="/client/api/ClientRisks"
|
||||||
filter="::$ctrl.filter"
|
filter="$ctrl.filter"
|
||||||
data="riskTotal"
|
data="riskTotal"
|
||||||
auto-load="true">
|
auto-load="true">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
|
|
|
@ -18,6 +18,7 @@ class Controller {
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
clientFk: $stateParams.id,
|
clientFk: $stateParams.id,
|
||||||
|
companyFk: this.companyFk
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this.params = {
|
this.params = {
|
||||||
|
@ -29,7 +30,9 @@ class Controller {
|
||||||
}
|
}
|
||||||
setOrder(value) {
|
setOrder(value) {
|
||||||
this.params.params.companyFk = value;
|
this.params.params.companyFk = value;
|
||||||
|
this.filter.where.companyFk = value;
|
||||||
this.$.model.refresh();
|
this.$.model.refresh();
|
||||||
|
this.$.riskModel.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
set risks(value) {
|
set risks(value) {
|
||||||
|
|
|
@ -57,6 +57,24 @@ module.exports = Self => {
|
||||||
throw new UserError(`You can't create a ticket for a client that has a debt`);
|
throw new UserError(`You can't create a ticket for a client that has a debt`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!params.shipped && params.landed) {
|
||||||
|
params.shipped = await Self.app.models.Agency.getShipped({
|
||||||
|
landed: params.landed,
|
||||||
|
addressFk: address.id,
|
||||||
|
agencyModeFk: params.agencyModeFk
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.shipped && !params.landed) {
|
||||||
|
params.landed = await Self.app.models.Agency.getLanded({
|
||||||
|
shipped: params.shipped,
|
||||||
|
addressFk: address.id,
|
||||||
|
agencyModeFk: params.agencyModeFk,
|
||||||
|
warehouseFk: params.warehouseFk
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!params.userId && ctx.req && ctx.req.accessToken.userId)
|
if (!params.userId && ctx.req && ctx.req.accessToken.userId)
|
||||||
params.userId = ctx.req.accessToken.userId;
|
params.userId = ctx.req.accessToken.userId;
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
ini-options="{enableTime: false}">
|
ini-options="{enableTime: false}">
|
||||||
</vn-date-picker>
|
</vn-date-picker>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
disabled="!$ctrl.clientFk || !$ctrl.landed"
|
disabled="!$ctrl.warehouseFk && (!$ctrl.clientFk || !$ctrl.landed)"
|
||||||
field="$ctrl.warehouseFk"
|
field="$ctrl.warehouseFk"
|
||||||
url="/agency/api/Warehouses"
|
url="/agency/api/Warehouses"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
|
|
|
@ -14,6 +14,9 @@ class Controller {
|
||||||
$onInit() {
|
$onInit() {
|
||||||
if (this.$stateParams && this.$stateParams.clientFk)
|
if (this.$stateParams && this.$stateParams.clientFk)
|
||||||
this.clientFk = this.$stateParams.clientFk;
|
this.clientFk = this.$stateParams.clientFk;
|
||||||
|
|
||||||
|
if (window.localStorage && window.localStorage.defaultWarehouseFk)
|
||||||
|
this.warehouseFk = parseInt(window.localStorage.defaultWarehouseFk);
|
||||||
}
|
}
|
||||||
|
|
||||||
set ticket(value) {
|
set ticket(value) {
|
||||||
|
@ -37,6 +40,7 @@ class Controller {
|
||||||
});
|
});
|
||||||
} else
|
} else
|
||||||
this.addressFk = null;
|
this.addressFk = null;
|
||||||
|
this.getAvailableAgencies();
|
||||||
}
|
}
|
||||||
|
|
||||||
get clientFk() {
|
get clientFk() {
|
||||||
|
@ -45,6 +49,7 @@ class Controller {
|
||||||
|
|
||||||
set addressFk(value) {
|
set addressFk(value) {
|
||||||
this.ticket.addressFk = value;
|
this.ticket.addressFk = value;
|
||||||
|
this.getAvailableAgencies();
|
||||||
}
|
}
|
||||||
|
|
||||||
get addressFk() {
|
get addressFk() {
|
||||||
|
@ -53,6 +58,7 @@ class Controller {
|
||||||
|
|
||||||
set landed(value) {
|
set landed(value) {
|
||||||
this.ticket.landed = value;
|
this.ticket.landed = value;
|
||||||
|
this.getAvailableAgencies();
|
||||||
}
|
}
|
||||||
|
|
||||||
get landed() {
|
get landed() {
|
||||||
|
@ -67,10 +73,9 @@ class Controller {
|
||||||
return this.ticket.warehouseFk;
|
return this.ticket.warehouseFk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getAvailableAgencies() {
|
getAvailableAgencies() {
|
||||||
|
if (this.ticket.warehouseFk && this.ticket.addressFk && this.ticket.landed && this.ticket.clientFk) {
|
||||||
this.ticket.agencyModeFk = null;
|
this.ticket.agencyModeFk = null;
|
||||||
if (this.ticket.landed && this.ticket.addressFk) {
|
|
||||||
let filter = {warehouseFk: this.ticket.warehouseFk, addressFk: this.ticket.addressFk, landed: this.ticket.landed};
|
let filter = {warehouseFk: this.ticket.warehouseFk, addressFk: this.ticket.addressFk, landed: this.ticket.landed};
|
||||||
filter = encodeURIComponent(JSON.stringify(filter));
|
filter = encodeURIComponent(JSON.stringify(filter));
|
||||||
let query = `/api/Agencies/getAgenciesWithWarehouse?filter=${filter}`;
|
let query = `/api/Agencies/getAgenciesWithWarehouse?filter=${filter}`;
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
.container {
|
||||||
|
font-family: verdana, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
zoom: 0.55
|
||||||
|
}
|
||||||
|
|
||||||
.columns {
|
.columns {
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
}
|
}
|
||||||
|
@ -27,46 +33,6 @@
|
||||||
float: left
|
float: left
|
||||||
}
|
}
|
||||||
|
|
||||||
.pull-left {
|
|
||||||
float: left
|
|
||||||
}
|
|
||||||
|
|
||||||
.pull-right {
|
|
||||||
float: right
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid {
|
|
||||||
border-bottom: 3px solid #888888
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid .row {
|
|
||||||
padding: 5px;
|
|
||||||
margin-bottom: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid .header {
|
|
||||||
border-bottom: 1px solid #808080;
|
|
||||||
border-top: 1px solid #808080;
|
|
||||||
background-color: #c0c0c0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.grid .row.inline > div {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.panel {
|
|
||||||
border: 1px solid #DDD;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
position: relative;
|
|
||||||
padding:10px
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel .header {
|
|
||||||
font-weight: bold
|
|
||||||
}
|
|
||||||
|
|
||||||
.row {
|
.row {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
|
@ -139,6 +105,37 @@
|
||||||
overflow: visible
|
overflow: visible
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
border-bottom: 3px solid #888888
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid .row {
|
||||||
|
padding: 5px;
|
||||||
|
margin-bottom: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid .header {
|
||||||
|
border-bottom: 1px solid #808080;
|
||||||
|
border-top: 1px solid #808080;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.grid .row.inline > div {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
border: 1px solid #DDD;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
position: relative;
|
||||||
|
padding:10px
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel .header {
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
.box {
|
.box {
|
||||||
border-top: 1px solid #CCC;
|
border-top: 1px solid #CCC;
|
||||||
border-right: 1px solid #CCC;
|
border-right: 1px solid #CCC;
|
||||||
|
@ -164,22 +161,3 @@
|
||||||
.pull-right {
|
.pull-right {
|
||||||
float: right
|
float: right
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid {
|
|
||||||
border-bottom: 3px solid #888888
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid .row {
|
|
||||||
padding: 5px;
|
|
||||||
margin-bottom: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid .header {
|
|
||||||
border-bottom: 1px solid #808080;
|
|
||||||
border-top: 1px solid #808080;
|
|
||||||
background-color: #c0c0c0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid .row.inline > div {
|
|
||||||
float: left;
|
|
||||||
}
|
|
|
@ -4,9 +4,10 @@
|
||||||
{"type": "email", "name": "payment-update"},
|
{"type": "email", "name": "payment-update"},
|
||||||
{"type": "email", "name": "letter-debtor-st"},
|
{"type": "email", "name": "letter-debtor-st"},
|
||||||
{"type": "email", "name": "letter-debtor-nd"},
|
{"type": "email", "name": "letter-debtor-nd"},
|
||||||
|
{"type": "email", "name": "claim-pickup-order"},
|
||||||
{"type": "report", "name": "delivery-note"},
|
{"type": "report", "name": "delivery-note"},
|
||||||
{"type": "report", "name": "invoice"},
|
{"type": "report", "name": "invoice"},
|
||||||
{"type": "report", "name": "claim-pickup"},
|
{"type": "report", "name": "rpt-claim-pickup-order"},
|
||||||
{"type": "static", "name": "email-header"},
|
{"type": "static", "name": "email-header"},
|
||||||
{"type": "static", "name": "email-footer"},
|
{"type": "static", "name": "email-footer"},
|
||||||
{"type": "static", "name": "report-header"},
|
{"type": "static", "name": "report-header"},
|
||||||
|
|
|
@ -4,18 +4,16 @@ const renderer = require('vue-server-renderer').createRenderer();
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const juice = require('juice');
|
const juice = require('juice');
|
||||||
const smtp = require('./smtp');
|
const smtp = require('./smtp');
|
||||||
const i18n = new VueI18n({
|
const fallbackLocale = 'es';
|
||||||
locale: 'es',
|
|
||||||
});
|
|
||||||
|
|
||||||
Vue.use(VueI18n);
|
|
||||||
|
|
||||||
if (!process.env.OPENSSL_CONF)
|
if (!process.env.OPENSSL_CONF)
|
||||||
process.env.OPENSSL_CONF = '/etc/ssl/';
|
process.env.OPENSSL_CONF = '/etc/ssl/';
|
||||||
|
|
||||||
|
Vue.use(VueI18n);
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
path: `${appPath}/reports`,
|
path: `${appPath}/report`,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a report component
|
* Renders a report component
|
||||||
|
@ -25,17 +23,18 @@ module.exports = {
|
||||||
*/
|
*/
|
||||||
async render(name, ctx) {
|
async render(name, ctx) {
|
||||||
const component = require(`${this.path}/${name}`);
|
const component = require(`${this.path}/${name}`);
|
||||||
const prefetchedData = await this.preFetch(component, ctx);
|
const result = await this.preFetch(component, ctx);
|
||||||
|
const i18n = new VueI18n({
|
||||||
const app = new Vue({
|
locale: 'es',
|
||||||
i18n,
|
fallbackLocale
|
||||||
render: h => h(component),
|
|
||||||
});
|
});
|
||||||
|
const app = new Vue({i18n,
|
||||||
|
render: h => h(result.component)});
|
||||||
|
|
||||||
return renderer.renderToString(app).then(renderedHtml => {
|
return renderer.renderToString(app).then(renderedHtml => {
|
||||||
return {
|
return {
|
||||||
html: renderedHtml,
|
html: renderedHtml,
|
||||||
data: prefetchedData,
|
data: result.mergedData,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -43,10 +42,11 @@ module.exports = {
|
||||||
/**
|
/**
|
||||||
* Prefetch all component data from asyncData method
|
* Prefetch all component data from asyncData method
|
||||||
*
|
*
|
||||||
* @param {Object} component - Component object
|
* @param {Object} orgComponent - Component object
|
||||||
* @param {Object} ctx - Request context
|
* @param {Object} ctx - Request context
|
||||||
*/
|
*/
|
||||||
async preFetch(component, ctx) {
|
async preFetch(orgComponent, ctx) {
|
||||||
|
let component = Object.create(orgComponent);
|
||||||
let mergedData = {attachments: []};
|
let mergedData = {attachments: []};
|
||||||
let asyncData = {};
|
let asyncData = {};
|
||||||
let data = {};
|
let data = {};
|
||||||
|
@ -60,14 +60,18 @@ module.exports = {
|
||||||
|
|
||||||
await this.attachAssets(component);
|
await this.attachAssets(component);
|
||||||
|
|
||||||
if (component.hasOwnProperty('data'))
|
if (orgComponent.hasOwnProperty('data'))
|
||||||
data = component.data();
|
data = orgComponent.data();
|
||||||
|
|
||||||
if (component.hasOwnProperty('asyncData')) {
|
if (orgComponent.hasOwnProperty('asyncData')) {
|
||||||
asyncData = await component.asyncData(ctx, params);
|
asyncData = await orgComponent.asyncData(ctx, params);
|
||||||
|
|
||||||
if (asyncData.locale) {
|
if (asyncData.locale) {
|
||||||
const locale = component.i18n.messages[asyncData.locale];
|
let locale = component.i18n.messages[asyncData.locale];
|
||||||
|
|
||||||
|
if (!locale)
|
||||||
|
locale = component.i18n.messages[fallbackLocale];
|
||||||
|
|
||||||
mergedData.subject = locale.subject;
|
mergedData.subject = locale.subject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +85,7 @@ module.exports = {
|
||||||
if (data.hasOwnProperty('files')) {
|
if (data.hasOwnProperty('files')) {
|
||||||
const files = data.files;
|
const files = data.files;
|
||||||
files.forEach(file => {
|
files.forEach(file => {
|
||||||
const componentPath = `${this.path}/${component.name}`;
|
const componentPath = `${this.path}/${orgComponent.name}`;
|
||||||
let fileSrc = componentPath + file;
|
let fileSrc = componentPath + file;
|
||||||
|
|
||||||
if (file.slice(0, 4) === 'http' || file.slice(0, 4) === 'https')
|
if (file.slice(0, 4) === 'http' || file.slice(0, 4) === 'https')
|
||||||
|
@ -96,25 +100,30 @@ module.exports = {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (component.components) {
|
const components = orgComponent.components;
|
||||||
const components = component.components;
|
|
||||||
const promises = [];
|
|
||||||
|
|
||||||
Object.keys(components).forEach(component => {
|
if (components) {
|
||||||
promises.push(this.preFetch(components[component], ctx));
|
const promises = [];
|
||||||
|
const childNames = [];
|
||||||
|
component.components = {};
|
||||||
|
|
||||||
|
Object.keys(components).forEach(childName => {
|
||||||
|
childNames.push(childName);
|
||||||
|
promises.push(this.preFetch(components[childName], ctx));
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(promises).then(results => {
|
await Promise.all(promises).then(results => {
|
||||||
results.forEach(result => {
|
results.forEach((result, i) => {
|
||||||
result.attachments.forEach(atth => {
|
result.mergedData.attachments.forEach(atth => {
|
||||||
mergedData.attachments.push(atth);
|
mergedData.attachments.push(atth);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
component.components[childNames[i]] = result.component;
|
||||||
});
|
});
|
||||||
return mergedData;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return mergedData;
|
return {component, mergedData};
|
||||||
},
|
},
|
||||||
|
|
||||||
async attachAssets(component) {
|
async attachAssets(component) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ if (!process.env.OPENSSL_CONF)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
path: `${appPath}/reports`,
|
path: `${appPath}/report`,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a report component
|
* Renders a report component
|
||||||
|
@ -23,16 +23,13 @@ module.exports = {
|
||||||
*/
|
*/
|
||||||
async render(name, ctx) {
|
async render(name, ctx) {
|
||||||
const component = require(`${this.path}/${name}`);
|
const component = require(`${this.path}/${name}`);
|
||||||
|
const result = await this.preFetch(component, ctx);
|
||||||
await this.preFetch(component, ctx);
|
|
||||||
|
|
||||||
const i18n = new VueI18n({
|
const i18n = new VueI18n({
|
||||||
locale: 'es',
|
locale: 'es',
|
||||||
|
fallbackLocale: 'en'
|
||||||
});
|
});
|
||||||
const app = new Vue({
|
const app = new Vue({i18n,
|
||||||
i18n,
|
render: h => h(result.component)});
|
||||||
render: h => h(component),
|
|
||||||
});
|
|
||||||
|
|
||||||
return renderer.renderToString(app);
|
return renderer.renderToString(app);
|
||||||
},
|
},
|
||||||
|
@ -40,10 +37,11 @@ module.exports = {
|
||||||
/**
|
/**
|
||||||
* Prefetch all component data from asyncData method
|
* Prefetch all component data from asyncData method
|
||||||
*
|
*
|
||||||
* @param {Object} component - Component object
|
* @param {Object} orgComponent - Component object
|
||||||
* @param {Object} ctx - Request context
|
* @param {Object} ctx - Request context
|
||||||
*/
|
*/
|
||||||
async preFetch(component, ctx) {
|
async preFetch(orgComponent, ctx) {
|
||||||
|
let component = Object.create(orgComponent);
|
||||||
let mergedData = {};
|
let mergedData = {};
|
||||||
let asyncData = {};
|
let asyncData = {};
|
||||||
let data = {};
|
let data = {};
|
||||||
|
@ -57,11 +55,11 @@ module.exports = {
|
||||||
|
|
||||||
await this.attachAssets(component);
|
await this.attachAssets(component);
|
||||||
|
|
||||||
if (component.hasOwnProperty('data'))
|
if (orgComponent.hasOwnProperty('data'))
|
||||||
data = component.data();
|
data = orgComponent.data();
|
||||||
|
|
||||||
if (component.hasOwnProperty('asyncData'))
|
if (orgComponent.hasOwnProperty('asyncData'))
|
||||||
asyncData = await component.asyncData(ctx, params);
|
asyncData = await orgComponent.asyncData(ctx, params);
|
||||||
|
|
||||||
mergedData = Object.assign(mergedData, data, asyncData);
|
mergedData = Object.assign(mergedData, data, asyncData);
|
||||||
|
|
||||||
|
@ -69,16 +67,25 @@ module.exports = {
|
||||||
return mergedData;
|
return mergedData;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (component.components) {
|
const components = orgComponent.components;
|
||||||
const components = component.components;
|
if (components) {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
const childNames = [];
|
||||||
|
component.components = {};
|
||||||
|
|
||||||
Object.keys(components).forEach(component => {
|
Object.keys(components).forEach(childName => {
|
||||||
promises.push(this.preFetch(components[component], ctx));
|
childNames.push(childName);
|
||||||
|
promises.push(this.preFetch(components[childName], ctx));
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(promises);
|
await Promise.all(promises).then(results => {
|
||||||
|
results.forEach((result, i) => {
|
||||||
|
component.components[childNames[i]] = result.component;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {component};
|
||||||
},
|
},
|
||||||
|
|
||||||
async attachAssets(component) {
|
async attachAssets(component) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ const express = require('express');
|
||||||
const routes = require(`../config/routes.json`);
|
const routes = require(`../config/routes.json`);
|
||||||
|
|
||||||
module.exports = app => {
|
module.exports = app => {
|
||||||
this.path = `${appPath}/reports`;
|
this.path = `${appPath}/report`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables a report
|
* Enables a report
|
||||||
|
@ -15,10 +15,9 @@ module.exports = app => {
|
||||||
if (!name) throw new Error('Report name required');
|
if (!name) throw new Error('Report name required');
|
||||||
|
|
||||||
app.get(`/report/${name}`, (request, response, next) => {
|
app.get(`/report/${name}`, (request, response, next) => {
|
||||||
|
reportEngine.toPdf(name, request).then(stream => {
|
||||||
response.setHeader('Content-Disposition', `attachment; filename="${name}.pdf"`);
|
response.setHeader('Content-Disposition', `attachment; filename="${name}.pdf"`);
|
||||||
response.setHeader('Content-type', 'application/pdf');
|
response.setHeader('Content-type', 'application/pdf');
|
||||||
|
|
||||||
reportEngine.toPdf(name, request).then(stream => {
|
|
||||||
stream.pipe(response);
|
stream.pipe(response);
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
next(e);
|
next(e);
|
||||||
|
|
|
@ -3,10 +3,8 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
font-family: arial, sans-serif;
|
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
font-size: 16px;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
color: #555
|
color: #555
|
||||||
}
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="es">
|
||||||
|
<head>
|
||||||
|
<title>{{ $t('subject') }}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="container">
|
||||||
|
<email-header></email-header>
|
||||||
|
<section class="main">
|
||||||
|
<!-- Title block -->
|
||||||
|
<div class="title">
|
||||||
|
<h1>{{ $t('title') }}</h1>
|
||||||
|
</div>
|
||||||
|
<!-- Title block end -->
|
||||||
|
|
||||||
|
<p>{{$t('description.dear')}},</p>
|
||||||
|
<p>{{$t('description.instructions')}}</p>
|
||||||
|
|
||||||
|
<!-- <h1>{{$t('sections.howToBuy.title')}}</h1>
|
||||||
|
<p>{{$t('sections.howToBuy.description')}}</p>
|
||||||
|
<ol>
|
||||||
|
<li v-for="requeriment in $t('sections.howToBuy.requeriments')">
|
||||||
|
<span v-html="requeriment"></span>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<p>{{$t('sections.howToBuy.stock')}}</p>
|
||||||
|
<p>{{$t('sections.howToBuy.delivery')}}</p> -->
|
||||||
|
</section>
|
||||||
|
<email-footer></email-footer>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,52 @@
|
||||||
|
const UserException = require(`${appPath}/lib/exceptions/userException`);
|
||||||
|
const reportEngine = require(`${appPath}/lib/reportEngine`);
|
||||||
|
const database = require(`${appPath}/lib/database`);
|
||||||
|
const emailHeader = require('../email-header');
|
||||||
|
const emailFooter = require('../email-footer');
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'claim-pickup-order',
|
||||||
|
async asyncData(ctx, params) {
|
||||||
|
const promises = [];
|
||||||
|
const data = {
|
||||||
|
isPreview: ctx.method === 'GET',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!params.claimFk)
|
||||||
|
throw new UserException('No claim id specified');
|
||||||
|
|
||||||
|
promises.push(reportEngine.toPdf('rpt-claim-pickup-order', ctx));
|
||||||
|
promises.push(this.methods.fetchClient(params.claimFk));
|
||||||
|
|
||||||
|
return Promise.all(promises).then(result => {
|
||||||
|
const stream = result[0];
|
||||||
|
const [[client]] = result[1];
|
||||||
|
|
||||||
|
Object.assign(data, client);
|
||||||
|
Object.assign(data, {attachments: [{filename: 'claim-pickup-order.pdf', content: stream}]});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.$i18n.locale = this.locale;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchClient(claimFk) {
|
||||||
|
return database.pool.query(`
|
||||||
|
SELECT
|
||||||
|
c.id,
|
||||||
|
u.lang locale,
|
||||||
|
c.email recipient
|
||||||
|
FROM claim cl
|
||||||
|
JOIN client c ON c.id = cl.clientFk
|
||||||
|
JOIN account.user u ON u.id = c.id
|
||||||
|
WHERE cl.id = ?`, [claimFk]);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
emailHeader,
|
||||||
|
emailFooter,
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,25 @@
|
||||||
|
module.exports = {
|
||||||
|
messages: {
|
||||||
|
es: {
|
||||||
|
subject: 'Orden de recogida',
|
||||||
|
title: 'Orden de recogida',
|
||||||
|
description: {
|
||||||
|
dear: 'Estimado cliente',
|
||||||
|
instructions: 'Aqui tienes tu orden de recogida.'
|
||||||
|
},
|
||||||
|
sections: {
|
||||||
|
howToBuy: {
|
||||||
|
title: 'Cómo hacer un pedido',
|
||||||
|
description: `Para realizar un pedido en nuestra web,
|
||||||
|
debes configurarlo indicando:`,
|
||||||
|
requeriments: [
|
||||||
|
'Si quieres recibir el pedido (por agencia o por nuestro propio reparto) o si lo prefieres recoger en alguno de nuestros almacenes.',
|
||||||
|
'La fecha en la que quieres recibir el pedido (se preparará el día anterior).',
|
||||||
|
'La dirección de entrega o el almacén donde quieres recoger el pedido.'],
|
||||||
|
stock: 'En nuestra web y aplicaciones puedes visualizar el stock disponible de flor cortada, verdes, plantas, complementos y artificial. Ten 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.',
|
||||||
|
delivery: 'El reparto se realiza de lunes a sábado según la zona en la que te encuentres. 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.',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
|
@ -3,10 +3,8 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
font-family: arial, sans-serif;
|
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
font-size: 16px;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
color: #555
|
color: #555
|
||||||
}
|
}
|
|
@ -15,6 +15,8 @@ module.exports = {
|
||||||
|
|
||||||
return this.methods.fetchClient(params.clientFk)
|
return this.methods.fetchClient(params.clientFk)
|
||||||
.then(([result]) => {
|
.then(([result]) => {
|
||||||
|
if (!result)
|
||||||
|
throw new UserException('No client data found');
|
||||||
return Object.assign(data, result[0]);
|
return Object.assign(data, result[0]);
|
||||||
});
|
});
|
||||||
},
|
},
|
|
@ -1,11 +1,3 @@
|
||||||
footer {
|
|
||||||
font-family: arial, sans-serif;
|
|
||||||
max-width: 600px;
|
|
||||||
min-width: 320px;
|
|
||||||
font-size: 16px;
|
|
||||||
margin: 0 auto
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons {
|
.buttons {
|
||||||
background-color: #FFF;
|
background-color: #FFF;
|
||||||
text-align: center;
|
text-align: center;
|
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: 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 |
|
@ -0,0 +1,7 @@
|
||||||
|
header {
|
||||||
|
color: #555
|
||||||
|
}
|
||||||
|
|
||||||
|
header img {
|
||||||
|
width: 100%
|
||||||
|
}
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
@ -0,0 +1,6 @@
|
||||||
|
const CssReader = require(`${appPath}/lib/cssReader`);
|
||||||
|
|
||||||
|
module.exports = new CssReader([
|
||||||
|
`${appPath}/common/css/layout.css`,
|
||||||
|
`${__dirname}/style.css`])
|
||||||
|
.mergeStyles();
|
|
@ -0,0 +1,39 @@
|
||||||
|
body {
|
||||||
|
background-color: #EEE
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 600px;
|
||||||
|
min-width: 320px;
|
||||||
|
margin: 0 auto;
|
||||||
|
color: #555
|
||||||
|
}
|
||||||
|
.main {
|
||||||
|
background-color: #FFF;
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.main a {
|
||||||
|
color: #8dba25
|
||||||
|
}
|
||||||
|
|
||||||
|
.main h1 {
|
||||||
|
color: #999
|
||||||
|
}
|
||||||
|
|
||||||
|
.main h3 {
|
||||||
|
font-size: 16px
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
background-color: #95d831;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-align: center;
|
||||||
|
padding: 35px 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.title h1 {
|
||||||
|
font-size: 32px;
|
||||||
|
color: #333;
|
||||||
|
margin: 0
|
||||||
|
}
|
|
@ -15,6 +15,8 @@ module.exports = {
|
||||||
|
|
||||||
return this.methods.fetchClientData(params.clientFk)
|
return this.methods.fetchClientData(params.clientFk)
|
||||||
.then(([result]) => {
|
.then(([result]) => {
|
||||||
|
if (!result)
|
||||||
|
throw new UserException('No client data found');
|
||||||
return Object.assign(data, result[0]);
|
return Object.assign(data, result[0]);
|
||||||
});
|
});
|
||||||
},
|
},
|
|
@ -0,0 +1,6 @@
|
||||||
|
const CssReader = require(`${appPath}/lib/cssReader`);
|
||||||
|
|
||||||
|
module.exports = new CssReader([
|
||||||
|
`${appPath}/common/css/layout.css`,
|
||||||
|
`${__dirname}/style.css`])
|
||||||
|
.mergeStyles();
|
|
@ -3,10 +3,8 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
font-family: arial, sans-serif;
|
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
font-size: 16px;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
color: #555
|
color: #555
|
||||||
}
|
}
|