From 861c6b16bef2253a953acb4b2ecb3a0fddeaefb6 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Thu, 23 Jul 2026 13:06:45 +0530 Subject: [PATCH] fix: create default warehouses with untranslated names Company.create_default_warehouses stored warehouse_name through the session _(), so a site set up in a non-English language keeps its default warehouses under translated names. The opening-stock fallback in item.py then looks up {"warehouse_name": _("Stores")} from an arbitrary session and misses the warehouse whenever the lookup session's language differs from the creation session's. Create the default warehouses with canonical English names, matching the identity-_ convention install_fixtures uses for other default records. The exists-guard also matches the session translation so a re-run on a legacy site does not insert English duplicates next to translated warehouses. The "Stores" fallback lookup moves to get_stores_warehouse, which tries the canonical name first and falls back to the session translation so legacy sites keep resolving their translated warehouse. The setup-wizard and test-bootstrap lookups drop _() since they now run after English creation (install_fixtures already used identity _, so its lookup silently missed translated warehouses before this change). Same bug class as #57345. --- erpnext/setup/doctype/company/company.py | 7 ++++- erpnext/setup/doctype/company/test_company.py | 29 +++++++++++++++++++ .../setup_wizard/operations/defaults_setup.py | 2 +- erpnext/stock/doctype/item/item.py | 17 ++++++++--- erpnext/tests/utils.py | 2 +- 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index e0546122344..57cc0783002 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -448,6 +448,8 @@ class Company(NestedSet): frappe.clear_cache() def create_default_warehouses(self): + from erpnext.setup.utils import identity as _ + parent_warehouse = None for wh_detail in [ {"warehouse_name": _("All Warehouses"), "is_group": 1}, @@ -459,7 +461,10 @@ class Company(NestedSet): if frappe.db.exists( "Warehouse", { - "warehouse_name": wh_detail["warehouse_name"], + "warehouse_name": ( + "in", + (wh_detail["warehouse_name"], frappe._(wh_detail["warehouse_name"])), + ), "company": self.name, }, ): diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py index ea43ff9c373..79825001872 100644 --- a/erpnext/setup/doctype/company/test_company.py +++ b/erpnext/setup/doctype/company/test_company.py @@ -15,6 +15,7 @@ from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import from erpnext.accounts.doctype.account.test_account import create_account from erpnext.setup.doctype.company.company import get_default_company_address from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note +from erpnext.stock.doctype.item.item import get_stores_warehouse from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.tests.utils import ERPNextTestSuite @@ -214,6 +215,34 @@ class TestCompany(ERPNextTestSuite): self.assertEqual({d.parent_department for d in departments}, {"All Departments"}) self.assertIn("Buchhaltung - DTTC", [d.name for d in departments]) + def test_default_warehouses_ignore_session_translations(self): + translations = {"Stores": "Lager", "All Warehouses": "Alle Lagerhäuser"} + with patch("frappe.translate.get_all_translations", return_value=translations): + company = frappe.new_doc("Company") + company.company_name = "Warehouse Translation Test Co" + company.abbr = "WTTC" + company.default_currency = "INR" + company.country = "India" + company.insert() + + self.assertEqual(get_stores_warehouse(company.name), "Stores - WTTC") + + warehouse_names = frappe.get_all("Warehouse", filters={"company": company.name}, pluck="name") + for warehouse_name in ( + "All Warehouses", + "Stores", + "Work In Progress", + "Finished Goods", + "Goods In Transit", + ): + self.assertIn(f"{warehouse_name} - WTTC", warehouse_names) + self.assertNotIn("Lager - WTTC", warehouse_names) + self.assertEqual(get_stores_warehouse(company.name), "Stores - WTTC") + + frappe.db.set_value("Warehouse", "Stores - WTTC", "warehouse_name", "Lager", update_modified=False) + with patch("frappe.translate.get_all_translations", return_value=translations): + self.assertEqual(get_stores_warehouse(company.name), "Stores - WTTC") + def test_change_parent_company(self): child_company = frappe.get_doc("Company", "_Test Company 5") diff --git a/erpnext/setup/setup_wizard/operations/defaults_setup.py b/erpnext/setup/setup_wizard/operations/defaults_setup.py index 82698808250..02b66c3433c 100644 --- a/erpnext/setup/setup_wizard/operations/defaults_setup.py +++ b/erpnext/setup/setup_wizard/operations/defaults_setup.py @@ -30,7 +30,7 @@ def set_default_settings(args): stock_settings = frappe.get_doc("Stock Settings") stock_settings.item_naming_by = "Item Code" stock_settings.valuation_method = "FIFO" - stock_settings.default_warehouse = frappe.db.get_value("Warehouse", {"warehouse_name": _("Stores")}) + stock_settings.default_warehouse = frappe.db.get_value("Warehouse", {"warehouse_name": "Stores"}) stock_settings.stock_uom = "Nos" stock_settings.auto_indent = 1 stock_settings.auto_insert_price_list_rate_if_missing = 1 diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index d369e7f3e68..35e7e01a899 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -328,9 +328,7 @@ class Item(Document): warehouse_company = frappe.db.get_value("Warehouse", default_warehouse, "company") if not default_warehouse or warehouse_company != default.company: - default_warehouse = frappe.db.get_value( - "Warehouse", {"warehouse_name": _("Stores"), "company": default.company} - ) + default_warehouse = get_stores_warehouse(default.company) if default_warehouse: opening_account = frappe.db.get_value( @@ -1776,7 +1774,7 @@ def get_default_warehouse_for_opening_stock(item, company: str, warehouse: str | if warehouse_company == company: return settings_warehouse - stores_warehouse = frappe.db.get_value("Warehouse", {"warehouse_name": _("Stores"), "company": company}) + stores_warehouse = get_stores_warehouse(company) if stores_warehouse: return stores_warehouse @@ -1788,6 +1786,17 @@ def get_default_warehouse_for_opening_stock(item, company: str, warehouse: str | ) +def get_stores_warehouse(company: str) -> str | None: + stores_warehouse = frappe.db.get_value("Warehouse", {"warehouse_name": "Stores", "company": company}) + + if not stores_warehouse and _("Stores") != "Stores": + stores_warehouse = frappe.db.get_value( + "Warehouse", {"warehouse_name": _("Stores"), "company": company} + ) + + return stores_warehouse + + def on_doctype_update(): if frappe.db.db_type == "postgres": # The Item link-search (erpnext.controllers.queries.item_query) filters diff --git a/erpnext/tests/utils.py b/erpnext/tests/utils.py index aebb7a22650..55f471422f8 100644 --- a/erpnext/tests/utils.py +++ b/erpnext/tests/utils.py @@ -246,7 +246,7 @@ class BootStrapTestData: stock_settings = frappe.get_doc("Stock Settings") stock_settings.item_naming_by = "Item Code" stock_settings.valuation_method = "FIFO" - stock_settings.default_warehouse = frappe.db.get_value("Warehouse", {"warehouse_name": _("Stores")}) + stock_settings.default_warehouse = frappe.db.get_value("Warehouse", {"warehouse_name": "Stores"}) stock_settings.stock_uom = "Nos" stock_settings.auto_indent = 1 stock_settings.auto_insert_price_list_rate_if_missing = 1