Employee tree (#11667)
* nested set implemented
* treeview for employee
* patch added to assign lft rgt, update nsm_model on trash
* call on_trash method of super class
diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json
index 227302c..2779b1d 100644
--- a/erpnext/hr/doctype/employee/employee.json
+++ b/erpnext/hr/doctype/employee/employee.json
@@ -2418,6 +2418,96 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "lft",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "lft",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "rgt",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "rgt",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "old_parent",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "ignore_user_permissions": 1,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Old Parent",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
"has_web_view": 0,
@@ -2432,7 +2522,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-10-04 11:42:02.495731",
+ "modified": "2017-11-19 01:27:48.222343",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee",
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 03626cd..7c9c112 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -10,13 +10,14 @@
import frappe.permissions
from frappe.model.document import Document
from erpnext.utilities.transaction_base import delete_events
-
+from frappe.utils.nestedset import NestedSet
class EmployeeUserDisabledError(frappe.ValidationError):
pass
+class Employee(NestedSet):
+ nsm_parent_field = 'reports_to'
-class Employee(Document):
def autoname(self):
naming_method = frappe.db.get_value("HR Settings", None, "emp_created_by")
if not naming_method:
@@ -52,7 +53,11 @@
frappe.permissions.remove_user_permission(
"Employee", self.name, existing_user_id)
+ def update_nsm_model(self):
+ frappe.utils.nestedset.update_nsm(self)
+
def on_update(self):
+ self.update_nsm_model()
if self.user_id:
self.update_user()
self.update_user_permissions()
@@ -154,13 +159,13 @@
throw(_("Employee cannot report to himself."))
def on_trash(self):
+ super(Employee, self).on_trash()
delete_events(self.doctype, self.name)
def validate_prefered_email(self):
if self.prefered_contact_email and not self.get(scrub(self.prefered_contact_email)):
frappe.msgprint(_("Please enter " + self.prefered_contact_email))
-
def get_timeline_data(doctype, name):
'''Return timeline for attendance'''
return dict(frappe.db.sql('''select unix_timestamp(attendance_date), count(*)
@@ -183,7 +188,6 @@
return ret
-
def validate_employee_role(doc, method):
# called via User hook
if "Employee" in [d.role for d in doc.get("roles")]:
@@ -241,7 +245,6 @@
def is_holiday(employee, date=None):
'''Returns True if given Employee has an holiday on the given date
-
:param employee: Employee `name`
:param date: Date to check. Will check for today if None'''
@@ -300,4 +303,27 @@
if user or email:
employee_emails.append(user or email)
- return employee_emails
\ No newline at end of file
+ return employee_emails
+
+@frappe.whitelist()
+def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False):
+ condition = ''
+
+ if is_root:
+ parent = ""
+ if parent and company and parent!=company:
+ condition = ' and reports_to = "{0}"'.format(frappe.db.escape(parent))
+ else:
+ condition = ' and ifnull(reports_to, "")=""'
+
+ employee = frappe.db.sql("""
+ select
+ name as value, employee_name as title,
+ exists(select name from `tabEmployee` where reports_to=emp.name) as expandable
+ from
+ `tabEmployee` emp
+ where company='{company}' {condition} order by name"""
+ .format(company=company, condition=condition), as_dict=1)
+
+ # return employee
+ return employee
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee/employee_tree.js b/erpnext/hr/doctype/employee/employee_tree.js
new file mode 100644
index 0000000..5d3ec42
--- /dev/null
+++ b/erpnext/hr/doctype/employee/employee_tree.js
@@ -0,0 +1,36 @@
+frappe.treeview_settings['Employee'] = {
+ get_tree_nodes: "erpnext.hr.doctype.employee.employee.get_children",
+ filters: [
+ {
+ fieldname: "company",
+ fieldtype:"Select",
+ options: $.map(locals[':Company'], function(c) { return c.name; }).sort(),
+ label: __("Company"),
+ default: frappe.defaults.get_default('company') ? frappe.defaults.get_default('company') : ""
+ }
+ ],
+ breadcrumb: "Hr",
+ disable_add_node: true,
+ get_tree_root: false,
+ toolbar: [
+ { toggle_btn: true },
+ {
+ label:__("Edit"),
+ condition: function(node) {
+ return !node.is_root;
+ },
+ click: function(node) {
+ frappe.set_route("Form", "Employee", node.data.value);
+ }
+ }
+ ],
+ menu_items: [
+ {
+ label: __("New Employee"),
+ action: function() {
+ frappe.new_doc("Employee", true);
+ },
+ condition: 'frappe.boot.user.can_create.indexOf("Employee") !== -1'
+ }
+ ],
+};
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 7725615..a2efa82 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -472,4 +472,5 @@
erpnext.patches.v10_0.rename_schools_to_education
erpnext.patches.v9_2.repost_reserved_qty_for_production
erpnext.patches.v9_2.remove_company_from_patient
-erpnext.patches.v9_2.set_item_name_in_production_order
\ No newline at end of file
+erpnext.patches.v9_2.set_item_name_in_production_order
+erpnext.patches.v10_0.update_lft_rgt_for_employee
diff --git a/erpnext/patches/v10_0/update_lft_rgt_for_employee.py b/erpnext/patches/v10_0/update_lft_rgt_for_employee.py
new file mode 100644
index 0000000..82fbeaa
--- /dev/null
+++ b/erpnext/patches/v10_0/update_lft_rgt_for_employee.py
@@ -0,0 +1,8 @@
+import frappe
+from frappe.utils.nestedset import rebuild_tree
+
+def execute():
+ """ assign lft and rgt appropriately """
+ frappe.reload_doc("hr", "doctype", "employee")
+
+ rebuild_tree("Employee", "reports_to")
\ No newline at end of file