Merge
This commit is contained in:
commit
fc09d76422
|
@ -0,0 +1,83 @@
|
|||
ALTER TABLE `vn2008`.`department`
|
||||
ADD COLUMN `parentFk` INT UNSIGNED NULL AFTER `sons`,
|
||||
ADD COLUMN `path` VARCHAR(255) NULL AFTER `parentFk`,
|
||||
CHANGE COLUMN `sons` `sons` DECIMAL(10,0) NOT NULL DEFAULT '0' ;
|
||||
|
||||
USE `vn`;
|
||||
CREATE
|
||||
OR REPLACE ALGORITHM = UNDEFINED
|
||||
DEFINER = `root`@`%`
|
||||
SQL SECURITY DEFINER
|
||||
VIEW `department` AS
|
||||
SELECT
|
||||
`b`.`department_id` AS `id`,
|
||||
`b`.`name` AS `name`,
|
||||
`b`.`production` AS `isProduction`,
|
||||
`b`.`parentFk` AS `parentFk`,
|
||||
`b`.`path` AS `path`,
|
||||
`b`.`lft` AS `lft`,
|
||||
`b`.`rgt` AS `rgt`,
|
||||
`b`.`isSelected` AS `isSelected`,
|
||||
`b`.`depth` AS `depth`,
|
||||
`b`.`sons` AS `sons`
|
||||
FROM
|
||||
`vn2008`.`department` `b`;
|
||||
|
||||
DROP TRIGGER IF EXISTS `vn2008`.`department_AFTER_DELETE`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn2008`$$
|
||||
CREATE DEFINER = CURRENT_USER TRIGGER `vn2008`.`department_AFTER_DELETE`
|
||||
AFTER DELETE ON `department` FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE vn.department_recalc SET isChanged = TRUE;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS `vn2008`.`department_BEFORE_INSERT`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn2008`$$
|
||||
CREATE DEFINER = CURRENT_USER TRIGGER `vn2008`.`department_BEFORE_INSERT`
|
||||
BEFORE INSERT ON `department` FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE vn.department_recalc SET isChanged = TRUE;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS `vn2008`.`department_AFTER_UPDATE`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn2008`$$
|
||||
CREATE DEFINER = CURRENT_USER TRIGGER `vn2008`.`department_AFTER_UPDATE`
|
||||
AFTER UPDATE ON `department` FOR EACH ROW
|
||||
BEGIN
|
||||
IF !(OLD.parentFk <=> NEW.parentFk) THEN
|
||||
UPDATE vn.department_recalc SET isChanged = TRUE;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CREATE TABLE `vn`.`department_recalc` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`isChanged` TINYINT(4) NOT NULL,
|
||||
PRIMARY KEY (`id`));
|
||||
|
||||
INSERT INTO `vn`.`department_recalc` (`id`, `isChanged`) VALUES ('1', '0');
|
||||
|
||||
|
||||
ALTER TABLE `vn2008`.`department`
|
||||
CHANGE COLUMN `lft` `lft` INT(11) NULL ,
|
||||
CHANGE COLUMN `rgt` `rgt` INT(11) NULL ;
|
||||
|
||||
ALTER TABLE `vn2008`.`department`
|
||||
DROP INDEX `rgt_UNIQUE` ,
|
||||
DROP INDEX `lft_UNIQUE` ;
|
||||
;
|
||||
|
||||
ALTER TABLE `vn2008`.`department`
|
||||
ADD INDEX `lft_rgt_depth_idx` (`lft` ASC, `rgt` ASC, `depth` ASC);
|
||||
;
|
||||
|
||||
|
||||
UPDATE vn.department SET lft = NULL, rgt = NULL;
|
|
@ -0,0 +1,37 @@
|
|||
USE `vn`;
|
||||
DROP procedure IF EXISTS `department_calcTree`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` PROCEDURE `department_calcTree`()
|
||||
BEGIN
|
||||
/**
|
||||
* Calculates the #path, #lft, #rgt, #sons and #depth columns of
|
||||
* the #department table. To build the tree, it uses the #parentFk
|
||||
* column.
|
||||
*/
|
||||
DECLARE vIndex INT DEFAULT 0;
|
||||
DECLARE vSons INT;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tNestedTree;
|
||||
CREATE TEMPORARY TABLE tNestedTree
|
||||
SELECT id, path, lft, rgt, depth, sons
|
||||
FROM department LIMIT 0;
|
||||
|
||||
SET max_sp_recursion_depth = 5;
|
||||
CALL department_calcTreeRec(NULL, '/', 0, vIndex, vSons);
|
||||
SET max_sp_recursion_depth = 0;
|
||||
|
||||
UPDATE department z
|
||||
JOIN tNestedTree t ON t.id = z.id
|
||||
SET z.path = t.path,
|
||||
z.lft = t.lft,
|
||||
z.rgt = t.rgt,
|
||||
z.depth = t.depth,
|
||||
z.sons = t.sons;
|
||||
|
||||
DROP TEMPORARY TABLE tNestedTree;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
USE `vn`;
|
||||
DROP procedure IF EXISTS `department_calcTreeRec`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` PROCEDURE `department_calcTreeRec`(
|
||||
vSelf INT,
|
||||
vPath VARCHAR(255),
|
||||
vDepth INT,
|
||||
INOUT vIndex INT,
|
||||
OUT vSons INT
|
||||
)
|
||||
BEGIN
|
||||
/**
|
||||
* Calculates and sets the #path, #lft, #rgt, #sons and #depth
|
||||
* columns for all children of the passed node. Once calculated
|
||||
* the last node rgt index and the number of sons are returned.
|
||||
* To update it's children, this procedure calls itself recursively
|
||||
* for each one.
|
||||
*
|
||||
* @vSelf The node identifier
|
||||
* @vPath The initial path
|
||||
* @vDepth The initial depth
|
||||
* @vIndex The initial lft index
|
||||
* @vSons The number of direct sons
|
||||
*/
|
||||
DECLARE vChildFk INT;
|
||||
DECLARE vLft INT;
|
||||
DECLARE vMySons INT;
|
||||
DECLARE vDone BOOL;
|
||||
DECLARE vChildren CURSOR FOR
|
||||
SELECT id FROM department
|
||||
WHERE (vSelf IS NULL AND parentFk IS NULL)
|
||||
OR (vSelf IS NOT NULL AND parentFk = vSelf);
|
||||
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||
|
||||
SET vSons = 0;
|
||||
|
||||
OPEN vChildren;
|
||||
myLoop: LOOP
|
||||
SET vDone = FALSE;
|
||||
FETCH vChildren INTO vChildFk;
|
||||
|
||||
IF vDone THEN
|
||||
LEAVE myLoop;
|
||||
END IF;
|
||||
|
||||
SET vIndex = vIndex + 1;
|
||||
SET vLft = vIndex;
|
||||
SET vSons = vSons + 1;
|
||||
|
||||
CALL department_calcTreeRec(
|
||||
vChildFk,
|
||||
CONCAT(vPath, vChildFk, '/'),
|
||||
vDepth + 1,
|
||||
vIndex,
|
||||
vMySons
|
||||
);
|
||||
|
||||
SET vIndex = vIndex + 1;
|
||||
|
||||
INSERT INTO tNestedTree
|
||||
SET id = vChildFk,
|
||||
path = vPath,
|
||||
lft = vLft,
|
||||
rgt = vIndex,
|
||||
depth = vDepth,
|
||||
sons = vMySons;
|
||||
END LOOP;
|
||||
CLOSE vChildren;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
USE `vn`;
|
||||
DROP procedure IF EXISTS `department_doCalc`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` PROCEDURE `department_doCalc`()
|
||||
proc: BEGIN
|
||||
/**
|
||||
* Recalculates the department tree.
|
||||
*/
|
||||
DECLARE vIsChanged BOOL;
|
||||
|
||||
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
|
||||
BEGIN
|
||||
DO RELEASE_LOCK('vn.department_doCalc');
|
||||
RESIGNAL;
|
||||
END;
|
||||
|
||||
IF !GET_LOCK('vn.department_doCalc', 0) THEN
|
||||
LEAVE proc;
|
||||
END IF;
|
||||
|
||||
SELECT isChanged INTO vIsChanged
|
||||
FROM department_recalc;
|
||||
|
||||
IF vIsChanged THEN
|
||||
UPDATE department_recalc SET isChanged = FALSE;
|
||||
CALL vn.department_calcTree;
|
||||
END IF;
|
||||
|
||||
DO RELEASE_LOCK('vn.department_doCalc');
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
USE `vn`;
|
||||
DROP procedure IF EXISTS `department_getLeaves`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` PROCEDURE `department_getLeaves`(
|
||||
vParentFk INT,
|
||||
vSearch VARCHAR(255)
|
||||
)
|
||||
BEGIN
|
||||
DECLARE vIsNumber BOOL;
|
||||
DECLARE vIsSearch BOOL DEFAULT vSearch IS NOT NULL AND vSearch != '';
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tNodes;
|
||||
CREATE TEMPORARY TABLE tNodes
|
||||
(UNIQUE (id))
|
||||
ENGINE = MEMORY
|
||||
SELECT id FROM department LIMIT 0;
|
||||
|
||||
IF vIsSearch THEN
|
||||
SET vIsNumber = vSearch REGEXP '^[0-9]+$';
|
||||
|
||||
INSERT INTO tNodes
|
||||
SELECT id FROM department
|
||||
WHERE (vIsNumber AND `name` = vSearch)
|
||||
OR (!vIsNumber AND `name` LIKE CONCAT('%', vSearch, '%'))
|
||||
LIMIT 1000;
|
||||
END IF;
|
||||
|
||||
IF vParentFk IS NULL THEN
|
||||
DROP TEMPORARY TABLE IF EXISTS tChilds;
|
||||
CREATE TEMPORARY TABLE tChilds
|
||||
ENGINE = MEMORY
|
||||
SELECT id FROM tNodes;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tParents;
|
||||
CREATE TEMPORARY TABLE tParents
|
||||
ENGINE = MEMORY
|
||||
SELECT id FROM department LIMIT 0;
|
||||
|
||||
myLoop: LOOP
|
||||
DELETE FROM tParents;
|
||||
INSERT INTO tParents
|
||||
SELECT parentFk id
|
||||
FROM department g
|
||||
JOIN tChilds c ON c.id = g.id
|
||||
WHERE g.parentFk IS NOT NULL;
|
||||
|
||||
INSERT IGNORE INTO tNodes
|
||||
SELECT id FROM tParents;
|
||||
|
||||
IF ROW_COUNT() = 0 THEN
|
||||
LEAVE myLoop;
|
||||
END IF;
|
||||
|
||||
DELETE FROM tChilds;
|
||||
INSERT INTO tChilds
|
||||
SELECT id FROM tParents;
|
||||
END LOOP;
|
||||
|
||||
DROP TEMPORARY TABLE
|
||||
tChilds,
|
||||
tParents;
|
||||
END IF;
|
||||
|
||||
IF !vIsSearch THEN
|
||||
INSERT IGNORE INTO tNodes
|
||||
SELECT id FROM department
|
||||
WHERE parentFk <=> vParentFk;
|
||||
END IF;
|
||||
|
||||
SELECT d.id,
|
||||
d.`name`,
|
||||
d.parentFk,
|
||||
d.sons
|
||||
FROM department d
|
||||
JOIN tNodes n ON n.id = d.id
|
||||
ORDER BY depth, `name`;
|
||||
|
||||
DROP TEMPORARY TABLE tNodes;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
|
|
@ -260,6 +260,7 @@ export default {
|
|||
submitItemTagsButton: `vn-item-tags ${components.vnSubmit}`
|
||||
},
|
||||
itemTax: {
|
||||
undoChangesButton: 'vn-item-tax vn-button-bar > vn-button[label="Undo changes"]',
|
||||
firstClassAutocomplete: 'vn-item-tax vn-horizontal:nth-child(1) > vn-autocomplete[field="tax.taxClassFk"]',
|
||||
secondClassAutocomplete: 'vn-item-tax vn-horizontal:nth-child(2) > vn-autocomplete[field="tax.taxClassFk"]',
|
||||
thirdClassAutocomplete: 'vn-item-tax vn-horizontal:nth-child(3) > vn-autocomplete[field="tax.taxClassFk"]',
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import createNightmare from '../../helpers/nightmare';
|
||||
|
||||
// #1702 Autocomplete no siempre refresca al cancelar formulario
|
||||
xdescribe('Item edit tax path', () => {
|
||||
describe('Item edit tax path', () => {
|
||||
const nightmare = createNightmare();
|
||||
|
||||
beforeAll(() => {
|
||||
|
@ -14,9 +13,9 @@ xdescribe('Item edit tax path', () => {
|
|||
|
||||
it(`should add the item tax to all countries`, async() => {
|
||||
const result = await nightmare
|
||||
.autocompleteSearch(selectors.itemTax.firstClassAutocomplete, 'Reduced VAT')
|
||||
.autocompleteSearch(selectors.itemTax.firstClassAutocomplete, 'General VAT')
|
||||
.autocompleteSearch(selectors.itemTax.secondClassAutocomplete, 'General VAT')
|
||||
.autocompleteSearch(selectors.itemTax.thirdClassAutocomplete, 'Reduced VAT')
|
||||
.autocompleteSearch(selectors.itemTax.thirdClassAutocomplete, 'General VAT')
|
||||
.waitToClick(selectors.itemTax.submitTaxButton)
|
||||
.waitForLastSnackbar();
|
||||
|
||||
|
@ -28,7 +27,7 @@ xdescribe('Item edit tax path', () => {
|
|||
.reloadSection('item.card.tax')
|
||||
.waitToGetProperty(`${selectors.itemTax.firstClassAutocomplete} input`, 'value');
|
||||
|
||||
expect(firstVatType).toEqual('Reduced VAT');
|
||||
expect(firstVatType).toEqual('General VAT');
|
||||
});
|
||||
|
||||
it(`should confirm the second item tax class was edited`, async() => {
|
||||
|
@ -42,6 +41,22 @@ xdescribe('Item edit tax path', () => {
|
|||
const thirdVatType = await nightmare
|
||||
.waitToGetProperty(`${selectors.itemTax.thirdClassAutocomplete} input`, 'value');
|
||||
|
||||
expect(thirdVatType).toEqual('Reduced VAT');
|
||||
expect(thirdVatType).toEqual('General VAT');
|
||||
});
|
||||
|
||||
it(`should edit the first class without saving the form`, async() => {
|
||||
const firstVatType = await nightmare
|
||||
.autocompleteSearch(selectors.itemTax.firstClassAutocomplete, 'Reduced VAT')
|
||||
.waitToGetProperty(`${selectors.itemTax.firstClassAutocomplete} input`, 'value');
|
||||
|
||||
expect(firstVatType).toEqual('Reduced VAT');
|
||||
});
|
||||
|
||||
it(`should now click the undo changes button and see the changes works`, async() => {
|
||||
const firstVatType = await nightmare
|
||||
.waitToClick(selectors.itemTax.undoChangesButton)
|
||||
.waitToGetProperty(`${selectors.itemTax.firstClassAutocomplete} input`, 'value');
|
||||
|
||||
expect(firstVatType).toEqual('General VAT');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -121,8 +121,8 @@ export default class Autocomplete extends Field {
|
|||
return;
|
||||
|
||||
const selection = this.fetchSelection();
|
||||
if (!this.selection)
|
||||
this.selection = selection;
|
||||
|
||||
this.selection = selection;
|
||||
}
|
||||
|
||||
fetchSelection() {
|
||||
|
|
|
@ -3,23 +3,28 @@ import './style.scss';
|
|||
|
||||
export default class IconButton {
|
||||
constructor($element) {
|
||||
if ($element[0].getAttribute('tabindex') == null)
|
||||
$element[0].tabIndex = 0;
|
||||
this.element = $element[0];
|
||||
|
||||
$element.on('keyup', event => this.onKeyDown(event, $element));
|
||||
let button = $element[0].querySelector('button');
|
||||
$element[0].addEventListener('click', event => {
|
||||
if (this.disabled || button.disabled)
|
||||
event.stopImmediatePropagation();
|
||||
});
|
||||
if (this.element.getAttribute('tabindex') == null)
|
||||
this.element.tabIndex = 0;
|
||||
|
||||
this.element.addEventListener('keyup', e => this.onKeyup(e));
|
||||
this.element.addEventListener('click', e => this.onClick(e));
|
||||
}
|
||||
|
||||
onKeyDown(event, $element) {
|
||||
onKeyup(event) {
|
||||
if (event.code == 'Space')
|
||||
this.onClick(event);
|
||||
}
|
||||
|
||||
onClick(event) {
|
||||
if (event.defaultPrevented) return;
|
||||
if (event.keyCode == 13) {
|
||||
event.preventDefault();
|
||||
$element.triggerHandler('click');
|
||||
}
|
||||
event.preventDefault();
|
||||
|
||||
// FIXME: Don't use Event.stopPropagation()
|
||||
let button = this.element.querySelector('button');
|
||||
if (this.disabled || button.disabled)
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,4 +45,3 @@ import './table';
|
|||
import './td-editable';
|
||||
import './th';
|
||||
import './treeview';
|
||||
import './treeview/child';
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
<ul ng-if="::$ctrl.items">
|
||||
<li
|
||||
ng-repeat="item in $ctrl.items"
|
||||
on-drop="$ctrl.onDrop(item, dragged, dropped)"
|
||||
vn-draggable="{{::$ctrl.draggable}}"
|
||||
vn-droppable="{{::$ctrl.droppable}}"
|
||||
ng-class="{expanded: item.active}">
|
||||
<div
|
||||
ng-click="$ctrl.toggle($event, item)"
|
||||
class="node clickable">
|
||||
<vn-icon
|
||||
class="arrow"
|
||||
ng-class="{invisible: item.sons == 0}"
|
||||
icon="keyboard_arrow_down"
|
||||
translate-attr="{title: 'Toggle'}">
|
||||
</vn-icon>
|
||||
<vn-check
|
||||
vn-acl="{{$ctrl.aclRole}}"
|
||||
ng-if="$ctrl.selectable"
|
||||
field="item.selected"
|
||||
disabled="$ctrl.disabled"
|
||||
on-change="$ctrl.select(item, value)"
|
||||
triple-state="true"
|
||||
label="{{::item.name}}">
|
||||
</vn-check>
|
||||
<vn-icon-button
|
||||
icon="{{icon.icon}}"
|
||||
ng-repeat="icon in $ctrl.icons"
|
||||
ng-click="$ctrl.onIconClick(icon, item, $ctrl.parent, $parent.$index)"
|
||||
vn-acl="{{$ctrl.aclRole}}"
|
||||
vn-acl-action="remove">
|
||||
</vn-icon-button>
|
||||
</div>
|
||||
<vn-treeview-child
|
||||
items="item.childs"
|
||||
parent="item"
|
||||
selectable="$ctrl.selectable"
|
||||
disabled="$ctrl.disabled"
|
||||
editable="$ctrl.editable"
|
||||
draggable="::$ctrl.draggable"
|
||||
droppable="::$ctrl.droppable"
|
||||
icons="::$ctrl.icons"
|
||||
parent-scope="::$ctrl.parentScope"
|
||||
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">
|
||||
<div class="node">
|
||||
<vn-icon-button
|
||||
icon="add_circle">
|
||||
</vn-icon-button>
|
||||
<div class="description" translate>
|
||||
Create new one
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
|
@ -1,56 +0,0 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from '../../lib/component';
|
||||
|
||||
class Controller extends Component {
|
||||
constructor($element, $scope) {
|
||||
super($element, $scope);
|
||||
this.$scope = $scope;
|
||||
}
|
||||
|
||||
toggle(event, item) {
|
||||
if (event.defaultPrevented || !item.sons) return;
|
||||
event.preventDefault();
|
||||
this.treeview.onToggle(item);
|
||||
}
|
||||
|
||||
select(item, value) {
|
||||
this.treeview.onSelection(item, value);
|
||||
}
|
||||
|
||||
onIconClick(icon, item, parent, index) {
|
||||
let parentController = this.parentScope.$ctrl;
|
||||
icon.callback.call(parentController, item, parent, index);
|
||||
}
|
||||
|
||||
onCreate(parent) {
|
||||
this.treeview.onCreate(parent);
|
||||
}
|
||||
|
||||
onDrop(item, dragged, dropped) {
|
||||
this.treeview.onDrop(item, dragged, dropped);
|
||||
}
|
||||
|
||||
get isInsertable() {
|
||||
return Array.isArray(this.parent) || this.parent.childs;
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnTreeviewChild', {
|
||||
template: require('./child.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
items: '<',
|
||||
parent: '<',
|
||||
icons: '<?',
|
||||
disabled: '<?',
|
||||
selectable: '<?',
|
||||
editable: '<?',
|
||||
draggable: '<?',
|
||||
droppable: '<?',
|
||||
aclRole: '<?',
|
||||
parentScope: '<'
|
||||
},
|
||||
require: {
|
||||
treeview: '^vnTreeview'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
<ul ng-if="$ctrl.items">
|
||||
<li ng-repeat="item in $ctrl.items" >
|
||||
<div
|
||||
ng-class="{expanded: item.active}"
|
||||
ng-click="$ctrl.onClick($event, item)"
|
||||
class="node clickable">
|
||||
<vn-icon
|
||||
class="arrow"
|
||||
ng-class="{invisible: !item.sons}"
|
||||
icon="keyboard_arrow_down"
|
||||
translate-attr="::{title: 'Toggle'}">
|
||||
</vn-icon>
|
||||
<vn-treeview-content
|
||||
item="::item">
|
||||
</vn-treeview-content>
|
||||
<section class="buttons" ng-if="::!$ctrl.treeview.readOnly">
|
||||
<vn-icon-button translate-attr="::{title: 'Remove'}"
|
||||
icon="delete"
|
||||
ng-click="$ctrl.treeview.onRemove(item)"
|
||||
ng-if="item.parent">
|
||||
</vn-icon-button>
|
||||
<vn-icon-button translate-attr="::{title: 'Create'}"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.treeview.onCreate(item)">
|
||||
</vn-icon-button>
|
||||
</section>
|
||||
</div>
|
||||
<vn-treeview-childs
|
||||
items="item.childs"
|
||||
parent="::item">
|
||||
</vn-treeview-childs>
|
||||
</li>
|
||||
</ul>
|
|
@ -0,0 +1,26 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from '../../lib/component';
|
||||
|
||||
class Controller extends Component {
|
||||
onClick(event, item) {
|
||||
if (event.defaultPrevented || !item.sons) return;
|
||||
event.preventDefault();
|
||||
this.treeview.onToggle(item);
|
||||
}
|
||||
|
||||
onDrop(item, dragged, dropped) {
|
||||
this.treeview.onDrop(item, dragged, dropped);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnTreeviewChilds', {
|
||||
template: require('./childs.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
items: '<',
|
||||
parent: '<?'
|
||||
},
|
||||
require: {
|
||||
treeview: '^vnTreeview'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
import ngModule from '../../module';
|
||||
|
||||
class Controller {
|
||||
constructor($element, $scope, $compile) {
|
||||
this.$element = $element;
|
||||
this.$scope = $scope;
|
||||
this.$compile = $compile;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
if (this.item.parent) {
|
||||
this.treeview.$transclude(($clone, $scope) => {
|
||||
this.$contentScope = $scope;
|
||||
$scope.item = this.item;
|
||||
this.$element.append($clone);
|
||||
});
|
||||
} else {
|
||||
let template = `<span translate>{{$ctrl.treeview.rootLabel}}</span>`;
|
||||
let $clone = this.$compile(template)(this.$scope);
|
||||
this.$element.append($clone);
|
||||
}
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
if (this.$contentScope)
|
||||
this.$contentScope.$destroy();
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$element', '$scope', '$compile'];
|
||||
|
||||
ngModule.component('vnTreeviewContent', {
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
item: '<'
|
||||
},
|
||||
require: {
|
||||
treeview: '^vnTreeview'
|
||||
}
|
||||
});
|
|
@ -1,13 +1,3 @@
|
|||
<vn-treeview-child
|
||||
acl-role="$ctrl.aclRole"
|
||||
items="$ctrl.data"
|
||||
parent="$ctrl.data"
|
||||
selectable="$ctrl.selectable"
|
||||
editable="$ctrl.editable"
|
||||
disabled="$ctrl.disabled"
|
||||
icons="$ctrl.icons"
|
||||
parent-scope="$ctrl.$scope.$parent"
|
||||
draggable="$ctrl.draggable"
|
||||
droppable="$ctrl.droppable"
|
||||
vn-droppable="{{$ctrl.droppable}}">
|
||||
</vn-treeview-child>
|
||||
<vn-treeview-childs
|
||||
items="$ctrl.items">
|
||||
</vn-treeview-childs>
|
||||
|
|
|
@ -2,73 +2,122 @@ import ngModule from '../../module';
|
|||
import Component from '../../lib/component';
|
||||
import './style.scss';
|
||||
|
||||
import './childs';
|
||||
import './content';
|
||||
|
||||
/**
|
||||
* Treeview
|
||||
*
|
||||
* @property {String} position The relative position to the parent
|
||||
*/
|
||||
export default class Treeview extends Component {
|
||||
constructor($element, $scope) {
|
||||
constructor($element, $scope, $transclude) {
|
||||
super($element, $scope);
|
||||
this.$scope = $scope;
|
||||
this.data = [];
|
||||
this.$transclude = $transclude;
|
||||
this.readOnly = true;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.refresh();
|
||||
get data() {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.model.refresh().then(() => {
|
||||
this.data = this.model.data;
|
||||
set data(value) {
|
||||
this._data = value;
|
||||
|
||||
const sons = value.length;
|
||||
const rootElement = [{
|
||||
childs: value,
|
||||
active: true,
|
||||
sons: sons
|
||||
}];
|
||||
|
||||
this.setParent(rootElement[0], value);
|
||||
|
||||
this.items = rootElement;
|
||||
}
|
||||
|
||||
fetch() {
|
||||
return this.fetchFunc().then(res =>
|
||||
this.data = res
|
||||
);
|
||||
}
|
||||
|
||||
setParent(parent, childs) {
|
||||
childs.forEach(child => {
|
||||
child.parent = parent;
|
||||
|
||||
if (child.childs)
|
||||
this.setParent(parent, child.childs);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
else {
|
||||
this.model.applyFilter({}, {parentFk: item.id}).then(() => {
|
||||
const newData = this.model.data;
|
||||
this.fold(item);
|
||||
else
|
||||
this.unfold(item);
|
||||
}
|
||||
|
||||
if (item.childs) {
|
||||
let childs = item.childs;
|
||||
childs.forEach(child => {
|
||||
let index = newData.findIndex(newChild => {
|
||||
return newChild.id == child.id;
|
||||
});
|
||||
newData[index] = child;
|
||||
fold(item) {
|
||||
item.childs = undefined;
|
||||
item.active = false;
|
||||
}
|
||||
|
||||
unfold(item) {
|
||||
return this.fetchFunc({$item: item}).then(newData => {
|
||||
this.setParent(item, newData);
|
||||
|
||||
const childs = item.childs;
|
||||
if (childs) {
|
||||
childs.forEach(child => {
|
||||
let index = newData.findIndex(newChild => {
|
||||
return newChild.id == child.id;
|
||||
});
|
||||
}
|
||||
|
||||
item.childs = newData.sort((a, b) => {
|
||||
if (b.selected !== a.selected) {
|
||||
if (a.selected == null)
|
||||
return 1;
|
||||
if (b.selected == null)
|
||||
return -1;
|
||||
return b.selected - a.selected;
|
||||
}
|
||||
|
||||
return a.name.localeCompare(b.name);
|
||||
newData[index] = child;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (this.sortFunc) {
|
||||
item.childs = newData.sort((a, b) =>
|
||||
this.sortFunc({$a: a, $b: b})
|
||||
);
|
||||
}
|
||||
}).then(() => item.active = true);
|
||||
}
|
||||
|
||||
onRemove(item) {
|
||||
if (this.removeFunc)
|
||||
this.removeFunc({$item: item});
|
||||
}
|
||||
|
||||
remove(item) {
|
||||
const parent = item.parent;
|
||||
let childs = parent.childs;
|
||||
|
||||
if (!childs) childs = [];
|
||||
|
||||
let index = childs.indexOf(item);
|
||||
childs.splice(index, 1);
|
||||
if (parent) parent.sons--;
|
||||
}
|
||||
|
||||
onCreate(parent) {
|
||||
if (this.createFunc)
|
||||
this.createFunc({$parent: parent});
|
||||
}
|
||||
|
||||
create(item) {
|
||||
const parent = item.parent;
|
||||
let childs = parent.childs;
|
||||
if (!childs) childs = [];
|
||||
|
||||
childs.push(item);
|
||||
|
||||
if (this.sortFunc) {
|
||||
childs = childs.sort((a, b) =>
|
||||
this.sortFunc({$a: a, $b: b})
|
||||
);
|
||||
}
|
||||
|
||||
item.active = !item.active;
|
||||
if (parent) parent.sons++;
|
||||
}
|
||||
|
||||
onDrop(item, dragged, dropped) {
|
||||
|
@ -76,19 +125,21 @@ export default class Treeview extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
Treeview.$inject = ['$element', '$scope'];
|
||||
Treeview.$inject = ['$element', '$scope', '$transclude'];
|
||||
|
||||
ngModule.component('vnTreeview', {
|
||||
template: require('./index.html'),
|
||||
controller: Treeview,
|
||||
bindings: {
|
||||
model: '<',
|
||||
icons: '<?',
|
||||
disabled: '<?',
|
||||
selectable: '<?',
|
||||
editable: '<?',
|
||||
rootLabel: '@',
|
||||
data: '<?',
|
||||
draggable: '<?',
|
||||
droppable: '<?',
|
||||
aclRole: '@?'
|
||||
}
|
||||
fetchFunc: '&',
|
||||
removeFunc: '&?',
|
||||
createFunc: '&?',
|
||||
sortFunc: '&?',
|
||||
readOnly: '<?'
|
||||
},
|
||||
transclude: true
|
||||
});
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
@import "effects";
|
||||
|
||||
vn-treeview {
|
||||
vn-treeview-child {
|
||||
display: block
|
||||
}
|
||||
vn-treeview-childs {
|
||||
display: block;
|
||||
|
||||
ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
@ -11,37 +10,43 @@ vn-treeview {
|
|||
li {
|
||||
list-style: none;
|
||||
|
||||
& > div > .arrow {
|
||||
min-width: 24px;
|
||||
margin-right: 10px;
|
||||
transition: transform 200ms;
|
||||
}
|
||||
&.expanded > div > .arrow {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
& > .node {
|
||||
@extend %clickable;
|
||||
display: flex;
|
||||
padding: 5px;
|
||||
align-items: center;
|
||||
|
||||
& > vn-check:not(.indeterminate) {
|
||||
color: $color-main;
|
||||
|
||||
& > .btn {
|
||||
border-color: $color-main;
|
||||
}
|
||||
}
|
||||
& > vn-check.checked {
|
||||
color: $color-main;
|
||||
}
|
||||
}
|
||||
|
||||
& > div > .arrow {
|
||||
min-width: 24px;
|
||||
margin-right: 10px;
|
||||
transition: transform 200ms;
|
||||
}
|
||||
|
||||
& > div.expanded > .arrow {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
ul {
|
||||
padding-left: 2.2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vn-icon-button {
|
||||
padding: 0
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.node > .buttons {
|
||||
display: none
|
||||
}
|
||||
|
||||
.node:hover > .buttons {
|
||||
display: block
|
||||
}
|
||||
}
|
||||
|
||||
vn-treeview-content {
|
||||
flex-grow: 1
|
||||
}
|
|
@ -223,11 +223,8 @@ export default class Watcher extends Component {
|
|||
}
|
||||
|
||||
loadOriginalData() {
|
||||
Object.keys(this.data).forEach(key => {
|
||||
delete this.data[key];
|
||||
});
|
||||
|
||||
this.data = Object.assign(this.data, this.orgData);
|
||||
const orgData = JSON.parse(JSON.stringify(this.orgData));
|
||||
this.data = Object.assign(this.data, orgData);
|
||||
this.setPristine();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,6 @@ vn-dialog.modal-form {
|
|||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
tpl-body {
|
||||
width: 100%;
|
||||
}
|
||||
table {
|
||||
width: 100%
|
||||
}
|
||||
|
|
|
@ -56,7 +56,5 @@
|
|||
"You can't delete a confirmed order": "You can't delete a confirmed order",
|
||||
"Value has an invalid format": "Value has an invalid format",
|
||||
"The postcode doesn't exists. Ensure you put the correct format": "The postcode doesn't exists. Ensure you put the correct format",
|
||||
"Can't create stowaway for this ticket": "Can't create stowaway for this ticket",
|
||||
"is not a valid date": "is not a valid date",
|
||||
"not zone with this parameters": "not zone with this parameters"
|
||||
"Can't create stowaway for this ticket": "Can't create stowaway for this ticket"
|
||||
}
|
|
@ -108,5 +108,5 @@
|
|||
"This postal code is not valid": "This postal code is not valid",
|
||||
"is invalid": "is invalid",
|
||||
"The postcode doesn't exists. Ensure you put the correct format": "El código postal no existe. Asegúrate de ponerlo con el formato correcto",
|
||||
"not zone with this parameters": "not zone with this parameters"
|
||||
"The department name can't be repeated": "El nombre del departamento no puede repetirse"
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('toggleIsIncluded', {
|
||||
description: 'Toggle include to delivery',
|
||||
accepts: [{
|
||||
arg: 'zoneFk',
|
||||
type: 'Number',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
arg: 'item',
|
||||
type: 'Object',
|
||||
required: true,
|
||||
}],
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/toggleIsIncluded`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.toggleIsIncluded = async(zoneFk, item) => {
|
||||
if (item.isIncluded === null)
|
||||
return Self.destroyAll({zoneFk, geoFk: item.id});
|
||||
else {
|
||||
return Self.upsert({
|
||||
zoneFk: zoneFk,
|
||||
geoFk: item.id,
|
||||
isIncluded: item.isIncluded
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
|
@ -6,10 +6,11 @@ module.exports = Self => {
|
|||
{
|
||||
arg: 'id',
|
||||
type: 'Number',
|
||||
description: 'The zone id',
|
||||
http: {source: 'path'},
|
||||
required: true
|
||||
}, {
|
||||
arg: 'parentFk',
|
||||
arg: 'parentId',
|
||||
type: 'Number',
|
||||
description: 'Get the children of the specified father',
|
||||
}, {
|
||||
|
@ -28,10 +29,10 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.getLeaves = async(id, parentFk = null, search) => {
|
||||
Self.getLeaves = async(id, parentId = null, search) => {
|
||||
let [res] = await Self.rawSql(
|
||||
`CALL zone_getLeaves(?, ?, ?)`,
|
||||
[id, parentFk, search]
|
||||
[id, parentId, search]
|
||||
);
|
||||
|
||||
let map = new Map();
|
||||
|
@ -49,7 +50,7 @@ module.exports = Self => {
|
|||
}
|
||||
}
|
||||
|
||||
let leaves = map.get(parentFk);
|
||||
let leaves = map.get(parentId);
|
||||
setLeaves(leaves);
|
||||
|
||||
return leaves || [];
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('toggleIsIncluded', {
|
||||
description: 'Toggle include to delivery',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'Number',
|
||||
description: 'The zone id',
|
||||
http: {source: 'path'},
|
||||
required: true
|
||||
}, {
|
||||
arg: 'geoId',
|
||||
type: 'Number',
|
||||
required: true
|
||||
}, {
|
||||
arg: 'isIncluded',
|
||||
type: 'Boolean'
|
||||
}],
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/toggleIsIncluded`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.toggleIsIncluded = async(id, geoId, isIncluded) => {
|
||||
const models = Self.app.models;
|
||||
|
||||
if (isIncluded === undefined)
|
||||
return models.ZoneIncluded.destroyAll({zoneFk: id, geoFk: geoId});
|
||||
else {
|
||||
return models.ZoneIncluded.upsert({
|
||||
zoneFk: id,
|
||||
geoFk: geoId,
|
||||
isIncluded: isIncluded
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/zone-included/toggleIsIncluded')(Self);
|
||||
};
|
|
@ -3,6 +3,7 @@ module.exports = Self => {
|
|||
require('../methods/zone/editPrices')(Self);
|
||||
require('../methods/zone/getLeaves')(Self);
|
||||
require('../methods/zone/getEvents')(Self);
|
||||
require('../methods/zone/toggleIsIncluded')(Self);
|
||||
|
||||
Self.validatesPresenceOf('agencyModeFk', {
|
||||
message: `Agency cannot be blank`
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/api/Zones/{{$ctrl.$stateParams.id}}/getLeaves"
|
||||
filter="::$ctrl.filter"
|
||||
auto-load="false">
|
||||
filter="::$ctrl.filter">
|
||||
</vn-crud-model>
|
||||
<div class="vn-w-md">
|
||||
<vn-card class="vn-px-lg">
|
||||
<vn-searchbar
|
||||
<vn-searchbar auto-load="false"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
vn-focus>
|
||||
</vn-searchbar>
|
||||
</vn-card>
|
||||
<vn-card class="vn-pa-lg vn-mt-md">
|
||||
<vn-treeview
|
||||
vn-id="treeview"
|
||||
model="model"
|
||||
acl-role="deliveryBoss"
|
||||
on-selection="$ctrl.onSelection(item, value)"
|
||||
selectable="true">
|
||||
<vn-treeview vn-id="treeview" root-label="Locations"
|
||||
fetch-func="$ctrl.onFetch($item)"
|
||||
sort-func="$ctrl.onSort($a, $b)">
|
||||
<vn-check
|
||||
field="item.selected"
|
||||
on-change="$ctrl.onSelection(value, item)"
|
||||
triple-state="true"
|
||||
label="{{::item.name}}">
|
||||
</vn-check>
|
||||
</vn-treeview>
|
||||
</vn-card>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,32 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'core/lib/section';
|
||||
import './style.scss';
|
||||
|
||||
class Controller extends Section {
|
||||
onSearch(params) {
|
||||
this.$.model.applyFilter(null, params);
|
||||
this.$.$applyAsync(() => this.$.treeview.refresh());
|
||||
this.$.model.applyFilter({}, params).then(() => {
|
||||
const data = this.$.model.data;
|
||||
this.$.treeview.data = data;
|
||||
});
|
||||
}
|
||||
|
||||
onFetch(item) {
|
||||
const params = item ? {parentId: item.id} : null;
|
||||
return this.$.model.applyFilter({}, params).then(() => {
|
||||
return this.$.model.data;
|
||||
});
|
||||
}
|
||||
|
||||
onSort(a, b) {
|
||||
if (b.selected !== a.selected) {
|
||||
if (a.selected == null)
|
||||
return 1;
|
||||
if (b.selected == null)
|
||||
return -1;
|
||||
return b.selected - a.selected;
|
||||
}
|
||||
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
|
||||
exprBuilder(param, value) {
|
||||
|
@ -14,13 +36,11 @@ class Controller extends Section {
|
|||
}
|
||||
}
|
||||
|
||||
onSelection(item, isIncluded) {
|
||||
let node = Object.assign({}, item);
|
||||
node.isIncluded = isIncluded;
|
||||
node.childs = []; // Data too large
|
||||
|
||||
const path = '/agency/api/ZoneIncludeds/toggleIsIncluded';
|
||||
const params = {zoneFk: this.zone.id, item: node};
|
||||
onSelection(value, item) {
|
||||
if (value == null)
|
||||
value = undefined;
|
||||
const params = {geoId: item.id, isIncluded: value};
|
||||
const path = `/api/zones/${this.zone.id}/toggleIsIncluded`;
|
||||
this.$http.post(path, params);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
@import "variables";
|
||||
|
||||
vn-treeview-content {
|
||||
& > vn-check:not(.indeterminate) {
|
||||
color: $color-main;
|
||||
|
||||
& > .btn {
|
||||
border-color: $color-main;
|
||||
}
|
||||
}
|
||||
& > vn-check.checked {
|
||||
color: $color-main;
|
||||
}
|
||||
}
|
|
@ -86,8 +86,9 @@ module.exports = Self => {
|
|||
return {'i.hasPdf': value};
|
||||
case 'created':
|
||||
return {'i.created': value};
|
||||
case 'amount':
|
||||
case 'clientFk':
|
||||
return {'i.clientFk': value};
|
||||
case 'amount':
|
||||
case 'companyFk':
|
||||
case 'issued':
|
||||
case 'dued':
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<vn-crud-model
|
||||
url="/item/api/TaxClasses"
|
||||
url="api/TaxClasses"
|
||||
fields="['id', 'description', 'code']"
|
||||
data="classes"
|
||||
auto-load="true">
|
||||
|
@ -11,7 +11,7 @@
|
|||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.submit()" compact>
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal ng-repeat="tax in $ctrl.taxes track by $index">
|
||||
<vn-horizontal ng-repeat="tax in $ctrl.taxes">
|
||||
<vn-textfield vn-one
|
||||
label="Country"
|
||||
model="tax.country.country"
|
||||
|
@ -21,7 +21,6 @@
|
|||
label="Class"
|
||||
field="tax.taxClassFk"
|
||||
data="classes"
|
||||
value-field="id"
|
||||
show-field="description">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
export default class Controller {
|
||||
constructor($stateParams, $http, $translate, vnApp) {
|
||||
constructor($stateParams, $http, $translate, $scope) {
|
||||
this.$ = $scope;
|
||||
this.$http = $http;
|
||||
this.$stateParams = $stateParams;
|
||||
this._ = $translate;
|
||||
this.vnApp = vnApp;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
|
@ -21,9 +21,8 @@ export default class Controller {
|
|||
}]
|
||||
};
|
||||
|
||||
let urlFilter = encodeURIComponent(JSON.stringify(filter));
|
||||
let url = `/item/api/Items/${this.$stateParams.id}/taxes?filter=${urlFilter}`;
|
||||
this.$http.get(url).then(json => {
|
||||
let url = `api/Items/${this.$stateParams.id}/taxes`;
|
||||
this.$http.get(url, {params: {filter}}).then(json => {
|
||||
this.taxes = json.data;
|
||||
});
|
||||
}
|
||||
|
@ -33,14 +32,16 @@ export default class Controller {
|
|||
for (let tax of this.taxes)
|
||||
data.push({id: tax.id, taxClassFk: tax.taxClassFk});
|
||||
|
||||
let url = `/item/api/Items/updateTaxes`;
|
||||
this.$http.post(url, data).then(
|
||||
() => this.vnApp.showSuccess(this._.instant('Data saved!'))
|
||||
);
|
||||
this.$.watcher.check();
|
||||
let url = `api/Items/updateTaxes`;
|
||||
this.$http.post(url, data).then(() => {
|
||||
this.$.watcher.notifySaved();
|
||||
this.$.watcher.updateOriginalData();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$stateParams', '$http', '$translate', 'vnApp'];
|
||||
Controller.$inject = ['$stateParams', '$http', '$translate', '$scope'];
|
||||
|
||||
ngModule.component('vnItemTax', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -2,65 +2,65 @@ import './index.js';
|
|||
|
||||
describe('Item', () => {
|
||||
describe('Component vnItemTax', () => {
|
||||
let $element;
|
||||
let $stateParams;
|
||||
let controller;
|
||||
let $httpBackend;
|
||||
let vnApp;
|
||||
|
||||
beforeEach(angular.mock.module('item', $translateProvider => {
|
||||
$translateProvider.translations('en', {});
|
||||
}));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, _$httpBackend_, _$stateParams_, _vnApp_) => {
|
||||
beforeEach(angular.mock.inject((_$httpBackend_, $rootScope, _$stateParams_, $compile) => {
|
||||
$stateParams = _$stateParams_;
|
||||
$stateParams.id = 1;
|
||||
$httpBackend = _$httpBackend_;
|
||||
vnApp = _vnApp_;
|
||||
spyOn(vnApp, 'showSuccess');
|
||||
controller = $componentController('vnItemTax', {$state: $stateParams});
|
||||
|
||||
$httpBackend.whenGET(url => url.startsWith(`api/TaxClasses`))
|
||||
.respond([
|
||||
{id: 1, description: 'Reduced VAT', code: 'R'},
|
||||
{id: 2, description: 'General VAT', code: 'G'}
|
||||
]);
|
||||
|
||||
$httpBackend.whenGET(url => url.startsWith(`api/Items/${$stateParams.id}/taxes`))
|
||||
.respond([
|
||||
{id: 1, taxClassFk: 1}
|
||||
]);
|
||||
|
||||
$element = $compile(`<vn-item-tax></vn-item-tax`)($rootScope);
|
||||
controller = $element.controller('vnItemTax');
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
$element.remove();
|
||||
});
|
||||
|
||||
describe('getTaxes()', () => {
|
||||
it('should perform a query to set the array of taxes into the controller', () => {
|
||||
let filter = {
|
||||
fields: ['id', 'countryFk', 'taxClassFk'],
|
||||
include: [{
|
||||
relation: 'country',
|
||||
scope: {fields: ['country']}
|
||||
}]
|
||||
};
|
||||
let response = [{id: 1, taxClassFk: 1}];
|
||||
filter = encodeURIComponent(JSON.stringify(filter));
|
||||
$httpBackend.when('GET', `/item/api/Items/1/taxes?filter=${filter}`).respond(response);
|
||||
$httpBackend.expect('GET', `/item/api/Items/1/taxes?filter=${filter}`);
|
||||
controller.$onInit();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.taxes).toEqual(response);
|
||||
expect(controller.taxes[0].id).toEqual(1);
|
||||
expect(controller.taxes[0].taxClassFk).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('submit()', () => {
|
||||
it('should perform a post to update taxes', () => {
|
||||
let filter = {
|
||||
fields: ['id', 'countryFk', 'taxClassFk'],
|
||||
include: [{
|
||||
relation: 'country',
|
||||
scope: {fields: ['country']}
|
||||
}]
|
||||
};
|
||||
let response = [{id: 1, taxClassFk: 1}];
|
||||
filter = encodeURIComponent(JSON.stringify(filter));
|
||||
$httpBackend.when('GET', `/item/api/Items/1/taxes?filter=${filter}`).respond(response);
|
||||
controller.$onInit();
|
||||
$httpBackend.flush();
|
||||
spyOn(controller.$.watcher, 'notifySaved');
|
||||
spyOn(controller.$.watcher, 'updateOriginalData');
|
||||
controller.taxes = [
|
||||
{id: 37, countryFk: 1, taxClassFk: 1, country: {id: 1, country: 'España'}}
|
||||
];
|
||||
controller.$.watcher.data = [
|
||||
{id: 37, countryFk: 1, taxClassFk: 2, country: {id: 1, country: 'España'}}
|
||||
];
|
||||
|
||||
$httpBackend.when('POST', `/item/api/Items/updateTaxes`).respond('ok');
|
||||
$httpBackend.expect('POST', `/item/api/Items/updateTaxes`);
|
||||
$httpBackend.whenPOST(`api/Items/updateTaxes`).respond('oki doki');
|
||||
controller.submit();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
|
||||
expect(controller.$.watcher.notifySaved).toHaveBeenCalledWith();
|
||||
expect(controller.$.watcher.updateOriginalData).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
<vn-label-value label="Nickname"
|
||||
value="{{$ctrl.summary.address.nickname}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Warehouse"
|
||||
value="{{$ctrl.summary.sourceApp}}">
|
||||
</vn-label-value>
|
||||
<vn-check label="Confirmed" disabled="true"
|
||||
field="$ctrl.summary.isConfirmed">
|
||||
</vn-check>
|
||||
|
@ -27,6 +24,9 @@
|
|||
<vn-label-value label="Phone"
|
||||
value="{{$ctrl.summary.address.phone}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Created from"
|
||||
value="{{$ctrl.summary.sourceApp}}">
|
||||
</vn-label-value>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-label-value label="{{'Notes'}}"
|
||||
|
|
|
@ -45,7 +45,7 @@ module.exports = Self => {
|
|||
clientFk: ship.clientFk,
|
||||
addressFk: ship.addressFk,
|
||||
agencyModeFk: ship.agencyModeFk,
|
||||
warehouse: {neq: ship.warehouseFk},
|
||||
warehouseFk: {neq: ship.warehouseFk},
|
||||
shipped: {
|
||||
between: [lowestDate.toJSON(), highestDate.toJSON()]
|
||||
}
|
||||
|
|
|
@ -1,37 +1,38 @@
|
|||
<vn-crud-model
|
||||
<vn-crud-model vn-id="model"
|
||||
url="/api/Tickets/{{$ctrl.$stateParams.id}}/getPossibleStowaways"
|
||||
vn-id="model"
|
||||
data="possibleStowaways">
|
||||
</vn-crud-model>
|
||||
<vn-dialog
|
||||
vn-id="dialog"
|
||||
class="modal-form"
|
||||
on-open="model.reload()">
|
||||
on-open="model.refresh()">
|
||||
<tpl-body>
|
||||
<vn-horizontal class="header vn-pa-md">
|
||||
<vn-horizontal class="header vn-pa-md vn-w-lg">
|
||||
<h5><span translate>Stowaways to add</span></h5>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-pa-md">
|
||||
<vn-table model="model" auto-load="false">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th number>Ticket id</vn-th>
|
||||
<vn-th number>Shipped</vn-th>
|
||||
<vn-th number>Agency</vn-th>
|
||||
<vn-th number>Warehouse</vn-th>
|
||||
<vn-th number>State</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="ticket in possibleStowaways" class="clickable" ng-click="$ctrl.addStowaway(ticket)">
|
||||
<vn-td number>{{ticket.id}}</vn-td>
|
||||
<vn-td number>{{ticket.landed | dateTime: 'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td number>{{ticket.agencyMode.name}}</vn-td>
|
||||
<vn-td number>{{ticket.warehouse.name}}</vn-td>
|
||||
<vn-td number>{{ticket.state.state.name}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
<vn-horizontal class="vn-pa-md vn-w-lg">
|
||||
<vn-data-viewer class="vn-w-xs" model="model">
|
||||
<vn-table model="model" auto-load="false">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th number>Ticket id</vn-th>
|
||||
<vn-th number>Shipped</vn-th>
|
||||
<vn-th number>Agency</vn-th>
|
||||
<vn-th number>Warehouse</vn-th>
|
||||
<vn-th number>State</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="ticket in possibleStowaways" class="clickable" ng-click="$ctrl.addStowaway(ticket)">
|
||||
<vn-td number>{{ticket.id}}</vn-td>
|
||||
<vn-td number>{{ticket.landed | dateTime: 'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td number>{{ticket.agencyMode.name}}</vn-td>
|
||||
<vn-td number>{{ticket.warehouse.name}}</vn-td>
|
||||
<vn-td number>{{ticket.state.state.name}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-data-viewer>
|
||||
</vn-horizontal>
|
||||
</tpl-body>
|
||||
</vn-dialog>
|
|
@ -0,0 +1,40 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('createChild', {
|
||||
description: 'Creates a new child department',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'parentId',
|
||||
type: 'Number'
|
||||
},
|
||||
{
|
||||
arg: 'name',
|
||||
type: 'String',
|
||||
required: true,
|
||||
}],
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/createChild`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.createChild = async(parentId = null, name) => {
|
||||
const models = Self.app.models;
|
||||
const nameExists = await models.Department.count({name});
|
||||
|
||||
if (nameExists)
|
||||
throw new UserError(`The department name can't be repeated`);
|
||||
|
||||
const newDep = await models.Department.create({
|
||||
parentFk: parentId,
|
||||
name: name
|
||||
});
|
||||
|
||||
return newDep;
|
||||
};
|
||||
};
|
|
@ -1,20 +1,14 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('getLeaves', {
|
||||
description: 'Returns the first shipped and landed possible for params',
|
||||
description: 'Returns the nodes for a department',
|
||||
accepts: [{
|
||||
arg: 'parentFk',
|
||||
arg: 'parentId',
|
||||
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'}
|
||||
description: 'Get the children of the specified father',
|
||||
}, {
|
||||
arg: 'search',
|
||||
type: 'String',
|
||||
description: 'Filter nodes whose name starts with',
|
||||
}],
|
||||
returns: {
|
||||
type: ['object'],
|
||||
|
@ -26,61 +20,30 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
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]);
|
||||
Self.getLeaves = async(parentId = null, search) => {
|
||||
let [res] = await Self.rawSql(
|
||||
`CALL department_getLeaves(?, ?)`,
|
||||
[parentId, search]
|
||||
);
|
||||
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
let map = new Map();
|
||||
for (let node of res) {
|
||||
if (!map.has(node.parentFk))
|
||||
map.set(node.parentFk, []);
|
||||
map.get(node.parentFk).push(node);
|
||||
}
|
||||
|
||||
function getLeaves(parent) {
|
||||
let elements = nodes.filter(element => {
|
||||
return element.lft > parent.lft && element.rgt < parent.rgt
|
||||
&& element.depth === parent.depth + 1;
|
||||
});
|
||||
|
||||
return elements;
|
||||
function setLeaves(nodes) {
|
||||
if (!nodes) return;
|
||||
for (let node of nodes) {
|
||||
node.childs = map.get(node.id);
|
||||
setLeaves(node.childs);
|
||||
}
|
||||
}
|
||||
|
||||
return leaves;
|
||||
let leaves = map.get(parentId);
|
||||
setLeaves(leaves);
|
||||
|
||||
return leaves || [];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('nodeAdd', {
|
||||
description: 'Returns the first shipped and landed possible for params',
|
||||
accessType: 'WRITE',
|
||||
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;
|
||||
};
|
||||
};
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('nodeDelete', {
|
||||
description: 'Returns the first shipped and landed possible for params',
|
||||
accessType: 'WRITE',
|
||||
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);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('removeChild', {
|
||||
description: 'Removes a child department',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'Number',
|
||||
description: 'The department id',
|
||||
http: {source: 'path'}
|
||||
}],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/removeChild`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.removeChild = async id => {
|
||||
const models = Self.app.models;
|
||||
const department = await models.Department.findById(id);
|
||||
|
||||
return await department.destroy();
|
||||
};
|
||||
};
|
|
@ -1,15 +1,5 @@
|
|||
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`);
|
||||
if (err.code === 'ER_DUP_ENTRY')
|
||||
return new UserError(`The department name can't be repeated`);
|
||||
return err;
|
||||
});
|
||||
require('../methods/department/createChild')(Self);
|
||||
require('../methods/department/removeChild')(Self);
|
||||
};
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
},
|
||||
"name": {
|
||||
"type": "String"
|
||||
},
|
||||
"parentFk": {
|
||||
"type": "Number"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,24 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/worker/api/departments/getLeaves"
|
||||
params="::$ctrl.params"
|
||||
auto-load="false">
|
||||
</vn-crud-model>
|
||||
|
||||
<form name="form">
|
||||
<div class="vn-ma-md">
|
||||
<div class="content-block" compact>
|
||||
<form name="form" compact>
|
||||
<vn-card class="vn-my-md vn-pa-md">
|
||||
<vn-treeview vn-id="treeview" model="model"
|
||||
on-selection="$ctrl.onSelection(item, value)"
|
||||
on-create="$ctrl.onCreate(parent)"
|
||||
on-drop="$ctrl.onDrop(item, dragged, dropped)"
|
||||
icons="$ctrl.icons"
|
||||
draggable="true" droppable="true"
|
||||
acl-role="hr" editable="true">
|
||||
<vn-treeview vn-id="treeview" root-label="Departments" read-only="false"
|
||||
fetch-func="$ctrl.onFetch($item)"
|
||||
remove-func="$ctrl.onRemove($item)"
|
||||
create-func="$ctrl.onCreate($parent)"
|
||||
sort-func="$ctrl.onSort($a, $b)">
|
||||
{{::item.name}}
|
||||
</vn-treeview>
|
||||
</vn-card>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<vn-button-bar>
|
||||
<vn-button ui-sref="worker.index" label="Back"></vn-button>
|
||||
</vn-button-bar>
|
||||
</form>
|
||||
</div>
|
||||
<vn-confirm
|
||||
vn-id="deleteNode"
|
||||
on-response="$ctrl.onRemoveResponse(response)"
|
||||
|
@ -37,7 +36,7 @@
|
|||
<vn-horizontal>
|
||||
<vn-textfield vn-one
|
||||
label="Name"
|
||||
model="$ctrl.newNode.name">
|
||||
model="$ctrl.newChild.name">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
</tpl-body>
|
||||
|
@ -45,4 +44,4 @@
|
|||
<input type="button" response="CANCEL" translate-attr="{value: 'Cancel'}"/>
|
||||
<button response="ACCEPT" translate>Create</button>
|
||||
</tpl-buttons>
|
||||
</vn-dialog>
|
||||
</vn-dialog>
|
||||
|
|
|
@ -2,31 +2,28 @@ import ngModule from '../module';
|
|||
|
||||
class Controller {
|
||||
constructor($scope, $http, vnApp, $translate) {
|
||||
this.$scope = $scope;
|
||||
this.$ = $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();
|
||||
$postLink() {
|
||||
this.$.treeview.fetch();
|
||||
}
|
||||
|
||||
onDelete(item, parent, index) {
|
||||
this.selectedNode = {id: item.id, parent, index};
|
||||
this.$scope.deleteNode.show();
|
||||
onFetch(item) {
|
||||
const params = item ? {parentId: item.id} : null;
|
||||
return this.$.model.applyFilter({}, params).then(() => {
|
||||
return this.$.model.data;
|
||||
});
|
||||
}
|
||||
|
||||
onDrop(item, dragged, dropped) {
|
||||
onSort(a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
|
||||
/* onDrop(item, dragged, dropped) {
|
||||
if (dropped.scope.item) {
|
||||
const droppedItem = dropped.scope.item;
|
||||
const draggedItem = dragged.scope.item;
|
||||
|
@ -38,27 +35,43 @@ class Controller {
|
|||
|
||||
this.$scope.$apply();
|
||||
}
|
||||
} */
|
||||
|
||||
onCreate(parent) {
|
||||
this.newChild = {
|
||||
parent: parent,
|
||||
name: ''
|
||||
};
|
||||
|
||||
this.$.createNode.show();
|
||||
}
|
||||
|
||||
onCreateDialogOpen() {
|
||||
this.newNode.name = '';
|
||||
this.newChild.name = '';
|
||||
}
|
||||
|
||||
onCreateResponse(response) {
|
||||
if (response == 'ACCEPT') {
|
||||
try {
|
||||
if (!this.newNode.name)
|
||||
if (!this.newChild.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);
|
||||
}
|
||||
const params = {name: this.newChild.name};
|
||||
const parent = this.newChild.parent;
|
||||
|
||||
if (parent && parent.id)
|
||||
params.parentId = parent.id;
|
||||
|
||||
if (!parent.active)
|
||||
this.$.treeview.unfold(parent);
|
||||
|
||||
const query = `/api/departments/createChild`;
|
||||
this.$http.post(query, params).then(res => {
|
||||
const parent = this.newChild.parent;
|
||||
const item = res.data;
|
||||
item.parent = parent;
|
||||
|
||||
this.$.treeview.create(item);
|
||||
});
|
||||
} catch (e) {
|
||||
this.vnApp.showError(this.$translate.instant(e.message));
|
||||
|
@ -68,17 +81,17 @@ class Controller {
|
|||
return true;
|
||||
}
|
||||
|
||||
onRemove(item) {
|
||||
this.removedChild = item;
|
||||
this.$.deleteNode.show();
|
||||
}
|
||||
|
||||
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);
|
||||
const childId = this.removedChild.id;
|
||||
const path = `/api/departments/${childId}/removeChild`;
|
||||
this.$http.post(path).then(() => {
|
||||
this.$.treeview.remove(this.removedChild);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue