This commit is contained in:
Carlos Jimenez Ruiz 2019-02-19 08:16:36 +01:00
commit 2d2ce304b5
35 changed files with 1715 additions and 990 deletions

39
Jenkinsfile vendored
View File

@ -6,6 +6,7 @@ pipeline {
disableConcurrentBuilds() disableConcurrentBuilds()
} }
environment { environment {
PROJECT_NAME = 'salix'
REGISTRY = 'registry.verdnatura.es' REGISTRY = 'registry.verdnatura.es'
DOCKER_HOST_1 = 'vch1.verdnatura.es' DOCKER_HOST_1 = 'vch1.verdnatura.es'
DOCKER_HOST_2 = 'vch2.verdnatura.es' DOCKER_HOST_2 = 'vch2.verdnatura.es'
@ -15,7 +16,7 @@ pipeline {
stage('Checkout') { stage('Checkout') {
steps { steps {
script { script {
env.COMPOSE_PROJECT_NAME = env.JOB_NAME.replace('/', '-') env.COMPOSE_PROJECT_NAME = "${env.PROJECT_NAME}-${env.BRANCH_NAME}"
env.GIT_COMMITTER_EMAIL = sh( env.GIT_COMMITTER_EMAIL = sh(
script: 'git --no-pager show -s --format="%ae"', script: 'git --no-pager show -s --format="%ae"',
returnStdout: true returnStdout: true
@ -28,9 +29,6 @@ pipeline {
case 'test': case 'test':
env.PORT = 5001 env.PORT = 5001
break break
case 'test':
env.PORT = 5000
break
} }
switch (env.BRANCH_NAME) { switch (env.BRANCH_NAME) {
case 'master': case 'master':
@ -39,9 +37,6 @@ pipeline {
case 'test': case 'test':
env.NODE_ENV = 'test' env.NODE_ENV = 'test'
break break
case 'dev':
env.NODE_ENV = 'development'
break
} }
} }
echo "Committer: ${env.GIT_COMMITTER_EMAIL}" echo "Committer: ${env.GIT_COMMITTER_EMAIL}"
@ -59,9 +54,10 @@ pipeline {
} }
} }
stage('Test') { stage('Test') {
when { when { not { anyOf {
branch 'dev' branch 'test'
} branch 'master'
}}}
environment { environment {
NODE_ENV = "" NODE_ENV = ""
FIREFOX_BIN = "/opt/firefox/firefox-bin" FIREFOX_BIN = "/opt/firefox/firefox-bin"
@ -75,9 +71,10 @@ pipeline {
} }
} }
stage('Build') { stage('Build') {
when { when { anyOf {
not { branch 'dev' } branch 'test'
} branch 'master'
}}
environment { environment {
CREDS = credentials('docker-registry') CREDS = credentials('docker-registry')
} }
@ -92,9 +89,10 @@ pipeline {
} }
} }
stage('Deploy') { stage('Deploy') {
when { when { anyOf {
not { branch 'dev' } branch 'test'
} branch 'master'
}}
environment { environment {
DOCKER_TLS_VERIFY = 1 DOCKER_TLS_VERIFY = 1
} }
@ -124,9 +122,10 @@ pipeline {
} }
} }
stage('Cleanup') { stage('Cleanup') {
when { when { anyOf {
not { branch 'dev' } branch 'test'
} branch 'master'
}}
steps { steps {
sh 'docker logout $REGISTRY' sh 'docker logout $REGISTRY'
} }
@ -135,7 +134,7 @@ pipeline {
post { post {
always { always {
script { script {
if (env.BRANCH_NAME == 'dev') { if (!['master', 'test'].contains(env.BRANCH_NAME)) {
try { try {
junit '*/junitresults.xml' junit '*/junitresults.xml'
junit 'junitresults.xml' junit 'junitresults.xml'

View File

@ -19,5 +19,11 @@
"expired": { "expired": {
"type": "date" "type": "date"
} }
},
"scope": {
"where" :{
"expired": null
}
} }
} }

View File

@ -0,0 +1,9 @@
const app = require('vn-loopback/server/server');
describe('loopback model Company', () => {
it('should check that the company FTH doesnt exists', async() => {
let result = await app.models.Company.findOne({where: {code: 'FTH'}});
expect(result).toBeFalsy();
});
});

View File

@ -31,7 +31,7 @@ describe('User config', () => {
expect(userLocalBank).toEqual(''); expect(userLocalBank).toEqual('');
expect(userLocalCompany).toEqual(''); expect(userLocalCompany).toEqual('');
expect(userWarehouse).toEqual('Warehouse Three'); expect(userWarehouse).toEqual('Warehouse Three');
expect(userCompany).toEqual('FTH'); expect(userCompany).toEqual('VNH');
}); });
}); });
@ -103,7 +103,7 @@ describe('User config', () => {
expect(userLocalBank).toContain('Pay on receipt'); expect(userLocalBank).toContain('Pay on receipt');
expect(userLocalCompany).toContain('VNL'); expect(userLocalCompany).toContain('VNL');
expect(userWarehouse).toEqual('Warehouse Three'); expect(userWarehouse).toEqual('Warehouse Three');
expect(userCompany).toEqual('FTH'); expect(userCompany).toEqual('VNH');
}); });
it('should now clear the local settings', async() => { it('should now clear the local settings', async() => {

View File

@ -1,5 +1,5 @@
<md-checkbox <md-checkbox
aria-label="Checkbox 1" aria-label="::$ctrl.label"
md-indeterminate="$ctrl.isIntermediate" md-indeterminate="$ctrl.isIntermediate"
ng-disabled="$ctrl.disabled" ng-disabled="$ctrl.disabled"
ng-checked="$ctrl.isChecked" ng-checked="$ctrl.isChecked"

View File

@ -16,9 +16,7 @@ export default class Controller extends Component {
set model(value) { set model(value) {
if (value === null) return; if (value === null) return;
if (this.model === true) if (this.model === false && this.tripleState)
value = false;
else if (this.model === false && this.tripleState)
value = null; value = null;
this.emit('change', {value}); this.emit('change', {value});
@ -38,9 +36,10 @@ export default class Controller extends Component {
} }
get isIntermediate() { get isIntermediate() {
return this.intermediate if (this.intermediate || (this.tripleState && (this.model === null || this.model === undefined)))
|| this.model === null return true;
|| this.model === undefined;
return false;
} }
get isChecked() { get isChecked() {

View File

@ -0,0 +1,64 @@
describe('Component vnCheck', () => {
let controller;
let $element;
beforeEach(ngModule('vnCore'));
beforeEach(inject(($compile, $rootScope) => {
$element = $compile(`<vn-check></vn-check`)($rootScope);
controller = $element.controller('vnCheck');
}));
afterEach(() => {
$element.remove();
});
describe('model() setter', () => {
it(`should set model value`, () => {
controller.model = true;
expect(controller.model).toEqual(true);
});
it(`should set model value to null if current model value is false and is a triple-state checkbox`, () => {
controller._model = false;
controller.tripleState = true;
controller.model = true;
expect(controller.model).toEqual(null);
});
});
describe('field() setter', () => {
it(`should set model value`, () => {
controller.field = true;
expect(controller.field).toEqual(true);
});
it(`should set model value and convert numerical values to boolean values`, () => {
controller.field = 1;
expect(controller.field).toEqual(true);
});
});
describe('isIntermediate() getter', () => {
it(`should return true if intermediate property is truthy`, () => {
controller.intermediate = true;
let result = controller.isIntermediate;
expect(result).toEqual(true);
});
it(`should return true if is a triple-state checkbox and has null or undefined value`, () => {
controller.tripleState = true;
controller.model = null;
let result = controller.isIntermediate;
expect(result).toEqual(true);
});
});
});

View File

@ -2,15 +2,16 @@
vn-check { vn-check {
position: relative; position: relative;
& > .mdl-checkbox {
width: initial;
}
& > i { & > i {
padding-left: 5px; padding-left: 5px;
position: absolute; position: absolute;
bottom: 3px;
color: $color-font-secondary; color: $color-font-secondary;
font-size: 20px !important font-size: 20px !important;
cursor: help
}
md-checkbox.md-checked .md-icon {
background-color: $color-main;
} }
} }

View File

@ -8,23 +8,37 @@ export default class Controller {
this.hasInfo = Boolean($attrs.info); this.hasInfo = Boolean($attrs.info);
this.info = $attrs.info || null; this.info = $attrs.info || null;
} }
set label(value) { set label(value) {
let label = this.element.querySelector('vn-label'); let label = this.element.querySelector('vn-label');
label.textContent = this._.instant(value); label.textContent = this._.instant(value);
this._label = value; this._label = value;
} }
get label() { get label() {
return this._label; return this._label;
} }
set value(value) { set value(value) {
let span = this.element.querySelector('span'); let span = this.element.querySelector('span');
span.title = value; span.title = value;
span.textContent = value ? value : '-'; span.textContent = value ? value : '-';
this._value = value; this._value = value;
} }
get value() { get value() {
return this._value; return this._value;
} }
get title() {
return this._title;
}
set title(value) {
let span = this.element.querySelector('span');
span.title = value;
this._title = value;
}
} }
Controller.$inject = ['$element', '$translate', '$attrs']; Controller.$inject = ['$element', '$translate', '$attrs'];
@ -32,6 +46,7 @@ ngModule.component('vnLabelValue', {
controller: Controller, controller: Controller,
template: require('./label-value.html'), template: require('./label-value.html'),
bindings: { bindings: {
title: '@?',
label: '@', label: '@',
value: '@' value: '@'
} }

View File

@ -1,24 +1,24 @@
<ul ng-if="$ctrl.items"> <ul ng-if="$ctrl.items">
<li ng-repeat="item in $ctrl.items" ng-class="{'selected' : item.selected && !item.excluded, 'included': item.included}"> <li ng-repeat="item in $ctrl.items"
ng-class="{
'expanded': item.active,
'collapsed': !item.active,
'included': item.isIncluded == 1,
'excluded': item.isIncluded == 0
}">
<vn-horizontal> <vn-horizontal>
<vn-auto class="actions"> <vn-auto class="actions">
<vn-icon icon="keyboard_arrow_up" ng-if="item.childs.length" <vn-icon icon="keyboard_arrow_down"
ng-click="$ctrl.toggle(item, $event)"> ng-show="item.sons > 0"
</vn-icon> ng-click="$ctrl.toggle(item, $event)" >
<vn-icon icon="keyboard_arrow_down" ng-if="item.sons > 0 && !item.childs"
ng-click="$ctrl.toggle(item, $event)">
</vn-icon> </vn-icon>
</vn-auto> </vn-auto>
<vn-one class="description"> <div class="description">
<vn-horizontal> <vn-check vn-auto field="item.isIncluded"
<vn-check vn-auto field="item.selected && !item.excluded" on-change="$ctrl.select(item, value)" triple-state="true">
on-change="$ctrl.select(item)">
</vn-check> </vn-check>
<vn-one ng-dblclick="$ctrl.toggle(item)" class="text unselectable">
{{::item.name}} {{::item.name}}
</vn-one> </div>
</vn-horizontal>
</vn-one>
</vn-horizontal> </vn-horizontal>
<vn-treeview-child items="item.childs"></vn-treeview-child> <vn-treeview-child items="item.childs"></vn-treeview-child>
</li> </li>

View File

@ -10,8 +10,8 @@ class Controller extends Component {
this.treeview.onToggle(item); this.treeview.onToggle(item);
} }
select(item) { select(item, value) {
this.treeview.onSelection(item); this.treeview.onSelection(item, value);
} }
} }

View File

@ -20,72 +20,10 @@ export default class Treeview extends Component {
refresh() { refresh() {
this.model.refresh().then(() => { this.model.refresh().then(() => {
this.data = this.model.data; this.data = this.model.data;
console.log(this.data);
this.repaintAll();
}); });
} }
repaintAll() { /* hasCheckedChilds(node) {
let oldData = this.data;
oldData.forEach(node => {
this.repaintAsc(node);
this.repaintDesc(node);
});
}
repaintNode(node) {
this.repaintAsc(node);
this.repaintDesc(node);
}
repaintAsc(node) {
if (!node.parent) return;
const parent = node.parent;
if ((node.selected || node.included) && !parent.selected) {
parent.included = true;
parent.hasCheckedChilds = true;
} else if (!this.hasCheckedChilds(parent) && !this.hasCheckedParents(node))
parent.included = false;
// FIXME - Propagate hasCheckedCHilds
if (!node.selected && this.hasCheckedParents(node)) {
node.included = true;
parent.hasCheckedChilds = false;
}
if (!this.hasCheckedChilds(node))
node.hasCheckedChilds = false;
this.repaintAsc(parent);
}
repaintDesc(node) {
/* if (node.hasCheckedChilds)
node.included = false; */
if (!node.selected && this.hasCheckedChilds(node)) {
node.hasCheckedChilds = true;
node.included = true;
} else if (!node.selected && node.childs && !this.hasCheckedChilds(node))
node.hasCheckedChilds = false;
const childs = node.childs || [];
for (let i = 0; i < childs.length; i++) {
childs[i].included = false;
if (((node.selected || node.included && this.hasCheckedParents(childs[i])) && !childs[i].selected) && !node.excluded)
childs[i].included = true;
this.repaintDesc(childs[i]);
}
if (!node.selected && node.hasCheckedChilds)
node.included = true;
}
hasCheckedChilds(node) {
if (!node.childs) return false; if (!node.childs) return false;
const childs = node.childs; const childs = node.childs;
@ -105,44 +43,41 @@ export default class Treeview extends Component {
return true; return true;
return false; return false;
} } */
onSelection(item) { onSelection(item, value) {
let canBeExcluded = this.hasCheckedChilds(item) || this.hasCheckedParents(item); this.emit('selection', {item, value});
if (!item.selected && item.included && canBeExcluded)
item.excluded = true;
else
item.excluded = false;
item.selected = !item.selected;
if (item.selected && item.included)
item.included = false;
if (this.hasCheckedChilds(item))
item.hasCheckedChilds = true;
else if (this.childs)
item.hasCheckedChilds = false;
this.emit('selection', {item});
} }
onToggle(item) { onToggle(item) {
if (item.childs && item.childs.length == 0) if (item.active)
return;
if (item.childs)
item.childs = undefined; item.childs = undefined;
else { else {
this.model.applyFilter({}, {parentFk: item.id}).then(() => { this.model.applyFilter({}, {parentFk: item.id}).then(() => {
item.childs = this.model.data; const newData = this.model.data;
item.childs.forEach(child => {
child.parent = item; if (item.childs) {
let childs = item.childs;
childs.forEach(child => {
let index = newData.findIndex(newChild => {
return newChild.id == child.id;
}); });
this.repaintNode(item); newData[index] = child;
}); });
} }
item.childs = newData.sort((a, b) => {
let priority = (b.isIncluded - a.isIncluded) - 1;
if (b.name > a.name)
priority++;
return priority;
});
});
}
item.active = !item.active;
} }
} }

View File

@ -2,19 +2,21 @@
vn-treeview { vn-treeview {
ul { ul {
margin: 0; line-height: 24px;
padding: 0; padding: 0;
margin: 0;
li { li {
list-style: none; list-style: none;
cursor: pointer; cursor: pointer;
.actions { .actions {
padding: 0.5em; min-width: 24px;
} }
.description { .description {
padding: 0.5em padding-left: 5px
} }
} }
@ -22,27 +24,41 @@ vn-treeview {
padding: 0 1.8em; padding: 0 1.8em;
} }
li > vn-horizontal {
padding: 5px
}
li > vn-horizontal:hover { li > vn-horizontal:hover {
background-color: $color-hover-cd background-color: $color-hover-cd
} }
li.selected > vn-horizontal > .description .text, li.expanded > vn-horizontal > .actions > vn-icon[icon="keyboard_arrow_down"] {
li.included > vn-horizontal > .description .text { transition: all 0.2s;
font-weight: bold; transform: rotate(180deg);
color: $color-main; }
li.collapsed > vn-horizontal > .actions > vn-icon[icon="keyboard_arrow_down"] {
transition: all 0.2s;
transform: rotate(0deg);
} }
li.included { li.included {
& > vn-horizontal > .description > vn-horizontal > vn-check { & > vn-horizontal > .description {
.mdl-checkbox .mdl-checkbox__box-outline, { color: $color-notice;
border: 2px solid $color-main-medium; font-weight: bold;
& > vn-check .md-icon {
background-color: $color-notice
} }
fieldset[disabled] .mdl-checkbox .mdl-checkbox__box-outline, .mdl-checkbox.is-disabled .mdl-checkbox__box-outline {
border: 2px solid rgba(0,0,0,.26);
} }
.mdl-checkbox .mdl-checkbox__tick-outline {
background: $color-main-medium;
} }
li.excluded {
& > vn-horizontal > .description {
color: $color-alert;
font-weight: bold;
} }
} }
} }

View File

@ -1,5 +1,5 @@
<div style="position: relative;"> <div style="position: relative;">
<div style="position: absolute; top: 0; left: 0; padding: .5em; z-index: 1"> <div style="position: absolute; top: 0; left: 0; padding: .3em; z-index: 1">
<vn-icon-button <vn-icon-button
icon="menu" icon="menu"
style="font-size: .4em;" style="font-size: .4em;"
@ -15,14 +15,16 @@
<div pad-medium> <div pad-medium>
<vn-horizontal ng-repeat="field in fields"> <vn-horizontal ng-repeat="field in fields">
<vn-check <vn-check
vn-one label="{{field}}" vn-one label="{{titles[field]}}"
field="tableConfiguration.configuration[field]"> field="tableConfiguration.configuration[field]">
</vn-check> </vn-check>
</vn-horizontal> </vn-horizontal>
<vn-horizontal>
<vn-button <vn-button
label="Save" label="Save"
ng-click="$ctrl.saveConfiguration(tableConfiguration)"> ng-click="$ctrl.saveConfiguration(tableConfiguration)">
</vn-button> </vn-button>
</vn-horizontal>
</div> </div>
</tpl-body> </tpl-body>
</vn-dialog> </vn-dialog>

View File

@ -1,5 +1,6 @@
import ngModule from '../module'; import ngModule from '../module';
import template from './uvc.html'; import template from './uvc.html';
import './uvc.scss';
directive.$inject = ['$http', '$compile', 'vnApp', '$translate']; directive.$inject = ['$http', '$compile', 'vnApp', '$translate'];
export function directive($http, $compile, vnApp, $translate) { export function directive($http, $compile, vnApp, $translate) {
@ -7,12 +8,16 @@ export function directive($http, $compile, vnApp, $translate) {
let allHeaders = $element[0].querySelectorAll(`vn-th[field], vn-th[th-id]`); let allHeaders = $element[0].querySelectorAll(`vn-th[field], vn-th[th-id]`);
let headerList = Array.from(allHeaders); let headerList = Array.from(allHeaders);
let ids = []; let ids = [];
let titles = {};
headerList.forEach(header => { headerList.forEach(header => {
ids.push(header.getAttribute('th-id') || header.getAttribute('field')); let id = header.getAttribute('th-id') || header.getAttribute('field');
ids.push(id);
titles[id] = header.innerText || id.charAt(0).toUpperCase() + id.slice(1);
}); });
$scope.fields = ids; $scope.fields = ids;
$scope.titles = titles;
return headerList; return headerList;
} }

View File

@ -0,0 +1,11 @@
vn-table vn-dialog[vn-id="uvc"]{
& > div {
min-width: 18em;
align-items: center;
}
vn-button[label="Save"] {
margin: 0 auto;
}
}

View File

@ -2,3 +2,5 @@ import './module';
import './routes'; import './routes';
import './components'; import './components';
import './styles'; import './styles';
// XXX: Pull request: Test 2

View File

@ -58,7 +58,7 @@ function backWatch(done) {
nodemon({ nodemon({
exec: commands.join(' && '), exec: commands.join(' && '),
ext: 'js html css', ext: 'js html css json',
args: ['backOnly'], args: ['backOnly'],
watch: backSources, watch: backSources,
done: done done: done

View File

@ -6,12 +6,6 @@ module.exports = Self => {
description: 'Returns the first shipped and landed possible for params', description: 'Returns the first shipped and landed possible for params',
accessType: '', accessType: '',
accepts: [{ accepts: [{
arg: 'filter',
type: 'Object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}
},
{
arg: 'zoneFk', arg: 'zoneFk',
type: 'Number', type: 'Number',
required: true, required: true,
@ -21,6 +15,12 @@ module.exports = Self => {
type: 'Number', type: 'Number',
default: 1, default: 1,
required: false, required: false,
},
{
arg: 'filter',
type: 'Object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}
}], }],
returns: { returns: {
type: ['object'], type: ['object'],
@ -32,64 +32,120 @@ module.exports = Self => {
} }
}); });
Self.getLeaves = async(filter, zoneFk, parentFk = 1) => { Self.getLeaves = async(zoneFk, parentFk = 1, filter) => {
let conn = Self.dataSource.connector; let conn = Self.dataSource.connector;
let stmts = []; let stmts = [];
stmts.push(`DROP TEMPORARY TABLE IF EXISTS tmp.checkedChilds`);
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
`SELECT lft, rgt, depth + 1 INTO @lft, @rgt, @depth `CREATE TEMPORARY TABLE tmp.checkedChilds (
FROM zoneGeo WHERE id = ?`, [parentFk])); id INT,
name VARCHAR(100),
lft INT,
rgt INT,
depth BIGINT(22),
sons DECIMAL(10, 0),
isIncluded TINYINT
) ENGINE = MEMORY`));
stmts.push(`DROP TEMPORARY TABLE IF EXISTS tChilds`); if (parentFk === 1) {
stmts.push(new ParameterizedSQL(
let stmt = new ParameterizedSQL( `INSERT INTO tmp.checkedChilds
`CREATE TEMPORARY TABLE tChilds SELECT
ENGINE = MEMORY zg.id,
SELECT id, lft, rgt zg.name,
FROM zoneGeo pt`); zg.lft,
stmt.merge(conn.makeSuffix(filter)); zg.rgt,
zg.depth,
if (!filter.where) { zg.sons,
stmt.merge(`WHERE pt.lft > @lft AND pt.rgt < @rgt zi.isIncluded
AND pt.depth = @depth`); FROM zoneGeo zg
JOIN zoneIncluded zi ON zi.geoFk = zg.id
AND zoneFk = ?`, [zoneFk]));
} }
stmts.push(stmt); let stmt = new ParameterizedSQL(
`SELECT * FROM (
SELECT
zg.id,
zg.name,
zg.lft,
zg.rgt,
zg.depth,
zg.sons,
IF(ch.id = zg.id, isIncluded, null) isIncluded
FROM zoneGeo zg
JOIN tmp.checkedChilds ch
ON zg.lft <= ch.lft AND zg.rgt >= ch.rgt
AND zg.depth > 0
UNION ALL
SELECT
child.id,
child.name,
child.lft,
child.rgt,
child.depth,
child.sons,
zi.isIncluded
FROM zoneGeo parent
JOIN zoneGeo child ON child.lft > parent.lft
AND child.rgt < parent.rgt
AND child.depth = parent.depth + 1
LEFT JOIN zoneIncluded zi ON zi.geoFk = child.id
AND zoneFk = ?
WHERE parent.id = ?) AS nst`, [zoneFk, parentFk]);
stmts.push(`DROP TEMPORARY TABLE IF EXISTS tZones`); // Get nodes from depth greather than Origin
stmts.push(new ParameterizedSQL( stmt.merge(conn.makeSuffix(filter));
`CREATE TEMPORARY TABLE tZones stmt.merge('GROUP BY nst.id');
(INDEX (id))
ENGINE = MEMORY
SELECT t.id
FROM tChilds t
JOIN zoneGeo zt
ON zt.lft > t.lft AND zt.rgt < t.rgt
JOIN zoneIncluded zi
ON zi.geoFk = zt.id AND zi.zoneFk = ?
GROUP BY t.id`, [zoneFk]));
const resultIndex = stmts.push(new ParameterizedSQL( const resultIndex = stmts.push(stmt) - 1;
`SELECT
pt.id,
pt.name,
pt.lft,
pt.rgt,
pt.depth,
pt.sons,
ti.id IS NOT NULL hasCheckedChilds,
zi.geoFk IS NOT NULL AS selected,
zi.isIncluded AS excluded
FROM zoneGeo pt
LEFT JOIN vn.zoneIncluded zi
ON zi.geoFk = pt.id AND zi.zoneFk = ?
JOIN tChilds c ON c.id = pt.id
LEFT JOIN tZones ti ON ti.id = pt.id
ORDER BY selected DESC, name`, [zoneFk])) - 1;
const sql = ParameterizedSQL.join(stmts, ';'); const sql = ParameterizedSQL.join(stmts, ';');
const result = await Self.rawStmt(sql); const result = await Self.rawStmt(sql);
const nodes = result[resultIndex];
return result[resultIndex]; if (nodes.length == 0)
return nodes;
// Get parent nodes
const minorDepth = nodes.reduce((a, b) => {
return b < a ? b : a;
}).depth;
const parentNodes = nodes.filter(element => {
return element.depth === minorDepth;
});
const sortedLeaves = parentNodes.sort((a, b) => {
let priority = (b.isIncluded - a.isIncluded) - 1;
if (b.name > a.name)
priority++;
return priority;
});
const leaves = Object.assign([], sortedLeaves);
nestLeaves(leaves);
function nestLeaves(elements) {
elements.forEach(element => {
element.childs = Object.assign([], getLeaves(element));
nestLeaves(element.childs);
});
}
function getLeaves(parent) {
let elements = nodes.filter(element => {
return element.lft > parent.lft && element.rgt < parent.rgt
&& element.depth === parent.depth + 1;
});
return elements;
}
return leaves;
}; };
}; };

View File

@ -8,8 +8,8 @@ module.exports = Self => {
required: true, required: true,
}, },
{ {
arg: 'geoFk', arg: 'item',
type: 'Number', type: 'Object',
required: true, required: true,
}], }],
returns: { returns: {
@ -22,31 +22,15 @@ module.exports = Self => {
} }
}); });
Self.toggleIsIncluded = async(zoneFk, geoFk) => { Self.toggleIsIncluded = async(zoneFk, item) => {
const models = Self.app.models; if (item.isIncluded === null)
const geo = await models.ZoneGeo.findById(geoFk); return Self.destroyAll({zoneFk, geoFk: item.id});
const isIncluded = await Self.findOne({ else {
where: {zoneFk, geoFk} return Self.upsert({
zoneFk: zoneFk,
geoFk: item.id,
isIncluded: item.isIncluded
}); });
}
const hasCheckedParents = await Self.rawSql(
`SELECT id
FROM vn.zoneGeo zt
JOIN vn.zoneIncluded zi ON zi.geoFk = zt.id
WHERE zt.lft < ? AND zt.rgt > ?`, [geo.lft, geo.rgt]
);
const hasCheckedChilds = await Self.rawSql(
`SELECT id
FROM vn.zoneGeo zt
JOIN vn.zoneIncluded zi ON zi.geoFk = zt.id
WHERE zt.lft > ? AND zt.rgt < ?`, [geo.lft, geo.rgt]
);
const isExcluded = hasCheckedParents.length || hasCheckedChilds.length;
if (isIncluded)
return Self.destroyAll({zoneFk, geoFk});
else
return Self.upsert({zoneFk, geoFk, isIncluded: isExcluded});
}; };
}; };

View File

@ -33,7 +33,7 @@ class Controller {
res.data.forEach(holiday => { res.data.forEach(holiday => {
events.push({ events.push({
date: holiday.dated, date: holiday.dated,
color: 'blue-circle', color: 'red',
title: holiday.description || holiday.name, title: holiday.description || holiday.name,
isRemovable: false isRemovable: false
}); });

View File

@ -2,7 +2,7 @@
vn-id="model" vn-id="model"
url="/agency/api/ZoneGeos/getLeaves" url="/agency/api/ZoneGeos/getLeaves"
filter="::$ctrl.filter" filter="::$ctrl.filter"
params="{zoneFk: $ctrl.$stateParams.id, parentFk: 1}"> params="{zoneFk: $ctrl.$stateParams.id}" auto-load="false">
</vn-crud-model> </vn-crud-model>
<div class="main-with-right-menu"> <div class="main-with-right-menu">
<vn-card compact pad-large> <vn-card compact pad-large>
@ -13,7 +13,7 @@
vn-focus> vn-focus>
</vn-searchbar> </vn-searchbar>
<vn-treeview vn-id="treeview" model="model" <vn-treeview vn-id="treeview" model="model"
on-selection="$ctrl.onSelection(item)"> on-selection="$ctrl.onSelection(item, value)">
</vn-treeview> </vn-treeview>
</vn-card> </vn-card>
<vn-side-menu side="right"> <vn-side-menu side="right">

View File

@ -22,11 +22,12 @@ class Controller {
} }
} }
onSelection(item) { onSelection(item, isIncluded) {
item.isIncluded = isIncluded;
const path = '/agency/api/ZoneIncludeds/toggleIsIncluded'; const path = '/agency/api/ZoneIncludeds/toggleIsIncluded';
const params = {geoFk: item.id, zoneFk: this.zone.id}; const params = {zoneFk: this.zone.id, item};
this.$http.post(path, params).then(() => { this.$http.post(path, params).then(() => {
this.$scope.treeview.repaintNode(item);
}); });
} }
} }

View File

@ -119,8 +119,7 @@ class Controller {
} else } else
offsetTop = onPreparationLine.offsetTop - headerHeight; offsetTop = onPreparationLine.offsetTop - headerHeight;
body.querySelector('ui-view').scrollTop = offsetTop; this.$window.scrollTo(0, offsetTop);
this.ticketFk = null; this.ticketFk = null;
} }

