This commit is contained in:
Carlos Jimenez Ruiz 2019-03-13 08:21:42 +01:00
commit a1539516b7
32 changed files with 685 additions and 95 deletions

View File

@ -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

View File

@ -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');
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');

View File

@ -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`; */

View File

@ -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 ;
*/

View File

@ -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 ;
*/

View File

@ -0,0 +1 @@
ALTER TABLE vn.itemLog MODIFY COLUMN userFk int(10) unsigned NULL;

View File

@ -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);

View File

@ -1,25 +1,54 @@
<ul ng-if="$ctrl.items">
<ul ng-if="::$ctrl.items">
<li ng-repeat="item in $ctrl.items"
ng-class="{
'expanded': item.active,
'collapsed': !item.active,
'included': item.isIncluded == 1,
'excluded': item.isIncluded == 0
'included': item.selected == 1,
'excluded': item.selected == 0
}">
<vn-horizontal>
<vn-auto class="actions">
<vn-icon icon="keyboard_arrow_down"
ng-show="item.sons > 0"
ng-click="$ctrl.toggle(item, $event)" >
<vn-icon icon="keyboard_arrow_down" title="{{'Toggle' | translate}}"
ng-click="$ctrl.toggle(item, $event)">
</vn-icon>
</vn-auto>
<div class="description">
<vn-check vn-auto field="item.isIncluded"
on-change="$ctrl.select(item, value)" triple-state="true">
<vn-one class="description">
<vn-check vn-auto vn-acl="{{$ctrl.aclRole}}"
ng-if="$ctrl.selectable"
field="item.selected"
disabled="$ctrl.disabled"
on-change="$ctrl.select(item, value)"
triple-state="true">
</vn-check>
{{::item.name}}
{{::item.name}}
</vn-one>
<vn-auto>
<vn-icon-button icon="{{icon.icon}}"
ng-repeat="icon in $ctrl.icons"
ng-click="$ctrl.onClick(icon, item, $ctrl.parent, $parent.$index)"
vn-acl="{{$ctrl.aclRole}}" vn-acl-action="remove">
</vn-icon-button>
</vn-auto>
</vn-horizontal>
<vn-treeview-child items="item.childs" parent="item"
selectable="$ctrl.selectable"
disabled="$ctrl.disabled"
editable="$ctrl.editable"
icons="$ctrl.icons"
acl-role="$ctrl.aclRole">
</vn-treeview-child>
</li>
<li ng-if="$ctrl.isInsertable && $ctrl.editable"
ng-click="$ctrl.onCreate($ctrl.parent)"
vn-acl="{{$ctrl.aclRole}}"
vn-acl-action="remove">
<vn-horizontal>
<vn-auto>
<vn-icon-button icon="add_circle"></vn-icon-button>
</vn-auto>
<div class="description" translate>
Create new one
</div>
</vn-horizontal>
<vn-treeview-child items="item.childs"></vn-treeview-child>
</li>
</ul>

View File

@ -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'

View File

@ -1 +1,9 @@
<vn-treeview-child items="$ctrl.data"></vn-treeview-child>
<vn-treeview-child
items="$ctrl.data"
parent="$ctrl.data"
selectable="$ctrl.selectable"
editable="$ctrl.editable"
disabled="$ctrl.disabled"
icons="$ctrl.icons"
acl-role="$ctrl.aclRole">
</vn-treeview-child>

View File

@ -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: '@?'
}
});

View File

@ -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
}
}

View File

@ -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];
}
});

View File

@ -39,4 +39,6 @@ November: Noviembre
December: Diciembre
Has delivery: Hay reparto
Loading: Cargando
Fields to show: Campos a mostrar
Fields to show: Campos a mostrar
Create new one: Crear nuevo
Toggle: Desplegar/Plegar

View File

@ -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');
});
},

View File

@ -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"
}

View File

@ -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);

View File

@ -12,7 +12,7 @@
on-search="$ctrl.onSearch()"
vn-focus>
</vn-searchbar>
<vn-treeview vn-id="treeview" model="model"
<vn-treeview vn-id="treeview" model="model" selectable="true" acl-role="deliveryBoss"
on-selection="$ctrl.onSelection(item, value)">
</vn-treeview>
</vn-card>

View File

@ -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;
};
};

View File

@ -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;
};
};

View File

@ -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);
};
};

View File

@ -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;
});
};

View File

@ -0,0 +1,45 @@
<vn-crud-model
vn-id="model"
url="/worker/api/departments/getLeaves"
params="::$ctrl.params"
auto-load="false">
</vn-crud-model>
<form name="form">
<div margin-medium>
<vn-card margin-medium-v pad-medium>
<vn-treeview vn-id="treeview" model="model"
on-selection="$ctrl.onSelection(item, value)"
on-create="$ctrl.onCreate(parent)"
icons="$ctrl.icons" editable="true" acl-role="hr">
</vn-treeview>
</vn-card>
</div>
</form>
<vn-confirm
vn-id="deleteNode"
on-response="$ctrl.onRemoveResponse(response)"
question="Delete department"
message="Are you sure you want to delete it?">
</vn-confirm>
<!-- Create department dialog -->
<vn-dialog
vn-id="createNode"
on-open="$ctrl.onCreateDialogOpen()"
on-response="$ctrl.onCreateResponse(response)">
<tpl-body>
<h5 pad-small-v translate>New department</h5>
<vn-horizontal>
<vn-textfield vn-one
label="Name"
model="$ctrl.newNode.name">
</vn-textfield>
</vn-horizontal>
</tpl-body>
<tpl-buttons>
<input type="button" response="CANCEL" translate-attr="{value: 'Cancel'}"/>
<button response="ACCEPT" translate>Create</button>
</tpl-buttons>
</vn-dialog>

View File

@ -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
});

View File

@ -0,0 +1,3 @@
New department: Nuevo departamento
Delete department: Eliminar departamento
Are you sure you want to delete it?: ¿Seguro que quieres eliminarlo?

View File

@ -8,3 +8,4 @@ import './descriptor-popover';
import './search-panel';
import './basic-data';
import './pbx';
import './department';

View File

@ -8,11 +8,23 @@
<div class="content-block">
<div class="vn-list">
<vn-card pad-medium-h>
<vn-searchbar
panel="vn-worker-search-panel"
on-search="$ctrl.onSearch($params)"
vn-focus>
</vn-searchbar>
<vn-horizontal>
<vn-searchbar
style="width: 100%"
panel="vn-worker-search-panel"
on-search="$ctrl.onSearch($params)"
vn-focus>
</vn-searchbar>
<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>
</vn-horizontal>
</vn-card>
<vn-card margin-medium-v>
<a

View File

@ -1,11 +1,16 @@
import ngModule from '../module';
import './style.scss';
export default class Controller {
constructor($) {
constructor($, $state) {
this.$state = $state;
Object.assign(this, {
$,
selectedWorker: null,
});
this.moreOptions = [
{callback: () => 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'),

View File

@ -0,0 +1,11 @@
@import "variables";
vn-worker-index vn-icon-menu {
padding-top: 30px;
padding-left: 10px;
color: $color-main;
li {
color: initial;
}
}

View File

@ -13,3 +13,4 @@ View worker: Ver trabajador
Worker id: Id trabajador
Fiscal Identifier: NIF
User name: Usuario
Departments: Departamentos

View File

@ -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"
}
]
}

View File

@ -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());