Department doctype Tree Page Error

Hi,
I’ve added tree page for Department doctype
I’ve added lft,rgt,is_group,parent_department feilds into the Department doctype

the problem appears when i enable this function
frappe.utils.nestedset.update_nsm(self)
it give me the following error

Item cannot be added to its own descendents

Any help ?
`

@mostafa share your code!

I can help if you are planning to contribute this back to the product.

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

:confused:

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)