From a05ec49062526d75fcb526fc543775e78dcb23d6 Mon Sep 17 00:00:00 2001 From: ervishnucs Date: Wed, 5 Aug 2026 19:00:51 +0530 Subject: [PATCH 1/2] fix(assets): split FIFO/LIFO rate across grouped stock item rows --- .../asset_capitalization.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 14f3f1befec..19532b8bbe5 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -152,6 +152,8 @@ class AssetCapitalization(StockController): if d.meta.has_field(k) and (not d.get(k) or k in force_fields): d.set(k, v) + self.split_valuation_rate_for_grouped_stock_items() + for d in self.asset_items: args = self.as_dict() args.update(d.as_dict()) @@ -173,6 +175,30 @@ class AssetCapitalization(StockController): if d.meta.has_field(k) and (not d.get(k) or k in force_fields): d.set(k, v) + def split_valuation_rate_for_grouped_stock_items(self): + groups = {} + for d in self.stock_items: + if d.item_code and d.warehouse and not (d.serial_no or d.batch_no or d.serial_and_batch_bundle): + groups.setdefault((d.item_code, d.warehouse), []).append(d) + + for rows in groups.values(): + if len(rows) < 2: + continue + + cumulative_qty = 0.0 + prev_cumulative_value = 0.0 + for d in rows: + cumulative_qty += flt(d.stock_qty) + args = self.get_args_for_incoming_rate(d) + args["qty"] = -1 * cumulative_qty + cumulative_rate = flt(get_incoming_rate(args, raise_error_if_no_rate=False)) + cumulative_value = cumulative_rate * cumulative_qty + + row_value = cumulative_value - prev_cumulative_value + d.valuation_rate = flt(row_value / d.stock_qty) if flt(d.stock_qty) else 0.0 + d.amount = flt(flt(d.stock_qty) * d.valuation_rate, d.precision("amount")) + prev_cumulative_value = cumulative_value + def validate_target_item(self): target_item = frappe.get_cached_doc("Item", self.target_item_code) @@ -306,6 +332,8 @@ class AssetCapitalization(StockController): warehouse_details = get_warehouse_details(args) d.update(warehouse_details) + self.split_valuation_rate_for_grouped_stock_items() + @frappe.whitelist() def set_asset_values(self): for d in self.get("asset_items"): From 2cbc5b89d64c4afef35ad64b6f9db176f81a76e9 Mon Sep 17 00:00:00 2001 From: ervishnucs Date: Wed, 5 Aug 2026 19:01:10 +0530 Subject: [PATCH 2/2] test(assets): cover grouped stock item rows splitting FIFO rate --- .../test_asset_capitalization.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py index 933e38098d2..fec8a7c0053 100644 --- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py @@ -397,6 +397,33 @@ class TestAssetCapitalization(ERPNextTestSuite): actual_gle = get_actual_gle_dict(asset_capitalization.name) self.assertEqual(actual_gle, {}) + def test_grouped_stock_item_rows_split_fifo_rate(self): + from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse + + company = "_Test Company" + warehouse = create_warehouse("_Test Warehouse for Grouped FIFO Rows", company=company) + item = create_item( + "_Test Grouped FIFO Rows Item", is_stock_item=1, is_fixed_asset=0, is_purchase_item=1 + ) + target_item = create_fixed_asset_item("_Test Grouped FIFO Rows Target Item") + + make_purchase_receipt(item_code=item.item_code, qty=1, rate=100, company=company, warehouse=warehouse) + make_purchase_receipt(item_code=item.item_code, qty=1, rate=200, company=company, warehouse=warehouse) + + asset_capitalization = frappe.new_doc("Asset Capitalization") + asset_capitalization.company = company + asset_capitalization.target_item_code = target_item.name + asset_capitalization.append( + "stock_items", {"item_code": item.item_code, "warehouse": warehouse, "stock_qty": 1} + ) + asset_capitalization.append( + "stock_items", {"item_code": item.item_code, "warehouse": warehouse, "stock_qty": 1} + ) + asset_capitalization.insert() + + rates = [d.valuation_rate for d in asset_capitalization.stock_items] + self.assertEqual(rates, [100, 200]) + def create_asset_capitalization_data(): create_item("Capitalization Target Stock Item", is_stock_item=1, is_fixed_asset=0, is_purchase_item=0)