View File

@ -74,6 +74,7 @@
</span> </span>
</vn-td> </vn-td>
<vn-td>{{::item.density}}</vn-td> <vn-td>{{::item.density}}</vn-td>
<vn-td number>{{::item.density}}</vn-td>
<vn-td>{{::item.taxClass}}</vn-td> <vn-td>{{::item.taxClass}}</vn-td>
<vn-td> <vn-td>
<vn-check <vn-check

View File

@ -0,0 +1 @@
picture: Foto

View File

@ -96,7 +96,8 @@
<vn-check <vn-check
vn-one vn-one
label="My team" label="My team"
field="filter.myTeam"> field="filter.myTeam"
triple-state="true">
</vn-check> </vn-check>
</vn-horizontal> </vn-horizontal>
<vn-horizontal margin-large-top> <vn-horizontal margin-large-top>

View File

@ -25,6 +25,13 @@ class Controller {
}, { }, {
relation: 'sip', relation: 'sip',
scope: {fields: ['extension']} scope: {fields: ['extension']}
}, {
relation: 'department',
scope: {
include: {
relation: 'department'
}
}
} }
] ]
}; };

View File

@ -10,12 +10,15 @@
</vn-horizontal> </vn-horizontal>
<div class="body"> <div class="body">
<div class="attributes"> <div class="attributes">
<h5>{{$ctrl.worker.firstName}} {{$ctrl.worker.name}}</h5> <h5 title="{{$ctrl.worker.firstName}} {{$ctrl.worker.name}}">
{{$ctrl.worker.firstName}} {{$ctrl.worker.name}}
</h5>
<vn-label-value label="Id" <vn-label-value label="Id"
value="{{$ctrl.worker.id}}"> value="{{$ctrl.worker.id}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="User" <vn-label-value label="User"
value="{{$ctrl.worker.user.name}}"> value="{{$ctrl.worker.user.name}}"
title="{{$ctrl.worker.firstName}} {{$ctrl.worker.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Email" <vn-label-value label="Email"
value="{{$ctrl.worker.user.email}}"> value="{{$ctrl.worker.user.email}}">
@ -24,13 +27,13 @@
value="{{$ctrl.worker.client.fi}}"> value="{{$ctrl.worker.client.fi}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Department" <vn-label-value label="Department"
value="{{$ctrl.worker.department.department}}"> value="{{$ctrl.worker.department.department.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Phone" <vn-label-value label="Phone"
value="{{$ctrl.worker.phone}}"> value="{{$ctrl.worker.phone}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Extension" <vn-label-value label="Extension"
value="{{$ctrl.worker.sip.phone}}"> value="{{$ctrl.worker.sip.extension}}">
</vn-label-value> </vn-label-value>
</div> </div>
<div class="quicklinks"> <div class="quicklinks">

