diff --git a/front/core/components/treeview/child.html b/front/core/components/treeview/child.html
new file mode 100644
index 0000000000..1b928d5ea5
--- /dev/null
+++ b/front/core/components/treeview/child.html
@@ -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>
diff --git a/front/core/components/treeview/content.js b/front/core/components/treeview/child.js
similarity index 51%
rename from front/core/components/treeview/content.js
rename to front/core/components/treeview/child.js
index 506117d4f8..9e4edef35f 100644
--- a/front/core/components/treeview/content.js
+++ b/front/core/components/treeview/child.js
@@ -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: '<'
diff --git a/front/core/components/treeview/childs.html b/front/core/components/treeview/childs.html
index 2dd7e77ef4..de69ffb891 100644
--- a/front/core/components/treeview/childs.html
+++ b/front/core/components/treeview/childs.html
@@ -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>
\ No newline at end of file
diff --git a/front/core/components/treeview/index.js b/front/core/components/treeview/index.js
index d9da39215b..22d6739f76 100644
--- a/front/core/components/treeview/index.js
+++ b/front/core/components/treeview/index.js
@@ -1,18 +1,113 @@
 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) {
+        let scrollY = this.$window.scrollY;
+
+        if (event.clientY < this.draggingY)
+            scrollY -= 2;
+        else scrollY += 2;
+
+        this.draggingY = event.clientY;
+        this.$window.scrollTo(0, scrollY);
+
+        // Prevents page reload
+        event.preventDefault();
+    }
+
+    dragStart(event) {
+        event.target.classList.add('dragging');
+        event.dataTransfer.setData('text', event.target.id);
+
+        const element = this.findDroppable(event);
+        this.dragging = element;
+    }
+
+    dragEnd(event) {
+        event.target.classList.remove('dragging');
+        this.undrop();
+        this.dropCount = 0;
+        this.dragging = null;
+    }
+
+    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.active && $dropped.sons) {
+            this.unfold($dropped).then(() => {
+                this.emit('drop', {$dropped, $dragged});
+            });
+        } else
+            this.emit('drop', {$dropped, $dragged});
     }
 
     get data() {
@@ -100,8 +195,14 @@ export default class Treeview extends Component {
     }
 
     onCreate(parent) {
-        if (this.createFunc)
-            this.createFunc({$parent: parent});
+        if (this.createFunc) {
+            if (!parent.active && parent.sons) {
+                this.unfold(parent).then(() => {
+                    this.createFunc({$parent: parent});
+                });
+            } else
+                this.createFunc({$parent: parent});
+        }
     }
 
     create(item) {
@@ -120,12 +221,24 @@ 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;
+        this.create(item);
     }
 }
 
-Treeview.$inject = ['$element', '$scope', '$transclude'];
+Treeview.$inject = ['$element', '$scope', '$transclude', '$window'];
 
 ngModule.component('vnTreeview', {
     template: require('./index.html'),
diff --git a/front/core/components/treeview/style.scss b/front/core/components/treeview/style.scss
index b3724a9f1d..e39d1708db 100644
--- a/front/core/components/treeview/style.scss
+++ b/front/core/components/treeview/style.scss
@@ -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,27 @@ vn-treeview-childs {
     .node:hover > .buttons {
         display: block
     }
+
+    .content {
+        flex-grow: 1
+    }
 }
 
-vn-treeview-content {
-    flex-grow: 1
-}
\ No newline at end of file
+vn-treeview-child {
+    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);
+    }
+} 
\ No newline at end of file
diff --git a/front/core/directives/draggable.js b/front/core/directives/draggable.js
deleted file mode 100644
index 3b68a6cb6d..0000000000
--- a/front/core/directives/draggable.js
+++ /dev/null
@@ -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);
diff --git a/front/core/directives/droppable.js b/front/core/directives/droppable.js
index 4832824183..929b64be77 100644
--- a/front/core/directives/droppable.js
+++ b/front/core/directives/droppable.js
@@ -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
+    };
+});
diff --git a/front/core/directives/droppable.scss b/front/core/directives/droppable.scss
index 749bc9a12f..97e6f8a197 100644
--- a/front/core/directives/droppable.scss
+++ b/front/core/directives/droppable.scss
@@ -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;
 }
