diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 14562c2824b..2c34e83a5b9 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -104,28 +104,9 @@ class BOM(WebsiteGenerator): ) def autoname(self): - existing_boms = frappe.get_all("BOM", filters={"item": self.item}) + existing_boms = frappe.get_all("BOM", filters={"item": self.item}, pluck="name") if existing_boms: - existing_bom_names = [bom.name for bom in existing_boms] - - # split by "/" and "-" - delimiters = ["/", "-"] - pattern = "|".join(map(re.escape, delimiters)) - bom_parts = [re.split(pattern, bom_name) for bom_name in existing_bom_names] - - # filter out BOMs that do not follow the following formats: - # - BOM/ITEM/001 - # - BOM/ITEM/001-1 - # - BOM-ITEM-001 - # - BOM-ITEM-001-1 - valid_bom_parts = list(filter(lambda x: len(x) > 1 and x[-1], bom_parts)) - - # extract the current index from the BOM parts - if valid_bom_parts: - indexes = [cint(part[-1]) for part in valid_bom_parts] - index = max(indexes) + 1 - else: - index = 1 + index = self.get_next_version_index(existing_boms) else: index = 1 @@ -156,6 +137,29 @@ class BOM(WebsiteGenerator): self.name = name + @staticmethod + def get_next_version_index(existing_boms: List[str]) -> int: + # split by "/" and "-" + delimiters = ["/", "-"] + pattern = "|".join(map(re.escape, delimiters)) + bom_parts = [re.split(pattern, bom_name) for bom_name in existing_boms] + + # filter out BOMs that do not follow the following formats: + # - BOM/ITEM/001 + # - BOM/ITEM/001-1 + # - BOM-ITEM-001 + # - BOM-ITEM-001-1 + valid_bom_parts = list(filter(lambda x: len(x) > 1 and x[-1], bom_parts)) + + # extract the current index from the BOM parts + if valid_bom_parts: + indexes = [cint(part[-1]) for part in valid_bom_parts] + index = max(indexes) + 1 + else: + index = 1 + + return index + def validate(self): self.route = frappe.scrub(self.name).replace('_', '-') diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py index 08ac50fa6ee..f43329121f3 100644 --- a/erpnext/manufacturing/doctype/bom/test_bom.py +++ b/erpnext/manufacturing/doctype/bom/test_bom.py @@ -394,6 +394,27 @@ class TestBOM(ERPNextTestCase): } create_nested_bom(bom_tree, prefix="") + def test_version_index(self): + + bom = frappe.new_doc("BOM") + + version_index_test_cases = [ + (1, []), + (1, ["BOM#XYZ"]), + (2, ["BOM/ITEM/001"]), + (2, ["BOM/ITEM/001", "BOM/ITEM/001-1"]), + (2, ["BOM-ITEM-001",]), + (2, ["BOM-ITEM-001", "BOM-ITEM-001-1"]), + (3, ["BOM-ITEM-001", "BOM-ITEM-002", "BOM-ITEM-001-1"]), + (4, ["BOM-ITEM-001", "BOM-ITEM-002", "BOM-ITEM-003"]), + (2, ["BOM-ITEM-001", "BOM-ITEM-001-1", "BOM-ITEM-001-2"]), + ] + + for expected_index, existing_boms in version_index_test_cases: + with self.subTest(): + self.assertEqual(expected_index, bom.get_next_version_index(existing_boms), + msg=f"Incorrect index for {existing_boms}") + def get_default_bom(item_code="_Test FG Item 2"): return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})