View File

@ -1,8 +1,8 @@
Workers: Trabajadores Workers: Trabajadores
Last name: Apellidos Last name: Apellidos
User data: Datos de usuario User data: Datos de usuario
Fiscal identifier: Identificador fiscal Fiscal identifier: NIF
Email: Correo electrónico Email: E-mail
Department: Departamento Department: Departamento
User id: Id de usuario User id: Id de usuario
Role: Rol Role: Rol

View File

@ -13,7 +13,7 @@
value="{{worker.user.email}}"> value="{{worker.user.email}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Department" <vn-label-value label="Department"
value="{{worker.department.department}}"> value="{{worker.department.department.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Phone" <vn-label-value label="Phone"
value="{{worker.phone}}"> value="{{worker.phone}}">
@ -25,13 +25,14 @@
value="{{worker.userFk}}"> value="{{worker.userFk}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="User" <vn-label-value label="User"
value="{{worker.user.name}}"> value="{{worker.user.name}}"
title="{{worker.firstName}} {{worker.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Role" <vn-label-value label="Role"
value="{{worker.user.role.name}}"> value="{{worker.user.role.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Extension" <vn-label-value label="Extension"
value="{{worker.sip.phone}}"> value="{{worker.sip.extension}}">
</vn-label-value> </vn-label-value>
</vn-one> </vn-one>
</vn-horizontal> </vn-horizontal>

