Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions erpnext/patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -446,3 +446,4 @@ erpnext.patches.v16_0.access_control_for_project_users
erpnext.patches.v16_0.rename_ar_ap_ageing_filter
erpnext.patches.v15_0.fix_titles
erpnext.patches.v16_0.backfill_repost_accounting_ledger_status
erpnext.patches.v16_0.merge_seeded_item_group_root
23 changes: 23 additions & 0 deletions erpnext/patches/v16_0/merge_seeded_item_group_root.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import frappe
from frappe.utils.nestedset import get_root_of

SEEDED_ROOT = "All Item Groups"


def execute():
"""Collapse the "All Item Groups" node seeded under a pre-existing root.

Setup seeding always inserted "All Item Groups" as a parentless group. On a
site where another app had already created the root (under a translated
name), it was re-parented instead, leaving a second group-root holding the
standard Item Groups.
"""
root = get_root_of("Item Group")
if not root or root == SEEDED_ROOT:
return

seeded = frappe.db.get_value("Item Group", SEEDED_ROOT, ["parent_item_group", "is_group"], as_dict=True)
if not seeded or not seeded.is_group or seeded.parent_item_group != root:
return

frappe.rename_doc("Item Group", SEEDED_ROOT, root, merge=True, show_alert=False)
45 changes: 45 additions & 0 deletions erpnext/setup/doctype/item_group/test_item_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

test_records = frappe.get_test_records("Item Group")

TRANSLATED_ROOT = "Todos os Grupos de Itens"


class TestItem(unittest.TestCase):
def test_basic_tree(self, records=None):
Expand Down Expand Up @@ -234,3 +236,46 @@ def test_merge_group_into_leaf(self):
"_Test Item Group B - 3",
merge=True,
)

def test_patch_merges_seeded_root_into_existing_root(self):
from erpnext.patches.v16_0.merge_seeded_item_group_root import execute

self.nest_root_under(TRANSLATED_ROOT)
self.assertEqual(
frappe.db.get_value("Item Group", "All Item Groups", "parent_item_group"), TRANSLATED_ROOT
)

execute()

self.assertFalse(frappe.db.exists("Item Group", "All Item Groups"))
self.assertEqual(self.get_root_names(), [TRANSLATED_ROOT])
self.assertEqual(
frappe.db.get_value("Item Group", "_Test Item Group B", "parent_item_group"), TRANSLATED_ROOT
)
self.test_basic_tree()

# restore the original root name for the tests that follow
frappe.rename_doc("Item Group", TRANSLATED_ROOT, "All Item Groups")
self.assertEqual(self.get_root_names(), ["All Item Groups"])
self.test_basic_tree()

def nest_root_under(self, new_root):
"""Recreate the tree left behind by seeding a root under a pre-existing one."""
frappe.get_doc(
{
"doctype": "Item Group",
"item_group_name": new_root,
"is_group": 1,
"parent_item_group": "All Item Groups",
}
).insert()

ig = frappe.qb.DocType("Item Group")
frappe.qb.update(ig).set(ig.parent_item_group, "").where(ig.name == new_root).run()
frappe.qb.update(ig).set(ig.parent_item_group, new_root).where(ig.name == "All Item Groups").run()
rebuild_tree("Item Group", "parent_item_group")

def get_root_names(self):
return frappe.db.sql_list(
"""select name from `tabItem Group` where ifnull(parent_item_group, '')=''"""
)
15 changes: 9 additions & 6 deletions erpnext/setup/setup_wizard/operations/install_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
)
from frappe.desk.page.setup_wizard.setup_wizard import make_records
from frappe.utils import cstr, getdate
from frappe.utils.nestedset import get_root_of

from erpnext.accounts.doctype.account.account import RootNotEditable
from erpnext.regional.address_template.setup import set_up_address_templates
Expand All @@ -24,46 +25,48 @@ def read_lines(filename: str) -> list[str]:


def install(country=None):
root_item_group = get_root_of("Item Group") or _("All Item Groups")
records = [
# ensure at least an empty Address Template exists for this Country
{"doctype": "Address Template", "country": country},
# item group
{
"doctype": "Item Group",
"item_group_name": _("All Item Groups"),
"item_group_name": root_item_group,
"is_group": 1,
"parent_item_group": "",
"__condition": lambda: not frappe.db.exists("Item Group", root_item_group),
},
{
"doctype": "Item Group",
"item_group_name": _("Products"),
"is_group": 0,
"parent_item_group": _("All Item Groups"),
"parent_item_group": root_item_group,
"show_in_website": 1,
},
{
"doctype": "Item Group",
"item_group_name": _("Raw Material"),
"is_group": 0,
"parent_item_group": _("All Item Groups"),
"parent_item_group": root_item_group,
},
{
"doctype": "Item Group",
"item_group_name": _("Services"),
"is_group": 0,
"parent_item_group": _("All Item Groups"),
"parent_item_group": root_item_group,
},
{
"doctype": "Item Group",
"item_group_name": _("Sub Assemblies"),
"is_group": 0,
"parent_item_group": _("All Item Groups"),
"parent_item_group": root_item_group,
},
{
"doctype": "Item Group",
"item_group_name": _("Consumable"),
"is_group": 0,
"parent_item_group": _("All Item Groups"),
"parent_item_group": root_item_group,
},
# Stock Entry Type
{
Expand Down
Loading