Sure I’ll be interested in contribution, And I have many a things that I can help in ERP concept.
About my issue.
I need to make department and each department has parent until we reach to the head manager department “Tree”.
I have already departments exists, I did the following:
1- Adding those fields to the department doctype [lft,rgt,is_group,parent_department]
2- Making page in the HR module.
3- Adding the code below, following some tutorials.
4- Adding nsm_parent_field = 'parent_department'
in the department.py file
5 - Adding on_update and on_trash in the department python file
6- Adding frappe.utils.nestedset.update_nsm(self)
inside on_update, and here is the problem when id remove this line every thing works, but by adding it this error message occare
Item cannot be added to its own descendents

JS:
frappe.pages[“department-browser”].on_page_load = function(wrapper){
var page = frappe.ui.make_app_page({
parent: wrapper,
single_column: true,
});
frappe.breadcrumbs.add(“Departments”);
wrapper.page.add_menu_item(__(‘Refresh’), function() {
wrapper.make_tree();
});
wrapper.make_tree = function() {
var ctype = frappe.get_route()[1] || ‘Department’;
return frappe.call({
method: ‘erpnext.hr.page.department_browser.department_browser.get_children’,
args: {ctype: ctype},
callback: function(r) {
var root = r.message[0]["value"];
frappe.tree_chart = new frappe.TreeChart(ctype, root, page,
page.main.css({
"min-height": "300px",
"padding-bottom": "25px"
}));
}
});
}
wrapper.make_tree();
}
frappe.pages[‘department-browser’].on_page_show = function(wrapper){
// set route
var ctype = frappe.get_route()[1] || ‘Tree’;
wrapper.page.set_title((‘{0} Chart’,[(ctype)]));
if(frappe.tree_chart && frappe.tree_chart.ctype != ctype) {
wrapper.make_tree();
}
frappe.breadcrumbs.add(frappe.breadcrumbs.last_module || “Tree Departments”);
};
frappe.TreeChart = Class.extend({
init: function(ctype, root, page, parent) {
$(parent).empty();
var me = this;
me.ctype = ctype;
me.page = page;
me.can_read = frappe.model.can_read(this.ctype);
me.can_create = frappe.boot.user.can_create.indexOf(this.ctype) !== -1 ||
frappe.boot.user.in_create.indexOf(this.ctype) !== -1;
me.can_write = frappe.model.can_write(this.ctype);
me.can_delete = frappe.model.can_delete(this.ctype);
me.page.set_primary_action(__("New"), function() {
me.new_node();
}, "octicon octicon-plus");
this.tree = new frappe.ui.Tree({
parent: $(parent),
label: __(root),
args: {ctype: ctype},
method: 'erpnext.hr.page.department_browser.department_browser.get_children',
toolbar: [
{toggle_btn: true},
{
label:__("Edit"),
condition: function(node) {
return !node.root && me.can_read;
},
click: function(node) {
frappe.set_route("Form", me.ctype, node.label);
}
},
{
label:__("Add Child"),
condition: function(node) { return me.can_create && node.expandable; },
click: function(node) {
me.new_node();
},
btnClass: "hidden-xs"
},
{
label:__("Rename"),
condition: function(node) { return !node.root && me.can_write; },
click: function(node) {
frappe.model.rename_doc(me.ctype, node.label, function(new_name) {
node.$a.html(new_name);
});
},
btnClass: "hidden-xs"
},
{
label:__("Delete"),
condition: function(node) { return !node.root && me.can_delete; },
click: function(node) {
frappe.model.delete_doc(me.ctype, node.label, function() {
node.parent.remove();
});
},
btnClass: "hidden-xs"
}
]
});
},
set_title: function(val) {
var chart_str = this.ctype==“Department” ? __(“Chart of Departments”) : __(“Chart of Departments”);
if(val) {
this.page.set_title(chart_str + " - " + cstr(val));
} else {
this.page.set_title(chart_str);
}
},
new_node: function() {
var me = this;
var node = me.tree.get_selected_node();
if(!(node && node.expandable)) {
frappe.msgprint(__("Select a group node first."));
return;
}
var fields = [
{fieldtype:'Data', fieldname: 'name_field',
label:__('New {0} Name',[__(me.ctype)]), reqd:true},
{fieldtype:'Select', fieldname:'is_group', label:__('Group Node'), options:'No\nYes',
description: __("Further nodes can be only created under 'Group' type nodes")}
]
// the dialog
var d = new frappe.ui.Dialog({
title: __('New {0}',[__(me.ctype)]),
fields: fields
})
d.set_value("is_group", "No");
// create
d.set_primary_action(__("Create New"), function() {
var btn = this;
var v = d.get_values();
if(!v) return;
var node = me.tree.get_selected_node();
v.parent = node.label;
v.ctype = me.ctype;
return frappe.call({
method: 'erpnext.hr.page.department_browser.department_browser.add_node',
args: v,
callback: function(r) {
if(!r.exc) {
d.hide();
if(node.expanded) {
node.toggle_node();
}
node.reload();
}
}
});
});
d.show();
},
});
Python
@frappe.whitelist()
def add_node():
ctype = frappe.form_dict.get(‘ctype’)
parent_field = ‘parent_’ + ctype.lower().replace(’ ', ‘‘)
name_field = ctype.lower().replace(’ ', '’) + ‘_name’
doc = frappe.new_doc(ctype)
doc.update({
name_field: frappe.form_dict[‘name_field’],
parent_field: frappe.form_dict[‘parent’],
“is_group”: frappe.form_dict[‘is_group’]
})
doc.save()
@frappe.whitelist()
def get_children():
ctype = frappe.local.form_dict.get(‘ctype’)
parent_field = ‘parent_’ + ctype.lower().replace(’ ', ‘_’)
parent = frappe.form_dict.get(“parent”) or “”
return frappe.db.sql(“”“select name as value,
if(is_group=‘Yes’, 1, 0) as expandable
from tab{ctype}
where docstatus < 2
and ifnull({parent_field}
,‘’) = %s
order by name”“”.format(ctype=frappe.db.escape(ctype), parent_field=frappe.db.escape(parent_field)),
parent, as_dict=1)