View File

@ -35,6 +35,13 @@ class Controller {
}, { }, {
relation: 'sip', relation: 'sip',
scope: {fields: ['extension']} scope: {fields: ['extension']}
}, {
relation: 'department',
scope: {
include: {
relation: 'department'
}
}
} }
] ]
}; };

2024
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,13 +11,13 @@
"dependencies": { "dependencies": {
"compression": "^1.7.3", "compression": "^1.7.3",
"fs-extra": "^5.0.0", "fs-extra": "^5.0.0",
"helmet": "^3.15.0", "helmet": "^3.15.1",
"i18n": "^0.8.3", "i18n": "^0.8.3",
"loopback": "^3.24.0", "loopback": "^3.25.0",
"loopback-boot": "^2.27.1", "loopback-boot": "^2.27.1",
"loopback-component-explorer": "^6.3.1", "loopback-component-explorer": "^6.3.1",
"loopback-connector-mysql": "^5.3.1", "loopback-connector-mysql": "^5.3.1",
"loopback-connector-remote": "^3.4.0", "loopback-connector-remote": "^3.4.1",
"loopback-context": "^3.4.0", "loopback-context": "^3.4.0",
"md5": "^2.2.1", "md5": "^2.2.1",
"object-diff": "0.0.4", "object-diff": "0.0.4",
@ -29,16 +29,16 @@
"vn-loopback": "file:./loopback" "vn-loopback": "file:./loopback"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.2.2", "@babel/core": "^7.3.3",
"@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/polyfill": "^7.2.5", "@babel/polyfill": "^7.2.5",
"@babel/preset-env": "^7.2.0", "@babel/preset-env": "^7.3.1",
"@babel/register": "^7.0.0", "@babel/register": "^7.0.0",
"angular-mocks": "^1.7.4", "angular-mocks": "^1.7.7",
"babel-loader": "^8.0.5", "babel-loader": "^8.0.5",
"css-loader": "^2.1.0", "css-loader": "^2.1.0",
"del": "^2.2.2", "del": "^2.2.2",
"eslint": "^5.12.0", "eslint": "^5.14.0",
"eslint-config-google": "^0.11.0", "eslint-config-google": "^0.11.0",
"eslint-plugin-jasmine": "^2.10.1", "eslint-plugin-jasmine": "^2.10.1",
"fancy-log": "^1.3.2", "fancy-log": "^1.3.2",
@ -68,16 +68,16 @@
"karma-webpack": "^3.0.5", "karma-webpack": "^3.0.5",
"merge-stream": "^1.0.1", "merge-stream": "^1.0.1",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"mysql2": "^1.6.1", "mysql2": "^1.6.5",
"nightmare": "^3.0.1", "nightmare": "^3.0.1",
"node-sass": "^4.9.3", "node-sass": "^4.9.3",
"nodemon": "^1.18.5", "nodemon": "^1.18.10",
"plugin-error": "^1.0.1", "plugin-error": "^1.0.1",
"raw-loader": "^1.0.0", "raw-loader": "^1.0.0",
"sass-loader": "^7.1.0", "sass-loader": "^7.1.0",
"style-loader": "^0.23.1", "style-loader": "^0.23.1",
"webpack": "^4.28.3", "webpack": "^4.29.5",
"webpack-cli": "^3.2.1", "webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.1.14", "webpack-dev-server": "^3.1.14",
"webpack-merge": "^4.2.1", "webpack-merge": "^4.2.1",
"yaml-loader": "^0.5.0" "yaml-loader": "^0.5.0"

View File

@ -1055,7 +1055,7 @@ INSERT INTO `vn`.`userConfig` (`userFk`, `warehouseFk`, `companyFk`)
(1, 2, 69), (1, 2, 69),
(5, 1, 442), (5, 1, 442),
(9, 1, 442), (9, 1, 442),
(18, 3, 791); (18, 3, 567);
INSERT INTO `vn`.`receipt`(`id`, `invoiceFk`, `amountPaid`, `amountUnpaid`, `payed`, `workerFk`, `bankFk`, `clientFk`, `created`, `companyFk`, `isConciliate`) INSERT INTO `vn`.`receipt`(`id`, `invoiceFk`, `amountPaid`, `amountUnpaid`, `payed`, `workerFk`, `bankFk`, `clientFk`, `created`, `companyFk`, `isConciliate`)
VALUES VALUES