diff --git a/db/import-changes.sh b/db/import-changes.sh
index d9042cf3c..498390b51 100755
--- a/db/import-changes.sh
+++ b/db/import-changes.sh
@@ -1,5 +1,26 @@
#!/bin/bash
+FORCE=FALSE
+
+usage() {
+ echo "Usage: $0 [-f] [environment]"
+ exit 1
+}
+
+while getopts ":f" option
+do
+ case $option in
+ f)
+ FORCE=TRUE
+ ;;
+ \?|:)
+ usage
+ ;;
+ esac
+done
+
+shift $(($OPTIND - 1))
+
ENV=$1
if [ "$ENV" == "production" ]; then
@@ -14,11 +35,13 @@ if [ "$ENV" == "production" ]; then
echo "|_| |_|_\ \___/|___/ \___/ \___| |_| |___| \___/|_|\_|"
echo ""
- read -p "Are you sure? (Default: no) [yes|no]: " ANSWER
+ if [ "$FORCE" != "TRUE" ]; then
+ read -p "Are you sure? (Default: no) [yes|no]: " ANSWER
- if [ "$ANSWER" != "yes" ]; then
- echo "Aborting"
- exit;
+ if [ "$ANSWER" != "yes" ]; then
+ echo "Aborting"
+ exit;
+ fi
fi
fi
if [ -z "$ENV" ]; then
@@ -28,15 +51,16 @@ fi
INI_FILE="config.$ENV.ini"
if [ ! -f "$INI_FILE" ]; then
- echo "File $INI_FILE doesn't exists"
- exit 1
+ echo "Config file doesn't exists: $INI_FILE"
+ exit 2
fi
echo "[INFO] Config file: $INI_FILE"
-echo "[INFO] Importing changes."
+echo "[INFO] Applying changes"
# Import changes
for file in install/changes/*.sql; do
- echo "[INFO] -> Applying $file"
+ echo "[INFO] -> $file"
mysql --defaults-file="$INI_FILE" < $file
done
+
diff --git a/db/install/changes/0-ACL.sql b/db/install/changes/0-ACL.sql
index 099e3c5a9..a2f3991f1 100644
--- a/db/install/changes/0-ACL.sql
+++ b/db/install/changes/0-ACL.sql
@@ -1,2 +1,4 @@
INSERT INTO `salix`.`ACL` (`id`,`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (149, 'Sip', '*', 'WRITE', 'ALLOW', 'ROLE', 'hr');
-INSERT INTO `salix`.`ACL` (`id`,`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (150, 'Sip', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
\ No newline at end of file
+INSERT INTO `salix`.`ACL` (`id`,`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (150, 'Sip', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
+INSERT INTO `salix`.`ACL` (`id`,`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (151, 'Department','*','READ','ALLOW','ROLE','employee');
+INSERT INTO `salix`.`ACL` (`id`,`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (152, 'Department','*','WRITE','ALLOW','ROLE','hr');
diff --git a/db/install/changes/12-department.sql b/db/install/changes/12-department.sql
new file mode 100644
index 000000000..4203b059e
--- /dev/null
+++ b/db/install/changes/12-department.sql
@@ -0,0 +1,23 @@
+/* Ejecutar en prod * /
+
+/* USE `vn2008`;
+
+ALTER TABLE vn2008.department ADD `depth` int DEFAULT 0 NOT NULL;
+ALTER TABLE vn2008.department ADD sons int DEFAULT 0 NOT NULL;
+
+USE `vn`;
+
+CREATE
+OR REPLACE
+VIEW `vn`.`department` AS select
+ `b`.`department_id` AS `id`,
+ `b`.`name` AS `name`,
+ `b`.`father_id` AS `fatherFk`,
+ `b`.`production` AS `isProduction`,
+ `b`.`lft` AS `lft`,
+ `b`.`rgt` AS `rgt`,
+ `b`.`isSelected` AS `isSelected`,
+ `b`.`depth` AS `depth`,
+ `b`.`sons` AS `sons`
+from
+ `vn2008`.`department` `b`; */
\ No newline at end of file
diff --git a/db/install/changes/13-nodeAdd.sql b/db/install/changes/13-nodeAdd.sql
new file mode 100644
index 000000000..f3f4381f3
--- /dev/null
+++ b/db/install/changes/13-nodeAdd.sql
@@ -0,0 +1,86 @@
+/* Ejecutar en prod * /
+
+/* DROP PROCEDURE IF EXISTS nst.NodeAdd;
+
+DELIMITER $$
+$$
+CREATE DEFINER=`root`@`%` PROCEDURE `nst`.`nodeAdd`(IN `vScheme` VARCHAR(45), IN `vTable` VARCHAR(45), IN `vParentFk` INT, IN `vChild` VARCHAR(100))
+BEGIN
+ DECLARE vSql TEXT;
+ DECLARE vTableClone VARCHAR(45);
+
+ SET vTableClone = CONCAT(vTable, 'Clone');
+
+ CALL util.exec(CONCAT('DROP TEMPORARY TABLE IF EXISTS tmp.', vTableClone));
+ CALL util.exec(CONCAT(
+ 'CREATE TEMPORARY TABLE tmp.', vTableClone,
+ ' ENGINE = MEMORY'
+ ' SELECT * FROM ', vScheme, '.', vTable
+ ));
+
+ -- Check parent childs
+ SET vSql = sql_printf('
+ SELECT COUNT(c.id) INTO @childs
+ FROM %t.%t p
+ LEFT JOIN %t.%t c ON c.lft BETWEEN p.lft AND p.rgt AND c.id != %v
+ WHERE p.id = %v',
+ vScheme, vTable, 'tmp', vTableClone, vParentFk, vParentFk);
+ SET @qrySql := vSql;
+
+ PREPARE stmt FROM @qrySql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+
+ -- Select left from last child
+ IF @childs = 0 THEN
+ SET vSql = sql_printf('SELECT lft INTO @vLeft FROM %t.%t WHERE id = %v', vScheme, vTable, vParentFk);
+ SET @qrySql := vSql;
+ ELSE
+ SET vSql = sql_printf('
+ SELECT c.rgt INTO @vLeft
+ FROM %t.%t p
+ JOIN %t.%t c ON c.lft BETWEEN p.lft AND p.rgt
+ WHERE p.id = %v
+ ORDER BY c.lft
+ DESC LIMIT 1',
+ vScheme, vTable, 'tmp', vTableClone, vParentFk);
+ SET @qrySql := vSql;
+ END IF;
+
+ PREPARE stmt FROM @qrySql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+
+ -- Update right
+ SET vSql = sql_printf('UPDATE %t.%t SET rgt = rgt + 2 WHERE rgt > %v ORDER BY rgt DESC', vScheme, vTable, @vLeft);
+ SET @qrySql := vSql;
+
+ PREPARE stmt FROM @qrySql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+
+ SET vSql = sql_printf('UPDATE %t.%t SET lft = lft + 2 WHERE lft > %v ORDER BY lft DESC', vScheme, vTable, @vLeft);
+ SET @qrySql := vSql;
+
+ PREPARE stmt FROM @qrySql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+
+ -- Escape character
+ SET vChild = REPLACE(vChild, "'", "\\'");
+
+ -- Add child
+ SET vSql = sql_printf('INSERT INTO %t.%t (name, lft, rgt) VALUES (%v, %v, %v)', vScheme, vTable, vChild, @vLeft + 1, @vLeft + 2);
+ SET @qrySql := vSql;
+
+ PREPARE stmt FROM @qrySql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+
+ SELECT id, name, lft, rgt, depth, sons FROM vn.department
+ WHERE id = LAST_INSERT_ID();
+
+ CALL util.exec(CONCAT('DROP TEMPORARY TABLE tmp.', vTableClone));
+END$$
+DELIMITER ;
+ */
\ No newline at end of file
diff --git a/db/install/changes/14-nodeRecalc.sql b/db/install/changes/14-nodeRecalc.sql
new file mode 100644
index 000000000..73f3042c4
--- /dev/null
+++ b/db/install/changes/14-nodeRecalc.sql
@@ -0,0 +1,31 @@
+/* Ejecutar en prod * /
+
+/* DROP PROCEDURE IF EXISTS nst.nodeRecalc;
+
+DELIMITER $$
+$$
+CREATE DEFINER=`root`@`%` PROCEDURE `nst`.`nodeRecalc`(IN `vScheme` VARCHAR(45), IN `vTable` VARCHAR(45))
+BEGIN
+ CALL util.exec (sql_printf (
+ 'UPDATE %t.%t d
+ JOIN (SELECT
+ node.id,
+ COUNT(parent.id) - 1 as depth,
+ cast((node.rgt - node.lft - 1) / 2 as DECIMAL) as sons
+ FROM
+ %t.%t AS node,
+ %t.%t AS parent
+ WHERE node.lft BETWEEN parent.lft AND parent.rgt
+ GROUP BY node.id
+ ORDER BY node.lft) n ON n.id = d.id
+ SET d.`depth` = n.depth, d.sons = n.sons',
+ vScheme,
+ vTable,
+ vScheme,
+ vTable,
+ vScheme,
+ vTable
+ ));
+END$$
+DELIMITER ;
+ */
\ No newline at end of file
diff --git a/db/install/changes/15-ticketLog.sql b/db/install/changes/15-ticketLog.sql
new file mode 100644
index 000000000..e4d5c9e98
--- /dev/null
+++ b/db/install/changes/15-ticketLog.sql
@@ -0,0 +1 @@
+ALTER TABLE vn.itemLog MODIFY COLUMN userFk int(10) unsigned NULL;
diff --git a/db/install/changes/15-zoneGeo.sql b/db/install/changes/15-zoneGeo.sql
new file mode 100644
index 000000000..1037fe089
--- /dev/null
+++ b/db/install/changes/15-zoneGeo.sql
@@ -0,0 +1,4 @@
+USE `vn`;
+
+CREATE UNIQUE INDEX zoneGeo_lft_IDX USING BTREE ON vn.zoneGeo (lft);
+CREATE UNIQUE INDEX zoneGeo_rgt_IDX USING BTREE ON vn.zoneGeo (rgt);
\ No newline at end of file
diff --git a/front/core/components/treeview/child.html b/front/core/components/treeview/child.html
index 8589790ec..a079d8f40 100644
--- a/front/core/components/treeview/child.html
+++ b/front/core/components/treeview/child.html
@@ -1,25 +1,54 @@
-
+
-
-
+
-
-
+
+
- {{::item.name}}
+ {{::item.name}}
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+ Create new one
-
\ No newline at end of file
diff --git a/front/core/components/treeview/child.js b/front/core/components/treeview/child.js
index b5bdb67e5..ca5b59efb 100644
--- a/front/core/components/treeview/child.js
+++ b/front/core/components/treeview/child.js
@@ -4,6 +4,7 @@ import Component from '../../lib/component';
class Controller extends Component {
constructor($element, $scope) {
super($element, $scope);
+ this.$scope = $scope;
}
toggle(item) {
@@ -13,13 +14,33 @@ class Controller extends Component {
select(item, value) {
this.treeview.onSelection(item, value);
}
+
+ onClick(icon, item, parent, index) {
+ let parentScope = this.$scope.$parent.$parent;
+ let parentController = parentScope.$ctrl;
+ icon.callback.call(parentController, item, parent, index);
+ }
+
+ onCreate(parent) {
+ this.treeview.onCreate(parent);
+ }
+
+ get isInsertable() {
+ return Array.isArray(this.parent) || this.parent.childs;
+ }
}
ngModule.component('vnTreeviewChild', {
template: require('./child.html'),
controller: Controller,
bindings: {
- items: '<'
+ items: '<',
+ parent: '<',
+ icons: '',
+ disabled: '',
+ selectable: '',
+ editable: '',
+ aclRole: '',
},
require: {
treeview: '^vnTreeview'
diff --git a/front/core/components/treeview/index.html b/front/core/components/treeview/index.html
index 05c485fef..85a4e4b6b 100644
--- a/front/core/components/treeview/index.html
+++ b/front/core/components/treeview/index.html
@@ -1 +1,9 @@
-
+
+
diff --git a/front/core/components/treeview/index.js b/front/core/components/treeview/index.js
index 0737bf8cb..9f2a0a3fa 100644
--- a/front/core/components/treeview/index.js
+++ b/front/core/components/treeview/index.js
@@ -23,10 +23,19 @@ export default class Treeview extends Component {
});
}
+ /**
+ * Emits selection event
+ * @param {Object} item - Selected item
+ * @param {Boolean} value - Changed value
+ */
onSelection(item, value) {
this.emit('selection', {item, value});
}
+ onCreate(parent) {
+ this.emit('create', {parent});
+ }
+
onToggle(item) {
if (item.active)
item.childs = undefined;
@@ -45,12 +54,12 @@ export default class Treeview extends Component {
}
item.childs = newData.sort((a, b) => {
- if (b.isIncluded !== a.isIncluded) {
- if (a.isIncluded == null)
+ if (b.selected !== a.selected) {
+ if (a.selected == null)
return 1;
- if (b.isIncluded == null)
+ if (b.selected == null)
return -1;
- return b.isIncluded - a.isIncluded;
+ return b.selected - a.selected;
}
return a.name.localeCompare(b.name);
@@ -68,6 +77,11 @@ ngModule.component('vnTreeview', {
template: require('./index.html'),
controller: Treeview,
bindings: {
- model: '<'
+ model: '<',
+ icons: '',
+ disabled: '',
+ selectable: '',
+ editable: '',
+ aclRole: '@?'
}
});
diff --git a/front/core/components/treeview/style.scss b/front/core/components/treeview/style.scss
index 317d85453..ce51fe482 100644
--- a/front/core/components/treeview/style.scss
+++ b/front/core/components/treeview/style.scss
@@ -21,7 +21,7 @@ vn-treeview {
}
li ul {
- padding: 0 1.8em;
+ padding-left: 1.8em;
}
li > vn-horizontal {
@@ -62,4 +62,8 @@ vn-treeview {
}
}
}
+
+ vn-icon-button {
+ padding: 0
+ }
}
diff --git a/front/core/directives/acl.js b/front/core/directives/acl.js
index 2ff35a87f..46e8c582e 100644
--- a/front/core/directives/acl.js
+++ b/front/core/directives/acl.js
@@ -36,7 +36,7 @@ function vnAcl(aclService, $timeout) {
return conditions;
}
- function permissionElement($element, action) {
+ function permissionElement($scope, $element, action) {
if (!aclService.hasAny(acls)) {
if (action === 'disabled') {
let input = $element[0];
@@ -72,9 +72,13 @@ function vnAcl(aclService, $timeout) {
priority: -1,
link: function($scope, $element, $attrs) {
acls = $attrs.vnAcl.split(',').map(i => i.trim());
+
+ if (acls[0] == '') return;
+
let action = $attrs.vnAclAction || 'disabled';
let conditions = getDynamicConditions($attrs);
- permissionElement($element, action);
+
+ permissionElement($scope, $element, action);
if (Object.keys(conditions).length) {
let watchConditions = $scope.$watch(() => {
@@ -82,7 +86,7 @@ function vnAcl(aclService, $timeout) {
let hasPermission = $scope.$eval($attrs[attrName]);
if (!hasPermission) {
updateAcls(conditions[attrName].role, hasPermission);
- permissionElement($element, action);
+ permissionElement($scope, $element, action);
delete conditions[attrName];
}
});
diff --git a/front/core/locale/es.yml b/front/core/locale/es.yml
index 2a5af89ce..7c413dd22 100644
--- a/front/core/locale/es.yml
+++ b/front/core/locale/es.yml
@@ -39,4 +39,6 @@ November: Noviembre
December: Diciembre
Has delivery: Hay reparto
Loading: Cargando
-Fields to show: Campos a mostrar
\ No newline at end of file
+Fields to show: Campos a mostrar
+Create new one: Crear nuevo
+Toggle: Desplegar/Plegar
\ No newline at end of file
diff --git a/loopback/common/models/vn-model.js b/loopback/common/models/vn-model.js
index 539b4aa98..41287c2a7 100644
--- a/loopback/common/models/vn-model.js
+++ b/loopback/common/models/vn-model.js
@@ -128,44 +128,33 @@ module.exports = function(Self) {
return replaceErrFunc(err);
}
+ function rewriteMethod(methodName) {
+ const realMethod = this[methodName];
+ return async(data, options, cb) => {
+ if (options instanceof Function) {
+ cb = options;
+ options = null;
+ }
+
+ try {
+ await realMethod.call(this, data, options);
+ if (cb) cb();
+ } catch (err) {
+ let myErr = replaceErr(err, replaceErrFunc);
+ if (cb)
+ cb(myErr);
+ else
+ throw myErr;
+ }
+ };
+ }
+
this.once('attached', () => {
- let realUpsert = this.upsert;
- this.upsert = async(data, options, cb) => {
- if (options instanceof Function) {
- cb = options;
- options = null;
- }
-
- try {
- await realUpsert.call(this, data, options);
- if (cb) cb();
- } catch (err) {
- let myErr = replaceErr(err, replaceErrFunc);
- if (cb)
- cb(myErr);
- else
- throw myErr;
- }
- };
-
- let realCreate = this.create;
- this.create = async(data, options, cb) => {
- if (options instanceof Function) {
- cb = options;
- options = null;
- }
-
- try {
- await realCreate.call(this, data, options);
- if (cb) cb();
- } catch (err) {
- let myErr = replaceErr(err, replaceErrFunc);
- if (cb)
- cb(myErr);
- else
- throw myErr;
- }
- };
+ this.remove =
+ this.deleteAll =
+ this.destroyAll = rewriteMethod.call(this, 'remove');
+ this.upsert = rewriteMethod.call(this, 'upsert');
+ this.create = rewriteMethod.call(this, 'create');
});
},
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index 4cf5f65c1..d4f3733b0 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -72,5 +72,6 @@
"Error. El NIF/CIF está repetido": "Error. El NIF/CIF está repetido",
"Street cannot be empty": "Dirección no puede estar en blanco",
"City cannot be empty": "Cuidad no puede estar en blanco",
- "Code cannot be blank": "Código no puede estar en blanco"
+ "Code cannot be blank": "Código no puede estar en blanco",
+ "You cannot remove this department": "No puedes eliminar este departamento"
}
\ No newline at end of file
diff --git a/modules/agency/back/methods/zone-geo/getLeaves.js b/modules/agency/back/methods/zone-geo/getLeaves.js
index 64bb68318..7209f5268 100644
--- a/modules/agency/back/methods/zone-geo/getLeaves.js
+++ b/modules/agency/back/methods/zone-geo/getLeaves.js
@@ -73,7 +73,7 @@ module.exports = Self => {
zg.rgt,
zg.depth,
zg.sons,
- IF(ch.id = zg.id, isIncluded, null) isIncluded
+ IF(ch.id = zg.id, isIncluded, null) selected
FROM zoneGeo zg
JOIN tmp.checkedChilds ch
ON zg.lft <= ch.lft AND zg.rgt >= ch.rgt
@@ -86,7 +86,7 @@ module.exports = Self => {
child.rgt,
child.depth,
child.sons,
- zi.isIncluded
+ zi.isIncluded AS selected
FROM zoneGeo parent
JOIN zoneGeo child ON child.lft > parent.lft
AND child.rgt < parent.rgt
@@ -122,9 +122,11 @@ module.exports = Self => {
function nestLeaves(elements) {
elements.forEach(element => {
- element.childs = Object.assign([], getLeaves(element));
-
- nestLeaves(element.childs);
+ let childs = Object.assign([], getLeaves(element));
+ if (childs.length > 0) {
+ element.childs = childs;
+ nestLeaves(element.childs);
+ }
});
}
@@ -142,12 +144,12 @@ module.exports = Self => {
function sortNodes(nodes) {
return nodes.sort((a, b) => {
- if (b.isIncluded !== a.isIncluded) {
- if (a.isIncluded == null)
+ if (b.selected !== a.selected) {
+ if (a.selected == null)
return 1;
- if (b.isIncluded == null)
+ if (b.selected == null)
return -1;
- return b.isIncluded - a.isIncluded;
+ return b.selected - a.selected;
}
return a.name.localeCompare(b.name);
diff --git a/modules/agency/front/location/index.html b/modules/agency/front/location/index.html
index 4482ff52e..c33a71e3c 100644
--- a/modules/agency/front/location/index.html
+++ b/modules/agency/front/location/index.html
@@ -12,7 +12,7 @@
on-search="$ctrl.onSearch()"
vn-focus>
-
diff --git a/modules/worker/back/methods/department/getLeaves.js b/modules/worker/back/methods/department/getLeaves.js
new file mode 100644
index 000000000..a97dc4f1d
--- /dev/null
+++ b/modules/worker/back/methods/department/getLeaves.js
@@ -0,0 +1,87 @@
+
+const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
+
+module.exports = Self => {
+ Self.remoteMethod('getLeaves', {
+ description: 'Returns the first shipped and landed possible for params',
+ accessType: '',
+ accepts: [{
+ arg: 'parentFk',
+ type: 'Number',
+ default: 1,
+ required: false,
+ },
+ {
+ arg: 'filter',
+ type: 'Object',
+ description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
+ http: {source: 'query'}
+ }],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/getLeaves`,
+ verb: 'GET'
+ }
+ });
+
+ Self.getLeaves = async(parentFk = 1, filter) => {
+ let conn = Self.dataSource.connector;
+ let stmt = new ParameterizedSQL(
+ `SELECT
+ child.id,
+ child.name,
+ child.lft,
+ child.rgt,
+ child.depth,
+ child.sons
+ FROM department parent
+ JOIN department child ON child.lft > parent.lft
+ AND child.rgt < parent.rgt
+ AND child.depth = parent.depth + 1
+ WHERE parent.id = ?`, [parentFk]);
+
+ // Get nodes from depth greather than Origin
+ stmt.merge(conn.makeSuffix(filter));
+
+ const nodes = await Self.rawStmt(stmt);
+
+ 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 leaves = Object.assign([], parentNodes);
+
+ nestLeaves(leaves);
+
+ function nestLeaves(elements) {
+ elements.forEach(element => {
+ let childs = Object.assign([], getLeaves(element));
+ if (childs.length > 0) {
+ element.childs = childs;
+ 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;
+ };
+};
diff --git a/modules/worker/back/methods/department/nodeAdd.js b/modules/worker/back/methods/department/nodeAdd.js
new file mode 100644
index 000000000..bbbcd82ef
--- /dev/null
+++ b/modules/worker/back/methods/department/nodeAdd.js
@@ -0,0 +1,43 @@
+
+const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
+
+module.exports = Self => {
+ Self.remoteMethod('nodeAdd', {
+ description: 'Returns the first shipped and landed possible for params',
+ accessType: '',
+ accepts: [{
+ arg: 'parentFk',
+ type: 'Number',
+ required: false,
+ },
+ {
+ arg: 'name',
+ type: 'String',
+ required: true,
+ }],
+ returns: {
+ type: 'object',
+ root: true
+ },
+ http: {
+ path: `/nodeAdd`,
+ verb: 'POST'
+ }
+ });
+
+ Self.nodeAdd = async(parentFk = 1, name) => {
+ let stmts = [];
+ let conn = Self.dataSource.connector;
+ let nodeIndex = stmts.push(new ParameterizedSQL(
+ `CALL nst.NodeAdd('vn', 'department', ?, ?)`, [parentFk, name])) - 1;
+
+ stmts.push(`CALL nst.nodeRecalc('vn', 'department')`);
+
+
+ let sql = ParameterizedSQL.join(stmts, ';');
+ let result = await conn.executeStmt(sql);
+ let [node] = result[nodeIndex];
+
+ return node;
+ };
+};
diff --git a/modules/worker/back/methods/department/nodeDelete.js b/modules/worker/back/methods/department/nodeDelete.js
new file mode 100644
index 000000000..22cf5312c
--- /dev/null
+++ b/modules/worker/back/methods/department/nodeDelete.js
@@ -0,0 +1,29 @@
+
+const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
+
+module.exports = Self => {
+ Self.remoteMethod('nodeDelete', {
+ description: 'Returns the first shipped and landed possible for params',
+ accessType: '',
+ accepts: [{
+ arg: 'parentFk',
+ type: 'Number',
+ required: false,
+ }],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/nodeDelete`,
+ verb: 'POST'
+ }
+ });
+
+ Self.nodeDelete = async parentFk => {
+ let stmt = new ParameterizedSQL(
+ `CALL nst.nodeDelete('vn', 'department', ?)`, [parentFk]);
+
+ return await Self.rawStmt(stmt);
+ };
+};
diff --git a/modules/worker/back/models/department.js b/modules/worker/back/models/department.js
new file mode 100644
index 000000000..99b470dbb
--- /dev/null
+++ b/modules/worker/back/models/department.js
@@ -0,0 +1,19 @@
+const UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+ require('../methods/department/getLeaves')(Self);
+ require('../methods/department/nodeAdd')(Self);
+ require('../methods/department/nodeDelete')(Self);
+
+ Self.rewriteDbError(function(err) {
+ if (err.code === 'ER_ROW_IS_REFERENCED_2')
+ return new UserError(`You cannot remove this department`);
+ return err;
+ });
+
+ Self.rewriteDbError(function(err) {
+ if (err.code === 'ER_DUP_ENTRY')
+ return new UserError(`The department name can't be repeated`);
+ return err;
+ });
+};
diff --git a/modules/worker/front/department/index.html b/modules/worker/front/department/index.html
new file mode 100644
index 000000000..7cf4bade7
--- /dev/null
+++ b/modules/worker/front/department/index.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+ New department
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/worker/front/department/index.js b/modules/worker/front/department/index.js
new file mode 100644
index 000000000..99d65a478
--- /dev/null
+++ b/modules/worker/front/department/index.js
@@ -0,0 +1,78 @@
+import ngModule from '../module';
+
+class Controller {
+ constructor($scope, $http, vnApp, $translate) {
+ this.$scope = $scope;
+ this.$http = $http;
+ this.vnApp = vnApp;
+ this.$translate = $translate;
+ this.params = {parentFk: 1};
+ this.icons = [{icon: 'delete', tooltip: 'Delete', callback: this.onDelete}];
+ this.newNode = {
+ name: ''
+ };
+ }
+
+ onCreate(parent) {
+ if (parent instanceof Object)
+ this.newNode.parentFk = parent.id;
+
+ this.selectedNode = {parent};
+ this.$scope.createNode.show();
+ }
+
+ onDelete(item, parent, index) {
+ this.selectedNode = {id: item.id, parent, index};
+ this.$scope.deleteNode.show();
+ }
+
+ onCreateDialogOpen() {
+ this.newNode.name = '';
+ }
+
+ onCreateResponse(response) {
+ if (response == 'ACCEPT') {
+ try {
+ if (!this.newNode.name)
+ throw new Error(`Name can't be empty`);
+
+ this.$http.post(`/worker/api/Departments/nodeAdd`, this.newNode).then(response => {
+ if (response.data) {
+ let parent = this.selectedNode.parent;
+ if ((parent instanceof Object) && !(parent instanceof Array)) {
+ const childs = parent.childs;
+ childs.push(response.data);
+ } else if ((parent instanceof Object) && (parent instanceof Array))
+ parent.push(response.data);
+ }
+ });
+ } catch (e) {
+ this.vnApp.showError(this.$translate.instant(e.message));
+ return false;
+ }
+ }
+ return true;
+ }
+
+ onRemoveResponse(response) {
+ if (response === 'ACCEPT') {
+ const path = `/worker/api/Departments/nodeDelete`;
+ this.$http.post(path, {parentFk: this.selectedNode.id}).then(() => {
+ let parent = this.selectedNode.parent;
+
+ if ((parent instanceof Object) && !(parent instanceof Array)) {
+ const childs = parent.childs;
+ childs.splice(this.selectedNode.index, 1);
+ } else if ((parent instanceof Object) && (parent instanceof Array))
+ parent.splice(this.selectedNode.index, 1);
+ });
+ }
+ }
+}
+
+Controller.$inject = ['$scope', '$http', 'vnApp', '$translate'];
+
+ngModule.component('vnWorkerDepartment', {
+ template: require('./index.html'),
+ controller: Controller
+});
diff --git a/modules/worker/front/department/locale/es.yml b/modules/worker/front/department/locale/es.yml
new file mode 100644
index 000000000..c481bf4a9
--- /dev/null
+++ b/modules/worker/front/department/locale/es.yml
@@ -0,0 +1,3 @@
+New department: Nuevo departamento
+Delete department: Eliminar departamento
+Are you sure you want to delete it?: ¿Seguro que quieres eliminarlo?
\ No newline at end of file
diff --git a/modules/worker/front/index.js b/modules/worker/front/index.js
index e9aa1424c..512e712c2 100644
--- a/modules/worker/front/index.js
+++ b/modules/worker/front/index.js
@@ -8,3 +8,4 @@ import './descriptor-popover';
import './search-panel';
import './basic-data';
import './pbx';
+import './department';
diff --git a/modules/worker/front/index/index.html b/modules/worker/front/index/index.html
index 6f679b3e9..703c82edd 100644
--- a/modules/worker/front/index/index.html
+++ b/modules/worker/front/index/index.html
@@ -8,11 +8,23 @@
-
-
+
+
+
+
+
+
this.$state.go('worker.department'), name: 'Departments'}
+ ];
}
onSearch(params) {
@@ -22,9 +27,13 @@ export default class Controller {
this.$.preview.show();
event.stopImmediatePropagation();
}
+
+ onMoreChange(callback) {
+ callback.call(this);
+ }
}
-Controller.$inject = ['$scope'];
+Controller.$inject = ['$scope', '$state'];
ngModule.component('vnWorkerIndex', {
template: require('./index.html'),
diff --git a/modules/worker/front/index/style.scss b/modules/worker/front/index/style.scss
new file mode 100644
index 000000000..f6ebf3828
--- /dev/null
+++ b/modules/worker/front/index/style.scss
@@ -0,0 +1,11 @@
+@import "variables";
+
+vn-worker-index vn-icon-menu {
+ padding-top: 30px;
+ padding-left: 10px;
+ color: $color-main;
+
+ li {
+ color: initial;
+ }
+}
\ No newline at end of file
diff --git a/modules/worker/front/locale/es.yml b/modules/worker/front/locale/es.yml
index d5d84a833..a7a47d654 100644
--- a/modules/worker/front/locale/es.yml
+++ b/modules/worker/front/locale/es.yml
@@ -13,3 +13,4 @@ View worker: Ver trabajador
Worker id: Id trabajador
Fiscal Identifier: NIF
User name: Usuario
+Departments: Departamentos
\ No newline at end of file
diff --git a/modules/worker/front/routes.json b/modules/worker/front/routes.json
index 7ef1237e0..73b503058 100644
--- a/modules/worker/front/routes.json
+++ b/modules/worker/front/routes.json
@@ -33,7 +33,8 @@
"component": "vn-worker-card",
"abstract": true,
"description": "Detail"
- }, {
+ },
+ {
"url": "/basic-data",
"state": "worker.card.basicData",
"component": "vn-worker-basic-data",
@@ -51,6 +52,12 @@
"worker": "$ctrl.worker"
},
"acl": ["hr"]
+ },
+ {
+ "url" : "/department",
+ "state": "worker.department",
+ "component": "vn-worker-department",
+ "description": "Departments"
}
]
}
\ No newline at end of file
diff --git a/print/report/rpt-sepa-core/index.js b/print/report/rpt-sepa-core/index.js
index 9c4ee6ac6..c98ddbcb4 100755
--- a/print/report/rpt-sepa-core/index.js
+++ b/print/report/rpt-sepa-core/index.js
@@ -11,7 +11,7 @@ module.exports = {
if (!params.companyFk)
throw new UserException('No company id specified');
- return this.methods.fetchClient(params.clientFk)
+ return this.methods.fetchClient(params.clientFk, params.companyFk)
.then(([[client]]) => {
if (!client)
throw new UserException('No client data found');
@@ -24,7 +24,7 @@ module.exports = {
this.$i18n.locale = this.locale;
},
methods: {
- fetchClient(clientFk) {
+ fetchClient(clientFk, companyFk) {
return database.pool.query(
`SELECT
c.id clientId,
@@ -46,12 +46,12 @@ module.exports = {
FROM client c
JOIN account.user u ON u.id = c.id
JOIN country ct ON ct.id = c.countryFk
+ JOIN mandate m ON m.clientFk = c.id AND m.finished IS NULL
+ JOIN supplier s ON s.id = m.companyFk
+ JOIN country sc ON sc.id = s.countryFk
+ JOIN province sp ON sp.id = s.provinceFk
LEFT JOIN province p ON p.id = c.provinceFk
- LEFT JOIN mandate m ON m.clientFk = c.id AND m.finished IS NULL
- LEFT JOIN supplier s ON s.id = m.companyFk
- LEFT JOIN country sc ON sc.id = s.countryFk
- LEFT JOIN province sp ON sp.id = s.provinceFk
- WHERE c.id = ?`, [clientFk]);
+ WHERE m.companyFk = ? AND c.id = ?`, [companyFk, clientFk]);
},
dated: () => {
return strftime('%d-%m-%Y', new Date());