From 5e3d0947c8a3b27844242d557f8a1989fd3ea6e2 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Tue, 11 Aug 2026 18:26:08 +0530 Subject: [PATCH] fix(stock): validate new warehouse inventory account after naming Move the insert-time check from before_insert to validate. before_insert runs before set_new_name, so the validation message rendered the warehouse name as None. validate runs after naming and only applies to new documents via is_new(). Resolve inheritance through the parent's lft/rgt bounds instead of the request-cached warehouse account map. The cached map can be stale within a request (a parent created moments earlier is missing from it), which made get_warehouse_account trigger a full nested-set rebuild_tree and could falsely reject a child whose parent carries a valid account. rebuild_tree enables auto_commit_on_many_writes, which must not run inside a document insert. --- erpnext/stock/doctype/warehouse/warehouse.py | 28 ++++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py index 9451228716e..e92b617600e 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.py +++ b/erpnext/stock/doctype/warehouse/warehouse.py @@ -52,14 +52,6 @@ class Warehouse(NestedSet): self.name = self.warehouse_name - def before_insert(self): - if ( - self.company - and not self.flags.ignore_inventory_account_validation - and frappe.get_cached_value("Company", self.company, "enable_perpetual_inventory") - ): - get_warehouse_account(self, get_warehouse_account_map(self.company)) - def onload(self): """load account name for General Ledger Report""" if self.company and cint(frappe.db.get_value("Company", self.company, "enable_perpetual_inventory")): @@ -70,8 +62,28 @@ class Warehouse(NestedSet): load_address_and_contact(self) def validate(self): + self.validate_inventory_account() self.warn_about_multiple_warehouse_account() + def validate_inventory_account(self): + if ( + not self.is_new() + or not self.company + or self.flags.ignore_inventory_account_validation + or not frappe.get_cached_value("Company", self.company, "enable_perpetual_inventory") + ): + return + + warehouse = frappe._dict(self.as_dict()) + if not self.account and self.parent_warehouse: + parent_bounds = frappe.db.get_value( + "Warehouse", self.parent_warehouse, ["lft", "rgt"], as_dict=True + ) + if parent_bounds: + warehouse.update(parent_bounds) + + get_warehouse_account(warehouse) + def on_update(self): self.update_nsm_model()