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 @@ -495,3 +495,4 @@ erpnext.patches.v16_0.enable_book_stock_expense_gl_entries
erpnext.patches.v16_0.rename_ar_ap_ageing_filter
erpnext.patches.v16_0.fix_subcontracting_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)
51 changes: 51 additions & 0 deletions erpnext/setup/doctype/item_group/test_item_group.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import unittest
from unittest.mock import patch

import frappe
from frappe.utils.nestedset import (
Expand All @@ -14,6 +15,8 @@

from erpnext.tests.utils import ERPNextTestSuite

TRANSLATED_ROOT = "Todos os Grupos de Itens"


class TestItemGroup(ERPNextTestSuite):
def setUp(self):
Expand Down Expand Up @@ -209,6 +212,54 @@ def test_merge_group_into_leaf(self):
merge=True,
)

def test_preset_records_use_existing_root(self):
from erpnext.setup.setup_wizard.operations import install_fixtures

with patch.object(install_fixtures, "get_root_of", return_value=TRANSLATED_ROOT):
records = [
r for r in install_fixtures.get_preset_records("India") if r["doctype"] == "Item Group"
]

root_record, *child_records = records
self.assertEqual(root_record["item_group_name"], TRANSLATED_ROOT)
self.assertTrue(root_record["__condition"]())
self.assertEqual({r["parent_item_group"] for r in child_records}, {TRANSLATED_ROOT})

with patch.object(install_fixtures, "get_root_of", return_value="All Item Groups"):
root_record = next(
r for r in install_fixtures.get_preset_records("India") if r["doctype"] == "Item Group"
)
self.assertFalse(root_record["__condition"]())

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(
frappe.get_all("Item Group", filters={"parent_item_group": ("is", "not set")}, pluck="name"),
[TRANSLATED_ROOT],
)
self.assertEqual(
frappe.db.get_value("Item Group", "_Test Item Group B", "parent_item_group"), TRANSLATED_ROOT
)
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}).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")

def _move_it_back(self):
group_b = frappe.get_doc("Item Group", "_Test Item Group B")
group_b.parent_item_group = "All Item Groups"
Expand Down
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 @@ -12,6 +12,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 get_preset_records(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