\ No newline at end of file
diff --git a/front/core/directives/index.js b/front/core/directives/index.js
index 08adfac077..7ee63220b4 100644
--- a/front/core/directives/index.js
+++ b/front/core/directives/index.js
@@ -11,7 +11,6 @@ import './bind';
 import './repeat-last';
 import './title';
 import './uvc';
-import './draggable';
 import './droppable';
 import './http-click';
 import './http-submit';
diff --git a/front/core/lib/event-emitter.js b/front/core/lib/event-emitter.js
index 2dede42ab9..022e4e98c2 100644
--- a/front/core/lib/event-emitter.js
+++ b/front/core/lib/event-emitter.js
@@ -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);
+            }
         }
     }
 }
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index 07c95af32a..aa135d520f 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -108,5 +108,7 @@
 	"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",
-	"The department name can't be repeated": "El nombre del departamento no puede repetirse"
+	"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"
 }
\ No newline at end of file
diff --git a/modules/claim/front/dms/index/index.html b/modules/claim/front/dms/index/index.html
index 10e35e58e6..81bd088a79 100644
--- a/modules/claim/front/dms/index/index.html
+++ b/modules/claim/front/dms/index/index.html
@@ -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>
diff --git a/modules/claim/front/dms/index/index.js b/modules/claim/front/dms/index/index.js
index f60feab6c7..f382e4d676 100644
--- a/modules/claim/front/dms/index/index.js
+++ b/modules/claim/front/dms/index/index.js
@@ -35,8 +35,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();
diff --git a/modules/worker/back/methods/department/moveChild.js b/modules/worker/back/methods/department/moveChild.js
new file mode 100644
index 0000000000..97206f198c
--- /dev/null
+++ b/modules/worker/back/methods/department/moveChild.js
@@ -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);
+    };
+};
diff --git a/modules/worker/back/models/department.js b/modules/worker/back/models/department.js
index e6905d273c..5a927fc640 100644
--- a/modules/worker/back/models/department.js
+++ b/modules/worker/back/models/department.js
@@ -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);
 };
diff --git a/modules/worker/back/models/department.json b/modules/worker/back/models/department.json
index bb5d5e9434..7de76e0395 100644
--- a/modules/worker/back/models/department.json
+++ b/modules/worker/back/models/department.json
@@ -16,6 +16,15 @@
         },
         "parentFk": {
             "type": "Number"
+        },
+        "lft": {
+            "type": "Number"
+        },
+        "rgt": {
+            "type": "Number"
+        },
+        "sons": {
+            "type": "Number"
         }
     }
 }
diff --git a/modules/worker/front/department/index.html b/modules/worker/front/department/index.html
index 7736620322..c7abaf3f8a 100644
--- a/modules/worker/front/department/index.html
+++ b/modules/worker/front/department/index.html
@@ -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>
diff --git a/modules/worker/front/department/index.js b/modules/worker/front/department/index.js
index 1a72681bce..b103efff96 100644
--- a/modules/worker/front/department/index.js
+++ b/modules/worker/front/department/index.js
@@ -23,19 +23,21 @@ 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;
+    onDrop(dropped, dragged) {
+        if (!dropped.active) {
+            this.$.treeview.unfold(dropped).then(() =>
+                this.move(dropped, dragged));
+        } else
+            this.move(dropped, dragged);
+    }
 
-            if (droppedItem.childs)
-                droppedItem.childs.push(Object.assign({}, draggedItem));
-
-            dragged.element.remove();
-
-            this.$scope.$apply();
-        }
-    } */
+    move(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,9 +64,6 @@ 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;