From 2e5310f8a01a424fe8e42755726dbe9e2354c295 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Sun, 21 Jun 2026 15:29:16 +0530 Subject: [PATCH] fix(manufacturing): case-sensitive variant BOM lookup on Postgres _bom_contains_item() lowercased the item name and then reused that lowercased value as a doc name in frappe.db.get_value("Item", item, "variant_of"). Doc names are case-sensitive on Postgres, so the lowercased name matched no row, variant_of came back NULL, and a Work Order for a variant item built from the template's BOM was wrongly rejected with 'BOM ... does not belong to Item ...'. Keep the original case for the Item lookup; the comparisons stay case-insensitive. MariaDB is unchanged (its name lookup was case-insensitive either way). --- erpnext/manufacturing/doctype/bom/bom.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index eebf131fd9d..90d898f4751 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -1402,16 +1402,18 @@ def validate_bom_no(item, bom_no): def _bom_contains_item(bom, item): - item = item.lower() + item_lower = item.lower() for d in bom.items: - if d.item_code.lower() == item: + if d.item_code.lower() == item_lower: return True for d in bom.secondary_items: - if d.item_code.lower() == item: + if d.item_code.lower() == item_lower: return True + # Use the original-cased `item` for the Item lookup: names are case-sensitive on Postgres, + # so a lowercased name would miss the record and drop the variant->template BOM match. return ( - bom.item.lower() == item + bom.item.lower() == item_lower or bom.item.lower() == cstr(frappe.db.get_value("Item", item, "variant_of")).lower() )