feat: Create NestedSet doctypes via configuration
This commit is contained in:
parent
e2b3c56902
commit
bff94703cf
7 changed files with 94 additions and 8 deletions
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
{base_class_import}
|
||||
|
||||
class {classname}(Document):
|
||||
class {classname}({base_class}):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
"is_submittable",
|
||||
"istable",
|
||||
"issingle",
|
||||
"is_tree",
|
||||
"editable_grid",
|
||||
"quick_entry",
|
||||
"cb01",
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
"form_settings_section",
|
||||
"image_field",
|
||||
"timeline_field",
|
||||
"nsm_parent_field",
|
||||
"max_attachments",
|
||||
"column_break_23",
|
||||
"hide_toolbar",
|
||||
|
|
@ -438,11 +440,23 @@
|
|||
"fieldtype": "Select",
|
||||
"label": "Database Engine",
|
||||
"options": "InnoDB\nMyISAM"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "Tree structures are implemented using Nested Set",
|
||||
"fieldname": "is_tree",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Tree"
|
||||
},
|
||||
{
|
||||
"fieldname": "nsm_parent_field",
|
||||
"fieldtype": "Data",
|
||||
"label": "Parent Field (Tree)"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-bolt",
|
||||
"idx": 6,
|
||||
"modified": "2019-07-04 23:23:17.174960",
|
||||
"modified": "2019-09-02 05:51:29.411525",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "DocType",
|
||||
|
|
@ -475,4 +489,4 @@
|
|||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
|
@ -84,6 +84,7 @@ class DocType(Document):
|
|||
|
||||
self.make_amendable()
|
||||
self.make_repeatable()
|
||||
self.validate_nestedset()
|
||||
self.validate_website()
|
||||
|
||||
if not self.is_new():
|
||||
|
|
@ -581,6 +582,64 @@ class DocType(Document):
|
|||
df = dict(fieldname='auto_repeat', label='Auto Repeat', fieldtype='Link', options='Auto Repeat', insert_after=insert_after, read_only=1, no_copy=1, print_hide=1)
|
||||
create_custom_field(self.name, df)
|
||||
|
||||
def validate_nestedset(self):
|
||||
if not self.is_tree:
|
||||
return
|
||||
self.add_nestedset_fields()
|
||||
# set field as mandatory
|
||||
field = self.meta.get_field('nsm_parent_field')
|
||||
field.reqd = 1
|
||||
# check if field is valid
|
||||
fieldnames = [df.fieldname for df in self.fields]
|
||||
if self.nsm_parent_field and self.nsm_parent_field not in fieldnames:
|
||||
frappe.throw(_("Parent Field must be a valid fieldname"), InvalidFieldNameError)
|
||||
|
||||
def add_nestedset_fields(self):
|
||||
"""If is_tree is set, add parent_field, lft, rgt, is_group fields."""
|
||||
fieldnames = [df.fieldname for df in self.fields]
|
||||
if 'lft' in fieldnames:
|
||||
return
|
||||
|
||||
self.append("fields", {
|
||||
"label": "Left",
|
||||
"fieldtype": "Int",
|
||||
"fieldname": "lft",
|
||||
"read_only": 1,
|
||||
"hidden": 1,
|
||||
"no_copy": 1
|
||||
})
|
||||
|
||||
self.append("fields", {
|
||||
"label": "Right",
|
||||
"fieldtype": "Int",
|
||||
"fieldname": "rgt",
|
||||
"read_only": 1,
|
||||
"hidden": 1,
|
||||
"no_copy": 1
|
||||
})
|
||||
|
||||
self.append("fields", {
|
||||
"label": "Is Group",
|
||||
"fieldtype": "Check",
|
||||
"fieldname": "is_group"
|
||||
})
|
||||
self.append("fields", {
|
||||
"label": "Old Parent",
|
||||
"fieldtype": "Link",
|
||||
"options": self.name,
|
||||
"fieldname": "old_parent"
|
||||
})
|
||||
|
||||
parent_field_label = "Parent {}".format(self.name)
|
||||
parent_field_name = frappe.scrub(parent_field_label)
|
||||
self.append("fields", {
|
||||
"label": parent_field_label,
|
||||
"fieldtype": "Link",
|
||||
"options": self.name,
|
||||
"fieldname": parent_field_name
|
||||
})
|
||||
self.nsm_parent_field = parent_field_name
|
||||
|
||||
|
||||
def get_max_idx(self):
|
||||
"""Returns the highest `idx`"""
|
||||
|
|
|
|||
|
|
@ -30,14 +30,15 @@ def get_controller(doctype):
|
|||
|
||||
:param doctype: DocType name as string."""
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils.nestedset import NestedSet
|
||||
global _classes
|
||||
|
||||
if not doctype in _classes:
|
||||
module_name, custom = frappe.db.get_value("DocType", doctype, ("module", "custom"), cache=True) \
|
||||
or ["Core", False]
|
||||
module_name, custom, is_tree = frappe.db.get_value("DocType", doctype, ("module", "custom", "is_tree"), cache=True) \
|
||||
or ["Core", False, False]
|
||||
|
||||
if custom:
|
||||
_class = Document
|
||||
_class = NestedSet if is_tree else Document
|
||||
else:
|
||||
module = load_doctype_module(doctype, module_name)
|
||||
classname = doctype.replace(" ", "").replace("-", "")
|
||||
|
|
|
|||
|
|
@ -240,6 +240,12 @@ def make_boilerplate(template, doc, opts=None):
|
|||
if not opts:
|
||||
opts = {}
|
||||
|
||||
base_class = 'Document'
|
||||
base_class_import = 'from frappe.model.document import Document'
|
||||
if doc.is_tree:
|
||||
base_class = 'NestedSet'
|
||||
base_class_import = 'from frappe.utils.nestedset import NestedSet'
|
||||
|
||||
with open(target_file_path, 'w') as target:
|
||||
with open(os.path.join(get_module_path("core"), "doctype", scrub(doc.doctype),
|
||||
"boilerplate", template), 'r') as source:
|
||||
|
|
@ -248,5 +254,7 @@ def make_boilerplate(template, doc, opts=None):
|
|||
app_publisher=app_publisher,
|
||||
year=frappe.utils.nowdate()[:4],
|
||||
classname=doc.name.replace(" ", ""),
|
||||
base_class_import=base_class_import,
|
||||
base_class=base_class,
|
||||
doctype=doc.name, **opts)
|
||||
))
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ frappe.views.ListSidebar = class ListSidebar {
|
|||
show_list_link = true;
|
||||
}
|
||||
|
||||
if (frappe.treeview_settings[this.doctype]) {
|
||||
if (frappe.treeview_settings[this.doctype] || frappe.get_meta(this.doctype).is_tree) {
|
||||
this.sidebar.find(".tree-link").removeClass("hide");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -183,6 +183,10 @@ def validate_loop(doctype, name, lft, rgt):
|
|||
frappe.throw(_("Item cannot be added to its own descendents"), NestedSetRecursionError)
|
||||
|
||||
class NestedSet(Document):
|
||||
def __setup__(self):
|
||||
if self.meta.nsm_parent_field:
|
||||
self.nsm_parent_field = self.meta.nsm_parent_field
|
||||
|
||||
def on_update(self):
|
||||
update_nsm(self)
|
||||
self.validate_ledger()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue