fix: do not fetch a random inventory account when multiple inventory accounts exist (backport #57626) (#57631)

* fix: do not fetch a random inventory account when multiple inventory accounts exist (#57626)

(cherry picked from commit 386a4ac1f0)

# Conflicts:
#	erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py

* chore: fix conflicts

Removed redundant test for valuation taxes in purchase receipt.

* fix: build warehouse account map only when perpetual inventory needs it

For asset purchase receipts or provisional accounting with perpetual
inventory disabled, GL entries do not use warehouse accounts. Building
the full warehouse account map in that case now throws when a company
has multiple inventory accounts and no default, breaking asset receipt
submission. Mirrors the gating on develop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: set default inventory account in valuation taxes LCV test

The conflict resolution kept the pre-backport copy of
test_valuation_taxes_lcv_repost_after_billing, which enables perpetual
inventory on _Test Company without configuring a default inventory
account. The test then failed on submit and leaked the perpetual
inventory flag, breaking every stock test that ran after it in the same
process. Restore the cherry-picked version from #57626.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mergify[bot]
2026-07-31 05:11:02 +00:00
committed by GitHub
parent 68c24f3767
commit 972a990b01
6 changed files with 73 additions and 13 deletions

View File

@@ -2802,12 +2802,15 @@ class TestSalesInvoice(FrappeTestCase):
old_perpetual_inventory = erpnext.is_perpetual_inventory_enabled("_Test Company 1")
frappe.local.enable_perpetual_inventory["_Test Company 1"] = 1
old_inventory_account = frappe.db.get_value("Company", "_Test Company 1", "default_inventory_account")
frappe.db.set_value(
"Company",
"_Test Company 1",
"stock_received_but_not_billed",
"Stock Received But Not Billed - _TC1",
{
"stock_received_but_not_billed": "Stock Received But Not Billed - _TC1",
"default_inventory_account": "Stock In Hand - _TC1",
},
)
frappe.db.set_value(
"Company",
@@ -2852,6 +2855,7 @@ class TestSalesInvoice(FrappeTestCase):
# tear down
frappe.local.enable_perpetual_inventory["_Test Company 1"] = old_perpetual_inventory
frappe.db.set_value("Company", "_Test Company 1", "default_inventory_account", old_inventory_account)
frappe.db.set_single_value("Stock Settings", "allow_negative_stock", old_negative_stock)
def test_sle_for_target_warehouse(self):

View File

@@ -177,13 +177,18 @@ class StockController(AccountsController):
)
is_asset_pr = any(d.get("is_fixed_asset") for d in self.get("items"))
need_inventory_map = (self.get_stock_items() or self.get("packed_items")) and cint(
erpnext.is_perpetual_inventory_enabled(self.company)
)
if (
cint(erpnext.is_perpetual_inventory_enabled(self.company))
or provisional_accounting_for_non_stock_items
or is_asset_pr
):
warehouse_account = get_warehouse_account_map(self.company)
warehouse_account = frappe._dict()
if need_inventory_map:
warehouse_account = get_warehouse_account_map(self.company)
if self.docstatus == 1:
if not gl_entries:

View File

@@ -79,10 +79,13 @@ def get_warehouse_account(warehouse, warehouse_account=None):
account = get_company_default_inventory_account(warehouse.company)
if not account and warehouse.company:
account = frappe.db.get_value(
"Account", {"account_type": "Stock", "is_group": 0, "company": warehouse.company}, "name"
inventory_accounts = frappe.get_all(
"Account", {"account_type": "Stock", "is_group": 0, "company": warehouse.company}, pluck="name"
)
if len(inventory_accounts) == 1:
account = inventory_accounts[0]
if not account and warehouse.company and not warehouse.is_group:
frappe.throw(
_("Please set Account in Warehouse {0} or Default Inventory Account in Company {1}").format(

View File

@@ -194,8 +194,10 @@ class TestLandedCostVoucher(FrappeTestCase):
epi = is_perpetual_inventory_enabled(company_a)
company_doc = frappe.get_doc("Company", company_a)
old_inventory_account = company_doc.default_inventory_account
company_doc.enable_perpetual_inventory = 1
company_doc.stock_received_but_not_billed = srbnb
company_doc.default_inventory_account = "Stock In Hand - _TC"
company_doc.save()
pr = make_purchase_receipt(
@@ -223,7 +225,11 @@ class TestLandedCostVoucher(FrappeTestCase):
distribute_landed_cost_on_items(lcv)
lcv.submit()
frappe.db.set_value("Company", company_a, "enable_perpetual_inventory", epi)
frappe.db.set_value(
"Company",
company_a,
{"enable_perpetual_inventory": epi, "default_inventory_account": old_inventory_account},
)
frappe.local.enable_perpetual_inventory = {}
def test_landed_cost_voucher_for_zero_purchase_rate(self):

View File

@@ -3263,11 +3263,14 @@ class TestPurchaseReceipt(FrappeTestCase):
old_perpetual_inventory = erpnext.is_perpetual_inventory_enabled("_Test Company")
frappe.local.enable_perpetual_inventory["_Test Company"] = 1
old_inventory_account = frappe.db.get_value("Company", "_Test Company", "default_inventory_account")
frappe.db.set_value(
"Company",
"_Test Company",
"stock_received_but_not_billed",
"Stock Received But Not Billed - _TC",
{
"stock_received_but_not_billed": "Stock Received But Not Billed - _TC",
"default_inventory_account": "Stock In Hand - _TC",
},
)
pr = make_purchase_receipt(qty=10, rate=1000, do_not_submit=1)
@@ -3296,13 +3299,14 @@ class TestPurchaseReceipt(FrappeTestCase):
gl_entries = get_gl_entries("Purchase Receipt", pr.name, skip_cancelled=True, as_dict=False)
warehouse_account = get_warehouse_account_map("_Test Company")
expected_gle = (
("Stock Received But Not Billed - _TC", 0, 10000, "Main - _TC"),
("Freight and Forwarding Charges - _TC", 0, 2000, "Main - _TC"),
("Expenses Included In Valuation - _TC", 0, 2000, "Main - _TC"),
(warehouse_account[pr.items[0].warehouse]["account"], 14000, 0, "Main - _TC"),
("Stock Received But Not Billed - _TC", 0.0, 10000.0, "Main - _TC"),
("Freight and Forwarding Charges - _TC", 0.0, 2000.0, "Main - _TC"),
("Expenses Included In Valuation - _TC", 0.0, 2000.0, "Main - _TC"),
(warehouse_account[pr.items[0].warehouse]["account"], 14000.0, 0.0, "Main - _TC"),
)
self.assertSequenceEqual(expected_gle, gl_entries)
self.assertCountEqual(expected_gle, gl_entries)
frappe.local.enable_perpetual_inventory["_Test Company"] = old_perpetual_inventory
frappe.db.set_value("Company", "_Test Company", "default_inventory_account", old_inventory_account)
def test_manufacturing_and_expiry_date_for_batch(self):
item = make_item(

View File

@@ -103,6 +103,44 @@ class TestWarehouse(FrappeTestCase):
children = get_children("Warehouse", parent=company, company=company, is_root=True)
self.assertTrue(any(wh["value"] == "_Test Warehouse - _TC" for wh in children))
def test_inventory_account_fallback_with_multiple_stock_accounts(self):
from erpnext.stock import get_warehouse_account
company = create_inventory_fallback_company()
frappe.db.set_value("Company", company, "default_inventory_account", None)
if frappe.db.exists("Account", "Extra Inventory Account - _TCIF"):
frappe.delete_doc("Account", "Extra Inventory Account - _TCIF")
warehouse = frappe.get_doc("Warehouse", {"company": company, "is_group": 0})
single_account = frappe.db.get_value(
"Account", {"account_type": "Stock", "is_group": 0, "company": company}, "name"
)
self.assertEqual(get_warehouse_account(warehouse), single_account)
create_account(
account_name="Extra Inventory Account",
parent_account=frappe.db.get_value("Account", single_account, "parent_account"),
account_type="Stock",
company=company,
)
self.assertRaises(frappe.ValidationError, get_warehouse_account, warehouse)
def create_inventory_fallback_company():
company = "_Test Company Inventory Fallback"
if not frappe.db.exists("Company", company):
frappe.get_doc(
{
"doctype": "Company",
"company_name": company,
"abbr": "_TCIF",
"default_currency": "INR",
"enable_perpetual_inventory": 0,
"country": "India",
}
).insert(ignore_permissions=True)
return company
def create_warehouse(warehouse_name, properties=None, company=None):
if not company: