This commit is contained in:
Juan Ferrer 2019-10-18 21:37:28 +02:00
commit 43fd8fe75e
42 changed files with 1053 additions and 570 deletions

View File

@ -351,16 +351,6 @@ INSERT INTO `vn`.`creditInsurance`(`id`, `creditClassification`, `credit`, `crea
(2, 2, 6000, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), NULL),
(3, 3, 10000, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), NULL);
INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agencyModeFk`, `description`, `m3`, `cost`, `started`, `finished`)
VALUES
(1, '1899-12-30 12:15:00', 56, CURDATE(), 1, 7, 'first route', 2.7, 10, CURDATE(), CURDATE()),
(2, '1899-12-30 13:20:00', 56, CURDATE(), 1, 7, 'second route', 0.9, 20, CURDATE(), CURDATE()),
(3, '1899-12-30 14:30:00', 56, CURDATE(), 2, 7, 'third route', 1.1, 30, CURDATE(), CURDATE()),
(4, '1899-12-30 15:45:00', 56, CURDATE(), 3, 7, 'fourth route', 0.1, 40, CURDATE(), CURDATE()),
(5, '1899-12-30 16:00:00', 56, CURDATE(), 4, 8, 'fifth route', NULL, 50, CURDATE(), CURDATE()),
(6, NULL, 57, CURDATE(), 5, 8, 'sixth route', NULL, 60, CURDATE(), CURDATE()),
(7, NULL, 57, CURDATE(), 6, NULL, 'seventh route', NULL, 70, CURDATE(), CURDATE());
INSERT INTO `vn2008`.`empresa_grupo`(`empresa_grupo_id`, `grupo`)
VALUES
(1, 'Wayne Industries');
@ -456,32 +446,42 @@ INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `warehouseFk`, `agencyModeFk`, `t
(12, 'Zone entanglement', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 4, 4, 0, 0, 0),
(13, 'Zone quantum break', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 5, 5, 0, 0, 0);
INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agencyModeFk`, `description`, `m3`, `cost`, `started`, `finished`, `zoneFk`)
VALUES
(1, '1899-12-30 12:15:00', 56, CURDATE(), 1, 1, 'first route', 1.8, 10, CURDATE(), CURDATE(), 1),
(2, '1899-12-30 13:20:00', 56, CURDATE(), 1, 2, 'second route', 0.2, 20, CURDATE(), CURDATE(), 9),
(3, '1899-12-30 14:30:00', 56, CURDATE(), 2, 3, 'third route', 0.5, 30, CURDATE(), CURDATE(), 10),
(4, '1899-12-30 15:45:00', 56, CURDATE(), 3, 4, 'fourth route', 0, 40, CURDATE(), CURDATE(), 12),
(5, '1899-12-30 16:00:00', 56, CURDATE(), 4, 5, 'fifth route', 0.1, 50, CURDATE(), CURDATE(), 13),
(6, NULL, 57, CURDATE(), 5, 7, 'sixth route', 1.7, 60, CURDATE(), CURDATE(), 3),
(7, NULL, 57, CURDATE(), 6, 8, 'seventh route', 0, 70, CURDATE(), CURDATE(), 5);
INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `zoneFk`, `created`)
VALUES
(1 , 3, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 101, 'Bat cave', 121, 'T1111111', 0, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(2 , 1, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T1111111', 0, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(3 , 1, 7, 1, 1, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -2 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T2222222', 0, 3, DATE_ADD(CURDATE(), INTERVAL -2 MONTH)),
(4 , 3, 2, 1, 1, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -3 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T3333333', 0, 9, DATE_ADD(CURDATE(), INTERVAL -3 MONTH)),
(5 , 3, 3, 3, 1, DATE_ADD(CURDATE(), INTERVAL -4 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -4 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T4444444', 0, 10, DATE_ADD(CURDATE(), INTERVAL -4 MONTH)),
(6 , 1, 3, 3, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 101, 'Mountain Drive Gotham', 1, 'A1111111', 0, 10, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(7 , NULL, 7, 1, 2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'Mountain Drive Gotham', 1, NULL, 0, 3, CURDATE()),
(8 , NULL, 7, 1, 2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'Bat cave', 121, NULL, 0, 3, CURDATE()),
(9 , NULL, 7, 1, 2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 104, 'Stark tower', 124, NULL, 0, 3, CURDATE()),
(10, 1, 1, 5, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 102, 'Ingram Street', 2, NULL, 0, 11, CURDATE()),
(11, 1, 7, 1, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 102, 'NY roofs', 122, NULL, 0, 3, CURDATE()),
(12, 1, 1, 1, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 103, 'Phone Box', 123, NULL, 0, 1, CURDATE()),
(13, 1, 7, 1, 2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 103, 'Phone Box', 123, NULL, 0, 1, CURDATE()),
(14, 1, 2, 1, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 104, 'Malibu Point', 4, NULL, 0, 9, CURDATE()),
(15, 1, 7, 1, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 105, 'Plastic Cell', 125, NULL, 0, 3, CURDATE()),
(16, 1, 7, 1, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()),
(17, 1, 7, 2, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()),
(18, 1, 4, 4, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 108, 'Cerebro', 128, NULL, 0, 12, CURDATE()),
(19, 1, 5, 5, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 109, 'Somewhere in Thailand', 129, NULL, 1, 13, CURDATE()),
(20, 1, 5, 5, 3, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Thailand', 129, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(21, NULL, 5, 5, NULL, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Holland', 102, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(22, NULL, 5, 5, NULL, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Japan', 103, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(23, NULL, 10, 1, NULL, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'address 21', 121, NULL, 0, 8, CURDATE()),
(24 ,NULL, 10, 1, NULL, CURDATE(), CURDATE(), 101, 'Bruce Wayne', 1, NULL, 0, 8, CURDATE());
(1 , 3, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 101, 'Bat cave', 121, 'T1111111', 0, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(2 , 1, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T1111111', 0, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(3 , 1, 7, 1, 6, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -2 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T2222222', 0, 3, DATE_ADD(CURDATE(), INTERVAL -2 MONTH)),
(4 , 3, 2, 1, 2, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -3 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T3333333', 0, 9, DATE_ADD(CURDATE(), INTERVAL -3 MONTH)),
(5 , 3, 3, 3, 3, DATE_ADD(CURDATE(), INTERVAL -4 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -4 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T4444444', 0, 10, DATE_ADD(CURDATE(), INTERVAL -4 MONTH)),
(6 , 1, 3, 3, 3, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 101, 'Mountain Drive Gotham', 1, 'A1111111', 0, 10, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(7 , NULL, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'Mountain Drive Gotham', 1, NULL, 0, 3, CURDATE()),
(8 , NULL, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'Bat cave', 121, NULL, 0, 3, CURDATE()),
(9 , NULL, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 104, 'Stark tower', 124, NULL, 0, 3, CURDATE()),
(10, 1, 1, 5, 1, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 102, 'Ingram Street', 2, NULL, 0, 1, CURDATE()),
(11, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 102, 'NY roofs', 122, NULL, 0, 3, CURDATE()),
(12, 1, 1, 1, 1, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 103, 'Phone Box', 123, NULL, 0, 1, CURDATE()),
(13, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 103, 'Phone Box', 123, NULL, 0, 3, CURDATE()),
(14, 1, 2, 1, NULL, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 104, 'Malibu Point', 4, NULL, 0, 9, CURDATE()),
(15, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 105, 'Plastic Cell', 125, NULL, 0, 3, CURDATE()),
(16, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()),
(17, 1, 7, 2, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()),
(18, 1, 4, 4, 4, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 108, 'Cerebro', 128, NULL, 0, 12, CURDATE()),
(19, 1, 5, 5, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 109, 'Somewhere in Thailand', 129, NULL, 1, 13, CURDATE()),
(20, 1, 5, 5, 3, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Thailand', 129, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(21, NULL, 5, 5, 5, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Holland', 102, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(22, NULL, 5, 5, 5, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Japan', 103, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(23, NULL, 8, 1, 7, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'address 21', 121, NULL, 0, 5, CURDATE()),
(24 ,NULL, 8, 1, 7, CURDATE(), CURDATE(), 101, 'Bruce Wayne', 1, NULL, 0, 5, CURDATE());
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
VALUES

View File

@ -529,13 +529,13 @@ export default {
header: 'vn-claim-summary > vn-card > div > h5',
state: 'vn-claim-summary vn-label-value[label="State"] > section > span',
observation: 'vn-claim-summary vn-textarea[ng-model="$ctrl.summary.claim.observation"] textarea',
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) > vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
itemDescriptorPopoverItemDiaryButton: '.vn-popover.shown vn-item-descriptor a[href="#!/item/2/diary"]',
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) > vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
firstDevelopmentWorkerGoToClientButton: '.vn-popover.shown vn-worker-descriptor div.quicklinks > a[href="#!/client/21/summary"]',
firstActionTicketId: 'vn-claim-summary > vn-card > div > vn-horizontal > vn-auto:nth-child(6) > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
firstActionTicketId: 'vn-claim-summary > vn-card > div > vn-horizontal > vn-auto:nth-child(6) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor'
},
claimBasicData: {

View File

@ -358,7 +358,7 @@ describe('Worker time control path', () => {
it(`should check Hank Pym doesn't have hours set on the next months first week`, async() => {
const wholeWeekHours = await nightmare
.waitToClick(selectors.workerTimeControl.nextMonthButton)
.waitToClick(selectors.workerTimeControl.nextMonthButton)
.waitForTextInElement(selectors.workerTimeControl.weekWorkedHours, '00:00 Hours')
.waitToGetProperty(selectors.workerTimeControl.weekWorkedHours, 'innerText');
expect(wholeWeekHours).toEqual('00:00 Hours');

View File

@ -30,6 +30,7 @@ describe('Ticket Edit basic data path', () => {
it(`should confirm the zone autocomplete is enabled for the role productionBoss`, async() => {
const disabled = await nightmare
.waitForSpinnerLoad()
.wait(selectors.ticketBasicData.zoneAutocomplete)
.evaluate(selector => {
return document.querySelector(selector).disabled;

View File

@ -0,0 +1,20 @@
<div class="node clickable">
<vn-icon
class="arrow"
ng-class="{invisible: !$ctrl.item.sons}"
icon="keyboard_arrow_down"
translate-attr="::{title: 'Toggle'}">
</vn-icon>
<section class="content"></section>
<section class="buttons" ng-if="::!$ctrl.treeview.readOnly">
<vn-icon-button translate-attr="::{title: 'Remove'}"
icon="delete"
ng-click="$ctrl.treeview.onRemove($ctrl.item)"
ng-if="$ctrl.item.parent">
</vn-icon-button>
<vn-icon-button translate-attr="::{title: 'Create'}"
icon="add_circle"
ng-click="$ctrl.treeview.onCreate($ctrl.item)">
</vn-icon-button>
</section>
</div>

View File

@ -2,22 +2,33 @@ import ngModule from '../../module';
class Controller {
constructor($element, $scope, $compile) {
this.$element = $element;
this.$scope = $scope;
this.$compile = $compile;
this.element = $element[0];
this.element.$ctrl = this;
this.element.droppable = true;
this.dropCount = 0;
this.element.classList.add('vn-droppable');
}
$onInit() {
const transcludeElement = this.element.querySelector('.content');
const content = angular.element(transcludeElement);
if (this.item.parent) {
this.treeview.$transclude(($clone, $scope) => {
this.$contentScope = $scope;
$scope.item = this.item;
this.$element.append($clone);
content.append($clone);
});
this.element.draggable = true;
this.element.classList.add('vn-draggable');
} else {
let template = `<span translate>{{$ctrl.treeview.rootLabel}}</span>`;
let $clone = this.$compile(template)(this.$scope);
this.$element.append($clone);
content.append($clone);
}
}
@ -25,10 +36,21 @@ class Controller {
if (this.$contentScope)
this.$contentScope.$destroy();
}
dragEnter() {
this.dropCount++;
if (element != this.dropping) {
this.undrop();
if (element) element.classList.add('dropping');
this.dropping = element;
}
}
}
Controller.$inject = ['$element', '$scope', '$compile'];
ngModule.component('vnTreeviewContent', {
ngModule.component('vnTreeviewChild', {
template: require('./child.html'),
controller: Controller,
bindings: {
item: '<'

View File

@ -1,34 +1,11 @@
<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>
<li ng-repeat="item in $ctrl.items">
<vn-treeview-child item="item" ng-class="{expanded: item.active}"
ng-click="$ctrl.onClick($event, item)">
</vn-treeview-child>
<vn-treeview-childs
items="item.childs"
parent="::item">
items="item.childs">
</vn-treeview-childs>
</li>
</ul>

View File

@ -7,10 +7,6 @@ class Controller extends Component {
event.preventDefault();
this.treeview.onToggle(item);
}
onDrop(item, dragged, dropped) {
this.treeview.onDrop(item, dragged, dropped);
}
}
ngModule.component('vnTreeviewChilds', {

View File

@ -1,18 +1,110 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import './style.scss';
import './childs';
import './content';
import './child';
/**
* Treeview
*/
export default class Treeview extends Component {
constructor($element, $scope, $transclude) {
constructor($element, $scope, $transclude, $window) {
super($element, $scope);
this.$transclude = $transclude;
this.$window = $window;
this.readOnly = true;
this.element.addEventListener('dragstart',
event => this.dragStart(event));
this.element.addEventListener('dragend',
event => this.dragEnd(event));
this.element.addEventListener('dragover',
event => this.dragOver(event));
this.element.addEventListener('drop',
event => this.drop(event));
this.element.addEventListener('dragenter',
event => this.dragEnter(event));
this.element.addEventListener('dragleave',
event => this.dragLeave(event));
this.dropCount = 0;
}
undrop() {
if (!this.dropping) return;
this.dropping.classList.remove('dropping');
this.dropping = null;
}
findDroppable(event) {
let element = event.target;
while (element != this.element && !element.droppable)
element = element.parentNode;
if (element == this.element)
return null;
return element;
}
dragOver(event) {
this.dragClientY = event.clientY;
// Prevents page reload
event.preventDefault();
}
onDragInterval() {
if (this.dragClientY > 0 && this.dragClientY < 75)
this.$window.scrollTo(0, this.$window.scrollY - 25);
}
dragStart(event) {
event.target.classList.add('dragging');
event.dataTransfer.setData('text', event.target.id);
const element = this.findDroppable(event);
this.dragging = element;
this.interval = setInterval(() => this.onDragInterval(), 100);
}
dragEnd(event) {
event.target.classList.remove('dragging');
this.undrop();
this.dropCount = 0;
this.dragging = null;
clearInterval(this.interval);
}
dragEnter(event) {
let element = this.findDroppable(event);
if (element) this.dropCount++;
if (element != this.dropping) {
this.undrop();
if (element) element.classList.add('dropping');
this.dropping = element;
}
}
dragLeave(event) {
let element = this.findDroppable(event);
if (element) {
this.dropCount--;
if (this.dropCount == 0) this.undrop();
}
}
drop(event) {
event.preventDefault();
this.element.classList.remove('dropping');
const $dropped = this.dropping.$ctrl.item;
const $dragged = this.dragging.$ctrl.item;
if ($dropped != $dragged.parent)
this.emit('drop', {$dropped, $dragged});
}
get data() {
@ -109,7 +201,10 @@ export default class Treeview extends Component {
let childs = parent.childs;
if (!childs) childs = [];
childs.push(item);
if (!parent.active)
this.unfold(parent);
else
childs.push(item);
if (this.sortFunc) {
childs = childs.sort((a, b) =>
@ -120,12 +215,30 @@ export default class Treeview extends Component {
if (parent) parent.sons++;
}
onDrop(item, dragged, dropped) {
this.emit('drop', {item, dragged, dropped});
move(item, newParent) {
if (newParent == item) return;
if (item.parent) {
const parent = item.parent;
const childs = parent.childs;
const index = childs.indexOf(item);
parent.sons--;
childs.splice(index, 1);
}
item.parent = newParent;
if (!newParent.active) {
this.unfold(newParent).then(() => {
item.parent.sons++;
});
} else
this.create(item);
}
}
Treeview.$inject = ['$element', '$scope', '$transclude'];
Treeview.$inject = ['$element', '$scope', '$transclude', '$window'];
ngModule.component('vnTreeview', {
template: require('./index.html'),

View File

@ -0,0 +1,260 @@
describe('Component vnTreeview', () => {
let controller;
let $element;
beforeEach(angular.mock.module('vnCore', $translateProvider => {
$translateProvider.translations('en', {});
}));
beforeEach(inject(($compile, $rootScope) => {
$element = $compile(`<vn-treeview></vn-treeview>`)($rootScope);
controller = $element.controller('vnTreeview');
const promise = new Promise(() => {
return {name: 'My item'};
});
controller.fetchFunc = () => {
return promise;
};
controller.createFunc = () => {
return promise;
};
controller.removeFunc = () => {
return promise;
};
controller.sortFunc = () => {
return promise;
};
}));
afterEach(() => {
$element.remove();
});
// See how to test DOM element in Jest
xdescribe('undrop()', () => {
it(`should reset all drop events and properties`, () => {
controller.dropping = angular.element(`<vn-treeview-child class="dropping"></vn-treeview-child>`);
spyOn(controller.dropping.classList, 'remove');
controller.undrop();
expect(controller.dropping).toBeNull();
});
});
describe('dragOver()', () => {
it(`should set the dragClientY property`, () => {
const event = new Event('dragover');
event.clientY = 100;
controller.dragOver(event);
expect(controller.dragClientY).toEqual(100);
});
});
describe('data() setter', () => {
it(`should set the items property nested into a root element`, () => {
const items = [{name: 'Item1'}, {name: 'Item2'}];
controller.data = items;
const rootItem = controller.items[0];
expect(rootItem.childs).toEqual(items);
});
});
describe('fetch()', () => {
it(`should call the fetchFunc() method`, () => {
spyOn(controller, 'fetchFunc').and.returnValue(
new Promise(resolve => resolve([{name: 'My item'}]))
);
controller.fetch().then(() => {
expect(controller.data).toBeDefined();
});
expect(controller.fetchFunc).toHaveBeenCalledWith();
});
});
describe('setParent()', () => {
it(`should set the parent property recursively to each element of an item list`, () => {
spyOn(controller, 'setParent').and.callThrough();
const items = [{name: 'Item1'}, {name: 'Item2', childs: [
{name: 'Item3'}
]}];
const rootItem = {name: 'Nested tree', sons: items};
controller.setParent(rootItem, items);
expect(items[0].parent).toEqual(rootItem);
expect(items[1].parent).toEqual(rootItem);
expect(controller.setParent).toHaveBeenCalledWith(rootItem, items[1].childs);
});
});
describe('onToggle()', () => {
it(`should call the fold() or unfold() methods`, () => {
spyOn(controller, 'fold');
spyOn(controller, 'unfold');
const item = {name: 'My item'};
controller.onToggle(item);
item.active = true;
controller.onToggle(item);
expect(controller.unfold).toHaveBeenCalledWith(item);
expect(controller.fold).toHaveBeenCalledWith(item);
});
});
describe('fold()', () => {
it(`should remove the childs and set the active property to false`, () => {
const item = {name: 'My item', childs: [{name: 'Item 1'}], active: true};
controller.fold(item);
expect(item.childs).toBeUndefined();
expect(item.active).toBeFalsy();
});
});
describe('unfold()', () => {
it(`should unfold a parent item`, () => {
const expectedResponse = [{name: 'Item 1'}, {name: 'Item 2'}];
spyOn(controller, 'fetchFunc').and.returnValue(
new Promise(resolve => resolve(expectedResponse))
);
spyOn(controller, 'setParent');
spyOn(controller, 'sortFunc');
const parent = {name: 'My item', sons: 1};
const child = {name: 'Item 1'};
child.parent = parent;
parent.childs = [child];
controller.unfold(parent).then(() => {
expect(controller.fetchFunc).toHaveBeenCalledWith({$item: parent});
expect(controller.setParent).toHaveBeenCalledWith(parent, expectedResponse);
expect(controller.sortFunc).toHaveBeenCalledWith(jasmine.any(Object));
expect(parent.active).toBeTruthy();
});
});
});
describe('onRemove()', () => {
it(`should call the removeFunc() method`, () => {
spyOn(controller, 'removeFunc');
const item = {name: 'My item'};
controller.onRemove(item);
expect(controller.removeFunc).toHaveBeenCalledWith({$item: item});
});
});
describe('remove()', () => {
it(`should remove a child element`, () => {
const parent = {name: 'My item', sons: 1};
const child = {name: 'Item 1'};
child.parent = parent;
parent.childs = [child];
controller.remove(child);
expect(parent.childs).toEqual([]);
expect(parent.sons).toEqual(0);
});
});
describe('onCreate()', () => {
it(`should call the createFunc() method`, () => {
spyOn(controller, 'createFunc');
const parent = {name: 'My item'};
controller.onCreate(parent);
expect(controller.createFunc).toHaveBeenCalledWith({$parent: parent});
});
});
describe('create()', () => {
it(`should unfold an inactive parent and then create a child`, () => {
spyOn(controller, 'unfold');
spyOn(controller, 'sortFunc');
const parent = {name: 'My item', sons: 2, childs: [
{name: 'Item 1'},
{name: 'Item 2'}
]};
const child = {name: 'Item 3'};
child.parent = parent;
parent.childs.push(child);
controller.create(child);
expect(parent.sons).toEqual(3);
expect(controller.unfold).toHaveBeenCalledWith(parent);
expect(controller.sortFunc).toHaveBeenCalledWith(jasmine.any(Object));
expect(controller.sortFunc).toHaveBeenCalledTimes(2);
});
it(`should create a child on an active parent`, () => {
spyOn(controller, 'unfold');
spyOn(controller, 'sortFunc');
const parent = {name: 'My item', sons: 2, childs: [
{name: 'Item 1'},
{name: 'Item 2'}
], active: true};
const child = {name: 'Item 3'};
child.parent = parent;
controller.create(child);
expect(parent.sons).toEqual(3);
expect(controller.unfold).not.toHaveBeenCalledWith(parent);
expect(controller.sortFunc).toHaveBeenCalledWith(jasmine.any(Object));
expect(controller.sortFunc).toHaveBeenCalledTimes(2);
});
});
describe('move()', () => {
it(`should move an item to anocher parent and then unfold the parent`, () => {
spyOn(controller, 'unfold').and.returnValue(
new Promise(resolve => resolve())
);
const newParent = {name: 'My item 2', sons: 0};
const parent = {name: 'My item', sons: 3, childs: [
{name: 'Item 1'},
{name: 'Item 2'}
]};
const child = {name: 'Item 3'};
child.parent = parent;
parent.childs.push(child);
controller.move(child, newParent);
expect(parent.sons).toEqual(2);
expect(controller.unfold).toHaveBeenCalledWith(newParent);
});
it(`should move an item to anocher parent`, () => {
spyOn(controller, 'unfold');
spyOn(controller, 'create');
const newParent = {name: 'My item 2', sons: 0, active: true};
const parent = {name: 'My item', sons: 3, childs: [
{name: 'Item 1'},
{name: 'Item 2'}
]};
const child = {name: 'Item 3'};
child.parent = parent;
parent.childs.push(child);
controller.move(child, newParent);
expect(parent.sons).toEqual(2);
expect(controller.unfold).not.toHaveBeenCalledWith(newParent);
});
});
});

View File

@ -10,22 +10,6 @@ vn-treeview-childs {
li {
list-style: none;
& > .node {
@extend %clickable;
display: flex;
padding: 5px;
align-items: center;
}
& > div > .arrow {
min-width: 24px;
margin-right: 10px;
transition: transform 200ms;
}
& > div.expanded > .arrow {
transform: rotate(180deg);
}
ul {
padding-left: 2.2em;
}
@ -45,8 +29,28 @@ vn-treeview-childs {
.node:hover > .buttons {
display: block
}
.content {
flex-grow: 1
}
}
vn-treeview-content {
flex-grow: 1
}
vn-treeview-child {
font-size: 16px;
display: block;
.node {
@extend %clickable;
display: flex;
padding: 5px;
align-items: center;
}
& > div > .arrow {
min-width: 24px;
margin-right: 10px;
transition: transform 200ms;
}
&.expanded > div > .arrow {
transform: rotate(180deg);
}
}

View File

@ -1,43 +0,0 @@
import ngModule from '../module';
/**
* Enables a draggable element and his drag events
*
* @return {Object} The directive
*/
export function directive() {
return {
restrict: 'A',
link: function($scope, $element, $attrs) {
const element = $element[0];
const isDraggable = $attrs.vnDraggable === 'true';
if (!isDraggable) return;
// Set draggable style properties
element.style.cursor = 'move';
// Enable as draggable element
element.setAttribute('draggable', true);
/**
* Fires when a drag event starts
*/
element.addEventListener('dragstart', event => {
element.style.opacity = 0.5;
event.stopPropagation();
});
/**
* Fires when a drag event ends
*/
element.addEventListener('dragend', event => {
element.style.opacity = 1;
event.stopPropagation();
});
}
};
}
ngModule.directive('vnDraggable', directive);

View File

@ -1,68 +1,43 @@
import ngModule from '../module';
import './droppable.scss';
export function directive($parse) {
return {
restrict: 'A',
link: function($scope, $element, $attrs) {
const element = $element[0];
const onDropEvent = $parse($attrs.onDrop);
const isDroppable = $attrs.vnDroppable === 'true';
class Controller {
constructor($element, $, $attrs) {
this.element = $element[0];
this.$ = $;
this.$attrs = $attrs;
if (!isDroppable) return;
this.element.addEventListener('dragover',
event => event.preventDefault()); // Prevents page reload
this.element.addEventListener('drop',
event => this.drop(event));
this.element.addEventListener('dragenter',
event => this.dragEnter(event));
this.element.addEventListener('dragleave',
event => this.dragLeave(event));
}
/**
* Captures current dragging element
*/
element.addEventListener('dragstart', () => {
this.dragged = element;
});
dragEnter(event) {
this.droppedElement = event.target;
this.element.classList.add('dropping');
}
/**
* Enter droppable area event
*/
element.addEventListener('dragenter', event => {
element.classList.add('active');
dragLeave(event) {
if (this.droppedElement === event.target)
this.element.classList.remove('dropping');
}
event.stopImmediatePropagation();
event.preventDefault();
}, false);
/**
* Exit droppable area event
*/
element.addEventListener('dragleave', event => {
element.classList.remove('active');
event.stopImmediatePropagation();
event.preventDefault();
});
/**
* Prevent dragover for allowing
* dispatch drop event
*/
element.addEventListener('dragover', event => {
event.stopPropagation();
event.preventDefault();
});
/**
* Fires when a drop events
*/
element.addEventListener('drop', event => {
element.classList.remove('active');
onDropEvent($scope, {event});
event.stopPropagation();
event.preventDefault();
});
}
};
drop(event) {
if (event.defaultPrevented) return;
event.preventDefault();
this.element.classList.remove('dropping');
this.$.$eval(this.$attrs.vnDroppable, {$event: event});
}
}
Controller.$inject = ['$element', '$scope', '$attrs'];
directive.$inject = ['$parse'];
ngModule.directive('vnDroppable', directive);
ngModule.directive('vnDroppable', () => {
return {
controller: Controller
};
});

View File

@ -1,11 +1,25 @@
@import "./variables";
.vn-droppable,
.vn-draggable,
[vn-droppable] {
border: 2px dashed transparent;
border-radius: 0.5em;
transition: all 0.5s;
}
&.active {
.vn-droppable,
[vn-droppable] {
display: block;
&.dropping {
background-color: $color-hover-cd;
border: 2px dashed $color-bg-dark;
border-color: $color-bg-dark;
}
}
.vn-draggable.dragging {
background-color: $color-main-light;
border-color: $color-main;
}

View File

@ -11,7 +11,6 @@ import './bind';
import './repeat-last';
import './title';
import './uvc';
import './draggable';
import './droppable';
import './http-click';
import './http-submit';

View File

@ -24,10 +24,12 @@ export default class EventEmitter {
*/
off(callback) {
if (!this.$events) return;
for (let event in this.$events)
for (let i = 0; i < event.length; i++)
for (let event in this.$events) {
for (let i = 0; i < event.length; i++) {
if (event[i].callback === callback)
event.splice(i--, 1);
}
}
}
/**
@ -37,10 +39,12 @@ export default class EventEmitter {
*/
disconnect(thisArg) {
if (!this.$events) return;
for (let event in this.$events)
for (let i = 0; i < event.length; i++)
for (let event in this.$events) {
for (let i = 0; i < event.length; i++) {
if (event[i].thisArg === thisArg)
event.splice(i--, 1);
}
}
}
/**
@ -72,9 +76,10 @@ export default class EventEmitter {
if (this[prop])
this[prop].disconnect(this);
this[prop] = value;
if (value)
if (value) {
for (let event in handlers)
value.on(event, handlers[event], this);
}
}
}
}

View File

@ -109,5 +109,7 @@
"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",
"The department name can't be repeated": "El nombre del departamento no puede repetirse",
"You cannot move a parent to any of its sons": "You cannot move a parent to any of its sons",
"You cannot move a parent to its own sons": "You cannot move a parent to its own sons",
"You can't create a claim for a removed ticket": "No puedes crear una reclamación para un ticket eliminado"
}

View File

@ -1,14 +1,14 @@
@import "variables";
vn-treeview-content {
& > vn-check:not(.indeterminate) {
vn-treeview-child {
.content > vn-check:not(.indeterminate) {
color: $color-main;
& > .btn {
border-color: $color-main;
}
}
& > vn-check.checked {
.content > vn-check.checked {
color: $color-main;
}
}

View File

@ -1,123 +1,119 @@
<vn-crud-model auto-load="false"
<vn-crud-model auto-load="true"
vn-id="model"
url="claim/api/ClaimEnds"
filter="$ctrl.filter"
data="$ctrl.salesClaimed">
</vn-crud-model>
<vn-vertical compact>
<vn-card class="vn-pa-lg">
<vn-vertical>
<vn-horizontal>
<div class="totalBox" ng-show="$ctrl.salesClaimed.length > 0">
<vn-label-value label="Total claimed"
value="{{$ctrl.claimedTotal | currency: 'EUR':2}}">
</vn-label-value>
</div>
</vn-horizontal>
<vn-horizontal>
<vn-tool-bar class="vn-mb-md">
<vn-button
label="Import claim"
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedState"
vn-http-click="$ctrl.importToNewRefundTicket()"p
vn-tooltip="Imports claim details">
</vn-button>
<vn-button
label="Import ticket"
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedState"
ng-click="$ctrl.showLastTickets($event)"
vn-tooltip="Imports ticket lines">
</vn-button>
<vn-range
vn-one
label="Responsability"
min-label="Company"
max-label="Sales/Client"
ng-model="$ctrl.claim.responsibility"
max="$ctrl.maxResponsibility"
min="1"
step="1"
vn-acl="salesAssistant"
on-change="$ctrl.saveResponsibility(value)">
</vn-range>
</vn-tool-bar>
<vn-one
style = "text-align:right">
<vn-check
vn-one
label="Is paid with mana"
ng-model="$ctrl.claim.isChargedToMana"
vn-acl="salesAssistant"
on-change="$ctrl.saveMana(value)">
</vn-check>
</vn-one>
</vn-horizontal>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th number>Id</vn-th>
<vn-th number>Ticket</vn-th>
<vn-th>Destination</vn-th>
<vn-th>Landed</vn-th>
<vn-th number>Quantity</vn-th>
<vn-th>Description</vn-th>
<vn-th number>Price</vn-th>
<vn-th number>Disc.</vn-th>
<vn-th number>Total</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr
ng-repeat="saleClaimed in $ctrl.salesClaimed"
vn-repeat-last on-last="$ctrl.focusLastInput()">
<vn-td number>
<span
ng-click="$ctrl.showDescriptor($event, saleClaimed.sale.itemFk)"
class="link">
{{saleClaimed.sale.itemFk | zeroFill:6}}
</span>
</vn-td>
<vn-td number>
<span
class="link"
ng-click="$ctrl.showTicketDescriptor($event, saleClaimed.sale.ticketFk)">
{{::saleClaimed.sale.ticketFk}}
<vn-card class="vn-mb-md vn-pa-lg vn-w-lg" style="text-align: right"
ng-if="$ctrl.salesClaimed.length > 0">
<vn-label-value label="Total claimed"
value="{{$ctrl.claimedTotal | currency: 'EUR':2}}">
</vn-label-value>
</vn-card>
<vn-card class="vn-pa-lg vn-w-lg">
<section class="header">
<vn-tool-bar class="vn-mb-md">
<vn-button
label="Import claim"
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedState"
vn-http-click="$ctrl.importToNewRefundTicket()"p
translate-attr="{title: 'Imports claim details'}">
</vn-button>
<vn-button
label="Import ticket"
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedState"
ng-click="$ctrl.showLastTickets($event)"
translate-attr="{title: 'Imports ticket lines'}">
</vn-button>
<vn-range
vn-one
label="Responsability"
min-label="Company"
max-label="Sales/Client"
ng-model="$ctrl.claim.responsibility"
max="$ctrl.maxResponsibility"
min="1"
step="1"
vn-acl="salesAssistant"
on-change="$ctrl.saveResponsibility(value)">
</vn-range>
</vn-tool-bar>
<vn-check vn-one
label="Is paid with mana"
ng-model="$ctrl.claim.isChargedToMana"
vn-acl="salesAssistant"
on-change="$ctrl.saveMana(value)">
</vn-check>
</section>
<vn-data-viewer model="model">
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th number>Id</vn-th>
<vn-th number>Ticket</vn-th>
<vn-th>Destination</vn-th>
<vn-th>Landed</vn-th>
<vn-th number>Quantity</vn-th>
<vn-th>Description</vn-th>
<vn-th number>Price</vn-th>
<vn-th number>Disc.</vn-th>
<vn-th number>Total</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr
ng-repeat="saleClaimed in $ctrl.salesClaimed"
vn-repeat-last on-last="$ctrl.focusLastInput()">
<vn-td number>
<span
ng-click="$ctrl.showDescriptor($event, saleClaimed.sale.itemFk)"
class="link">
{{::saleClaimed.sale.itemFk | zeroFill:6}}
</span>
</vn-td>
<vn-td>
<vn-autocomplete
vn-one
id="claimDestinationFk"
ng-model="saleClaimed.claimDestinationFk"
url="/claim/api/ClaimDestinations"
fields="['id','description']"
value-field="id"
show-field="description"
on-change="$ctrl.setClaimDestination(saleClaimed.id, value)">
</vn-autocomplete>
</vn-td>
<vn-td>{{saleClaimed.sale.ticket.landed | dateTime: 'dd/MM/yyyy'}}</vn-td>
<vn-td number>{{saleClaimed.sale.quantity}}</vn-td>
<vn-td expand>{{saleClaimed.sale.concept}}</vn-td>
<vn-td number>{{saleClaimed.sale.price | currency: 'EUR':2}}</vn-td>
<vn-td number>{{saleClaimed.sale.discount}} %</vn-td>
<vn-td number>
{{saleClaimed.sale.quantity * saleClaimed.sale.price *
((100 - saleClaimed.sale.discount) / 100) | currency: 'EUR':2}}
</vn-td>
<vn-td shrink>
<vn-icon-button
vn-tooltip="Remove line"
icon="delete"
ng-click="$ctrl.deleteClaimedSale(saleClaimed.id)"
tabindex="-1">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-vertical>
</vn-card>
</vn-td>
<vn-td number>
<span
class="link"
ng-click="$ctrl.showTicketDescriptor($event, saleClaimed.sale.ticketFk)">
{{::saleClaimed.sale.ticketFk}}
</span>
</vn-td>
<vn-td>
<vn-autocomplete vn-one
id="claimDestinationFk"
ng-model="saleClaimed.claimDestinationFk"
url="/claim/api/ClaimDestinations"
fields="['id','description']"
value-field="id"
show-field="description"
on-change="$ctrl.setClaimDestination(saleClaimed.id, value)">
</vn-autocomplete>
</vn-td>
<vn-td>{{::saleClaimed.sale.ticket.landed | dateTime: 'dd/MM/yyyy'}}</vn-td>
<vn-td number>{{::saleClaimed.sale.quantity}}</vn-td>
<vn-td expand>{{::saleClaimed.sale.concept}}</vn-td>
<vn-td number>{{::saleClaimed.sale.price | currency: 'EUR':2}}</vn-td>
<vn-td number>{{::saleClaimed.sale.discount}} %</vn-td>
<vn-td number>
{{saleClaimed.sale.quantity * saleClaimed.sale.price *
((100 - saleClaimed.sale.discount) / 100) | currency: 'EUR':2}}
</vn-td>
<vn-td shrink>
<vn-icon-button
vn-tooltip="Remove line"
icon="delete"
ng-click="$ctrl.deleteClaimedSale(saleClaimed.id)"
tabindex="-1">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-data-viewer>
<vn-button-bar>
<vn-button
label="Regularize"
@ -125,11 +121,7 @@
vn-http-click="$ctrl.regularize()">
</vn-button>
</vn-button-bar>
<!-- WIP
<a ng-click="$ctrl.openAddSalesDialog()" vn-tooltip="New item" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>
-->
</vn-card>
<!-- Add Lines Dialog -->
<vn-dialog vn-id="addSales">

View File

@ -1,4 +1,19 @@
vn-claim-action {
.header {
display: flex;
justify-content: space-between;
align-items: center;
align-content: center;
vn-tool-bar {
flex: 1
}
vn-check {
flex: none;
}
}
vn-dialog[vn-id=addSales] {
tpl-body {
width: 950px;

View File

@ -1,84 +1,84 @@
<vn-crud-model
auto-load="false"
vn-id="model"
<vn-crud-model vn-id="model"
auto-load="true"
url="claim/api/ClaimBeginnings"
filter="$ctrl.filter"
data="$ctrl.salesClaimed"
on-data-change="$ctrl.calculateTotals()">
</vn-crud-model>
<vn-vertical>
<vn-card class="vn-pa-lg">
<vn-vertical>
<vn-horizontal>
<div class="totalBox">
<vn-label-value label="Total"
value="{{$ctrl.paidTotal | currency: 'EUR':2}}">
</vn-label-value>
<vn-label-value label="Total claimed"
value="{{$ctrl.claimedTotal | currency: 'EUR':2}}">
</vn-label-value>
</div>
</vn-horizontal>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th center>Landed</vn-th>
<vn-th number>Quantity</vn-th>
<vn-th>Claimed</vn-th>
<vn-th>Description</vn-th>
<vn-th number>Price</vn-th>
<vn-th number>Disc.</vn-th>
<vn-th number>Total</vn-th>
<vn-th></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="saleClaimed in $ctrl.salesClaimed" vn-repeat-last>
<vn-td center>{{::saleClaimed.sale.ticket.landed | dateTime:'dd/MM/yyyy'}}</vn-td>
<vn-td number>{{::saleClaimed.sale.quantity}}</vn-td>
<vn-td>
<vn-input-number
vn-focus min="0"
step="1"
ng-model="saleClaimed.quantity"
on-change="$ctrl.setClaimedQuantity(saleClaimed.id, saleClaimed.quantity)">
</vn-input-number>
</vn-td>
<vn-td expand title="{{::saleClaimed.sale.concept}}">
<span
class="link"
ng-click="$ctrl.showItemDescriptor($event, saleClaimed.sale.itemFk)">
{{::saleClaimed.sale.concept}}
</span>
</vn-td>
<vn-td number>{{::saleClaimed.sale.price | currency: 'EUR':2}}</vn-td>
<vn-td number>
<span class="link"
vn-tooltip="Edit discount"
ng-click="$ctrl.showEditPopover($event, saleClaimed)">
{{::saleClaimed.sale.discount}} %
</span>
</vn-td>
<vn-td number>
{{::$ctrl.getSaleTotal(saleClaimed.sale) | currency: 'EUR':2}}
</vn-td>
<vn-td shrink>
<vn-icon-button
vn-tooltip="Remove sale"
icon="delete"
ng-click="$ctrl.deleteClaimedSale($index)"
tabindex="-1">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-vertical>
</vn-card>
<a ng-click="$ctrl.openAddSalesDialog()" vn-tooltip="Add sale item" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>
</vn-vertical>
<vn-card class="vn-mb-md vn-pa-lg vn-w-lg" style="text-align: right"
ng-if="$ctrl.salesClaimed.length > 0">
<vn-label-value label="Total"
value="{{$ctrl.paidTotal | currency: 'EUR':2}}">
</vn-label-value>
<vn-label-value label="Total claimed"
value="{{$ctrl.claimedTotal | currency: 'EUR':2}}">
</vn-label-value>
</vn-card>
<vn-card class="vn-pa-lg">
<vn-data-viewer model="model">
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th center>Landed</vn-th>
<vn-th number>Quantity</vn-th>
<vn-th>Claimed</vn-th>
<vn-th>Description</vn-th>
<vn-th number>Price</vn-th>
<vn-th number>Disc.</vn-th>
<vn-th number>Total</vn-th>
<vn-th></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="saleClaimed in $ctrl.salesClaimed" vn-repeat-last>
<vn-td center>{{::saleClaimed.sale.ticket.landed | dateTime:'dd/MM/yyyy'}}</vn-td>
<vn-td number>{{::saleClaimed.sale.quantity}}</vn-td>
<vn-td>
<vn-input-number
vn-focus min="0"
step="1"
ng-model="saleClaimed.quantity"
on-change="$ctrl.setClaimedQuantity(saleClaimed.id, saleClaimed.quantity)">
</vn-input-number>
</vn-td>
<vn-td expand title="{{::saleClaimed.sale.concept}}">
<span
class="link"
ng-click="$ctrl.showItemDescriptor($event, saleClaimed.sale.itemFk)">
{{::saleClaimed.sale.concept}}
</span>
</vn-td>
<vn-td number>{{::saleClaimed.sale.price | currency: 'EUR':2}}</vn-td>
<vn-td number>
<span class="link"
vn-tooltip="Edit discount"
ng-click="$ctrl.showEditPopover($event, saleClaimed)">
{{::saleClaimed.sale.discount}} %
</span>
</vn-td>
<vn-td number>
{{::$ctrl.getSaleTotal(saleClaimed.sale) | currency: 'EUR':2}}
</vn-td>
<vn-td shrink>
<vn-icon-button
vn-tooltip="Remove sale"
icon="delete"
ng-click="$ctrl.deleteClaimedSale($index)"
tabindex="-1">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-data-viewer>
</vn-card>
<a ng-click="$ctrl.openAddSalesDialog()" vn-tooltip="Add sale item" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>
<!-- Add Lines Dialog -->
<vn-dialog vn-id="add-sales" class="modal-form">
<tpl-body>

View File

@ -5,7 +5,7 @@
data="$ctrl.photos">
</vn-crud-model>
<section class="drop-zone" vn-droppable="true" on-drop="$ctrl.onDrop(event)">
<section class="drop-zone" vn-droppable="$ctrl.onDrop($event)">
<section><vn-icon icon="add_circle"></vn-icon></section>
<section translate>Drag & Drop files here...</section>
</section>

View File

@ -36,8 +36,9 @@ class Controller {
}
}
onDrop(event) {
const files = event.dataTransfer.files;
onDrop($event) {
console.log($event);
const files = $event.dataTransfer.files;
this.setDefaultParams().then(() => {
this.dms.files = files;
this.create();

View File

@ -1,11 +1,9 @@
<vn-crud-model
<vn-crud-model vn-id="model"
url="/api/ClaimDms"
where="{claimFk: $ctrl.$stateParams.id}"
data="photos"
auto-load="true">
data="photos">
</vn-crud-model>
<vn-card class="summary">
<h5>{{$ctrl.summary.claim.id}} - {{$ctrl.summary.claim.client.name}}</h5>
<h5>{{::$ctrl.summary.claim.id}} - {{::$ctrl.summary.claim.client.name}}</h5>
<vn-horizontal>
<vn-one>
<vn-label-value label="Created"
@ -45,41 +43,43 @@
</vn-one>
<vn-auto>
<h4 translate>Detail</h4>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th number>Item</vn-th>
<vn-th>Landed</vn-th>
<vn-th number>Quantity</vn-th>
<vn-th number>Claimed</vn-th>
<vn-th>Description</vn-th>
<vn-th number>Price</vn-th>
<vn-th number>Disc.</vn-th>
<vn-th number>Total</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="saleClaimed in $ctrl.summary.salesClaimed">
<vn-td number>
<span
ng-click="$ctrl.showItemDescriptor($event, saleClaimed.sale.itemFk)"
class="link">
{{saleClaimed.sale.itemFk | zeroFill:6}}
</span>
</vn-td>
<vn-td>{{saleClaimed.sale.ticket.landed | dateTime: 'dd/MM/yyyy'}}</vn-td>
<vn-td number>{{saleClaimed.sale.quantity}}</vn-td>
<vn-td number>{{saleClaimed.quantity}}</vn-td>
<vn-td expand>{{saleClaimed.sale.concept}}</vn-td>
<vn-td number>{{saleClaimed.sale.price | currency: 'EUR':2}}</vn-td>
<vn-td number>{{saleClaimed.sale.discount}} %</vn-td>
<vn-td number>
{{saleClaimed.sale.quantity * saleClaimed.sale.price *
((100 - saleClaimed.sale.discount) / 100) | currency: 'EUR':2}}
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
<vn-data-viewer data="::$ctrl.summary.salesClaimed">
<vn-table>
<vn-thead>
<vn-tr>
<vn-th number>Item</vn-th>
<vn-th>Landed</vn-th>
<vn-th number>Quantity</vn-th>
<vn-th number>Claimed</vn-th>
<vn-th>Description</vn-th>
<vn-th number>Price</vn-th>
<vn-th number>Disc.</vn-th>
<vn-th number>Total</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="saleClaimed in $ctrl.summary.salesClaimed">
<vn-td number>
<span
ng-click="$ctrl.showItemDescriptor($event, saleClaimed.sale.itemFk)"
class="link">
{{::saleClaimed.sale.itemFk | zeroFill:6}}
</span>
</vn-td>
<vn-td>{{::saleClaimed.sale.ticket.landed | dateTime: 'dd/MM/yyyy'}}</vn-td>
<vn-td number>{{::saleClaimed.sale.quantity}}</vn-td>
<vn-td number>{{::saleClaimed.quantity}}</vn-td>
<vn-td expand>{{::saleClaimed.sale.concept}}</vn-td>
<vn-td number>{{::saleClaimed.sale.price | currency: 'EUR':2}}</vn-td>
<vn-td number>{{::saleClaimed.sale.discount}} %</vn-td>
<vn-td number>
{{saleClaimed.sale.quantity * saleClaimed.sale.price *
((100 - saleClaimed.sale.discount) / 100) | currency: 'EUR':2}}
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-data-viewer>
</vn-auto>
<vn-auto ng-if="photos.length > 0">
<h4 translate>Photos</h4>
@ -94,78 +94,82 @@
</vn-auto>
<vn-auto>
<h4 translate>Development</h4>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th>Reason</vn-th>
<vn-th>Result</vn-th>
<vn-th>Responsible</vn-th>
<vn-th>Worker</vn-th>
<vn-th>Redelivery</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="development in $ctrl.summary.developments">
<vn-td>{{development.claimReason.description}}</vn-td>
<vn-td>{{development.claimResult.description}}</vn-td>
<vn-td>{{development.claimResponsible.description}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, development.workerFk)">
{{::development.worker.user.nickname}}
</span>
</vn-td>
<vn-td>{{development.claimRedelivery.description}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
<vn-data-viewer data="::$ctrl.summary.developments">
<vn-table>
<vn-thead>
<vn-tr>
<vn-th>Reason</vn-th>
<vn-th>Result</vn-th>
<vn-th>Responsible</vn-th>
<vn-th>Worker</vn-th>
<vn-th>Redelivery</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="development in $ctrl.summary.developments">
<vn-td>{{::development.claimReason.description}}</vn-td>
<vn-td>{{::development.claimResult.description}}</vn-td>
<vn-td>{{::development.claimResponsible.description}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, development.workerFk)">
{{::development.worker.user.nickname}}
</span>
</vn-td>
<vn-td>{{::development.claimRedelivery.description}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-data-viewer>
</vn-auto>
<vn-auto>
<h4 translate>Action</h4>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th number>Item</vn-th>
<vn-th number>Ticket</vn-th>
<vn-th>Destination</vn-th>
<vn-th number>Landed</vn-th>
<vn-th number>Quantity</vn-th>
<vn-th>Description</vn-th>
<vn-th number>Price</vn-th>
<vn-th number>Disc.</vn-th>
<vn-th number>Total</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="action in $ctrl.summary.actions">
<vn-td number>
<span
ng-click="$ctrl.showItemDescriptor($event, action.sale.itemFk)"
class="link">
{{action.sale.itemFk | zeroFill:6}}
</span>
</vn-td>
<vn-td number>
<span
ng-click="$ctrl.showTicketDescriptor($event, action.sale.ticket.id)"
class="link">
{{action.sale.ticket.id | zeroFill:6}}
</span>
</vn-td>
<vn-td expand>{{action.claimBeggining.description}}</vn-td>
<vn-td number>{{action.sale.ticket.landed | dateTime: 'dd/MM/yyyy'}}</vn-td>
<vn-td number>{{action.sale.quantity}}</vn-td>
<vn-td expand>{{action.sale.concept}}</vn-td>
<vn-td number>{{action.sale.price}}</vn-td>
<vn-td number>{{action.sale.discount}} %</vn-td>
<vn-td number>
{{action.sale.quantity * action.sale.price *
((100 - action.sale.discount) / 100) | currency: 'EUR':2}}
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
<vn-data-viewer data="::$ctrl.summary.actions">
<vn-table>
<vn-thead>
<vn-tr>
<vn-th number>Item</vn-th>
<vn-th number>Ticket</vn-th>
<vn-th>Destination</vn-th>
<vn-th number>Landed</vn-th>
<vn-th number>Quantity</vn-th>
<vn-th>Description</vn-th>
<vn-th number>Price</vn-th>
<vn-th number>Disc.</vn-th>
<vn-th number>Total</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="action in $ctrl.summary.actions">
<vn-td number>
<span
ng-click="$ctrl.showItemDescriptor($event, action.sale.itemFk)"
class="link">
{{::action.sale.itemFk | zeroFill:6}}
</span>
</vn-td>
<vn-td number>
<span
ng-click="$ctrl.showTicketDescriptor($event, action.sale.ticket.id)"
class="link">
{{::action.sale.ticket.id | zeroFill:6}}
</span>
</vn-td>
<vn-td expand>{{::action.claimBeggining.description}}</vn-td>
<vn-td number>{{::action.sale.ticket.landed | dateTime: 'dd/MM/yyyy'}}</vn-td>
<vn-td number>{{::action.sale.quantity}}</vn-td>
<vn-td expand>{{::action.sale.concept}}</vn-td>
<vn-td number>{{::action.sale.price}}</vn-td>
<vn-td number>{{::action.sale.discount}} %</vn-td>
<vn-td number>
{{action.sale.quantity * action.sale.price *
((100 - action.sale.discount) / 100) | currency: 'EUR':2}}
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-data-viewer>
</vn-auto>
</vn-horizontal>
</vn-card>

View File

@ -9,6 +9,26 @@ class Controller {
this.accessToken = vnToken.token;
}
get claim() {
return this._claim;
}
set claim(value) {
this._claim = value;
// Get DMS on summary load
/* if (value)
this.$.$applyAsync(() => this.loadDms()); */
}
loadDms() {
this.$.model.where = {
claimFk: this.claim.id
};
this.$.model.refresh();
}
getSummary() {
this.$http.get(`/claim/api/Claims/${this.claim.id}/getSummary`).then(response => {
this.summary = response.data;

View File

@ -1,4 +1,5 @@
import './index.js';
import crudModel from 'core/mocks/crud-model';
describe('Claim', () => {
describe('Component summary', () => {
@ -13,6 +14,7 @@ describe('Claim', () => {
$httpBackend = _$httpBackend_;
controller = $componentController('vnClaimSummary');
controller.claim = {id: 1};
controller.$.model = crudModel;
}));
describe('getSummary()', () => {

View File

@ -117,6 +117,6 @@ describe('Route filter()', () => {
let result = await app.models.Route.filter(ctx);
expect(result.length).toEqual(4);
expect(result.length).toEqual(1);
});
});

View File

@ -4,6 +4,6 @@ describe('route getTickets()', () => {
it('should return the tickets for a given route', async() => {
let result = await app.models.Route.getTickets(2);
expect(result.length).toEqual(4);
expect(result.length).toEqual(1);
});
});

View File

@ -1,7 +1,7 @@
const app = require('vn-loopback/server/server');
describe('route guessPriority()', () => {
const targetRouteId = 2;
const targetRouteId = 7;
let routeTicketsToRestore;
afterAll(async done => {
@ -17,25 +17,23 @@ describe('route guessPriority()', () => {
it('should confirm the tickets in the target route have no priority yet', async() => {
routeTicketsToRestore = await app.models.Ticket.find({where: {routeFk: targetRouteId}});
expect(routeTicketsToRestore.length).toEqual(4);
expect(routeTicketsToRestore.length).toEqual(2);
expect(routeTicketsToRestore[0].id).toEqual(23);
expect(routeTicketsToRestore[0].priority).toBeNull();
expect(routeTicketsToRestore[0].id).toEqual(7);
expect(routeTicketsToRestore[1].id).toEqual(24);
expect(routeTicketsToRestore[1].priority).toBeNull();
expect(routeTicketsToRestore[1].id).toEqual(8);
expect(routeTicketsToRestore[2].priority).toBeNull();
expect(routeTicketsToRestore[2].id).toEqual(9);
});
it('should call guessPriority() and then check the tickets in the target route now have their priorities defined', async() => {
await app.models.Route.guessPriority(targetRouteId);
let routeTickets = await app.models.Ticket.find({where: {routeFk: targetRouteId}, fields: ['id', 'priority']});
expect(routeTickets.length).toEqual(4);
expect(routeTickets[0].priority).toEqual(1);
expect(routeTickets[0].id).toEqual(7);
expect(routeTickets[1].priority).toEqual(3);
expect(routeTickets[1].id).toEqual(8);
expect(routeTickets[2].priority).toEqual(2);
expect(routeTickets[2].id).toEqual(9);
expect(routeTickets.length).toEqual(2);
expect(routeTickets[0].id).toEqual(23);
expect(routeTickets[0].priority).toEqual(3);
expect(routeTickets[1].id).toEqual(24);
expect(routeTickets[1].priority).toEqual(1);
});
});

View File

@ -11,7 +11,7 @@ describe('route summary()', () => {
const result = await app.models.Route.summary(1);
const agency = result.route.agencyMode();
expect(agency.name).toEqual('Silla247');
expect(agency.name).toEqual('inhouse pickup');
});
it(`should return a summary object containing it's vehicle`, async() => {
@ -31,6 +31,6 @@ describe('route summary()', () => {
it(`should return a summary object containing data from the tickets`, async() => {
const result = await app.models.Route.summary(2);
expect(result.tickets.length).toEqual(4);
expect(result.tickets.length).toEqual(1);
});
});

View File

@ -10,8 +10,8 @@ describe('route updateVolume()', () => {
afterAll(async done => {
await originalRoute.updateAttributes({m3: 2.7});
await ticketToRestore.updateAttributes({routeFk: 2});
await originalRoute.updateAttributes({m3: 1.8});
await ticketToRestore.updateAttributes({routeFk: null});
await app.models.RouteLog.destroyById(logIdToDestroy);
done();
});
@ -19,12 +19,12 @@ describe('route updateVolume()', () => {
it('should confirm the original volume of the route is the expected', async() => {
originalRoute = await app.models.Route.findById(routeId);
expect(originalRoute.m3).toEqual(2.7);
expect(originalRoute.m3).toEqual(1.8);
});
it('should confirm the route volume is updated when a ticket is added', async() => {
ticketToRestore = await app.models.Ticket.findById(8);
let updatedTicket = await app.models.Ticket.findById(8);
ticketToRestore = await app.models.Ticket.findById(14);
let updatedTicket = await app.models.Ticket.findById(14);
await updatedTicket.updateAttributes({routeFk: routeId});
await app.models.Route.updateVolume(ctx, routeId);
@ -36,8 +36,9 @@ describe('route updateVolume()', () => {
it('should confirm the change is logged', async() => {
let logs = await app.models.RouteLog.find({fields: ['id', 'newInstance']});
let m3Log = logs.filter(log => {
return log.newInstance.m3 === 3.1;
return log.newInstance.m3 === 1.9;
});
logIdToDestroy = m3Log[0].id;

View File

@ -216,7 +216,7 @@
"url" : "/create",
"state": "ticket.card.request.create",
"component": "vn-ticket-request-create",
"description": "Purchase request",
"description": "New purchase request",
"acl": ["salesPerson"]
}, {
"url": "/create?clientFk",

View File

@ -0,0 +1,42 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('moveChild', {
description: 'Changes the parent of a child department',
accessType: 'WRITE',
accepts: [{
arg: 'id',
type: 'Number',
description: 'The department id',
http: {source: 'path'}
}, {
arg: 'parentId',
type: 'Number',
description: 'New parent id',
}],
returns: {
type: 'Object',
root: true
},
http: {
path: `/:id/moveChild`,
verb: 'POST'
}
});
Self.moveChild = async(id, parentId = null) => {
const models = Self.app.models;
const child = await models.Department.findById(id);
if (id == parentId) return;
if (parentId) {
const parent = await models.Department.findById(parentId);
if (child.lft < parent.lft && child.rgt > parent.rgt)
throw new UserError('You cannot move a parent to its own sons');
}
return child.updateAttribute('parentFk', parentId);
};
};

View File

@ -0,0 +1,18 @@
const app = require('vn-loopback/server/server');
describe('department createChild()', () => {
let createdChild;
afterAll(async done => {
await createdChild.destroy();
done();
});
it('should create a new child', async() => {
const parentId = null;
createdChild = await app.models.Department.createChild(parentId, 'My new department');
expect(createdChild.name).toEqual('My new department');
expect(createdChild.parentFk).toBeNull();
});
});

View File

@ -0,0 +1,23 @@
const app = require('vn-loopback/server/server');
describe('department moveChild()', () => {
let updatedChild;
afterAll(async done => {
const child = await app.models.Department.findById(updatedChild.id);
await child.updateAttribute('parentFk', null);
done();
});
it('should move a child department to a new parent', async() => {
const childId = 22;
const parentId = 1;
const child = await app.models.Department.findById(childId);
expect(child.parentFk).toBeNull();
updatedChild = await app.models.Department.moveChild(childId, parentId);
expect(updatedChild.parentFk).toEqual(1);
});
});

View File

@ -0,0 +1,21 @@
const app = require('vn-loopback/server/server');
describe('department removeChild()', () => {
let removedChild;
afterAll(async done => {
await app.models.Department.create(removedChild);
done();
});
it('should remove a child department', async() => {
const childId = 1;
removedChild = await app.models.Department.findById(childId);
const result = await app.models.Department.removeChild(childId);
const existsChild = await app.models.Department.findById(childId);
expect(result.count).toEqual(1);
expect(existsChild).toBeNull();
});
});

View File

@ -32,14 +32,12 @@ module.exports = Self => {
throw new UserError(`You don't have enough privileges`);
const subordinate = await Worker.findById(data.workerFk);
const timed = new Date(data.timed);
return Self.create({
userFk: subordinate.userFk,
timed: data.timed,
manual: 1
});
let offset = timed.getTimezoneOffset() * 60000;
timed.setTime(timed.getTime() - offset);
/* return Self.rawSql('CALL vn.workerTimeControl_add(?, ?, ?, ?)', [
subordinate.userFk, null, data.timed, true]); */
return Self.rawSql('CALL vn.workerTimeControl_add(?, ?, ?, ?)', [
subordinate.userFk, null, timed, true]);
};
};

View File

@ -2,4 +2,5 @@ module.exports = Self => {
require('../methods/department/getLeaves')(Self);
require('../methods/department/createChild')(Self);
require('../methods/department/removeChild')(Self);
require('../methods/department/moveChild')(Self);
};

View File

@ -16,6 +16,15 @@
},
"parentFk": {
"type": "Number"
},
"lft": {
"type": "Number"
},
"rgt": {
"type": "Number"
},
"sons": {
"type": "Number"
}
}
}

View File

@ -10,7 +10,10 @@
fetch-func="$ctrl.onFetch($item)"
remove-func="$ctrl.onRemove($item)"
create-func="$ctrl.onCreate($parent)"
sort-func="$ctrl.onSort($a, $b)">
sort-func="$ctrl.onSort($a, $b)"
on-drop="$ctrl.onDrop($dropped, $dragged)"
on-drag-start="$ctrl.onDragStart(item)"
on-drag-end="$ctrl.onDragEnd(item)">
{{::item.name}}
</vn-treeview>
</vn-card>

View File

@ -23,19 +23,13 @@ class Controller {
return a.name.localeCompare(b.name);
}
/* onDrop(item, dragged, dropped) {
if (dropped.scope.item) {
const droppedItem = dropped.scope.item;
const draggedItem = dragged.scope.item;
if (droppedItem.childs)
droppedItem.childs.push(Object.assign({}, draggedItem));
dragged.element.remove();
this.$scope.$apply();
}
} */
onDrop(dropped, dragged) {
const params = dropped ? {parentId: dropped.id} : null;
const query = `/api/departments/${dragged.id}/moveChild`;
this.$http.post(query, params).then(() => {
this.$.treeview.move(dragged, dropped);
});
}
onCreate(parent) {
this.newChild = {
@ -62,12 +56,8 @@ class Controller {
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;

View File

@ -88,7 +88,7 @@
ng-if="!log.newProperties"
id="description">
<div>
<span>{{log.description}}</span>
<span>{{::log.description}}</span>
</div>
</vn-one>
</vn-td>