From 83b32f964667058fafc13de3ed23dbccebe0bc31 Mon Sep 17 00:00:00 2001 From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> Date: Wed, 28 May 2025 17:48:04 +0530 Subject: [PATCH 1/2] fix: correct gl entry when capitalizing composite component --- .../asset_capitalization.py | 91 +++++++++++-------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index bb4081f35d7..6286ace0302 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -13,6 +13,7 @@ import erpnext from erpnext.assets.doctype.asset.asset import get_asset_value_after_depreciation from erpnext.assets.doctype.asset.depreciation import ( depreciate_asset, + get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal, get_value_after_depreciation_on_disposal_date, reset_depreciation_schedule, @@ -441,7 +442,11 @@ class AssetCapitalization(StockController): self.get_gl_entries_for_consumed_asset_items(gl_entries, target_account, target_against, precision) self.get_gl_entries_for_consumed_service_items(gl_entries, target_account, target_against, precision) - self.get_gl_entries_for_target_item(gl_entries, target_account, target_against, precision) + composite_component_value = self.get_composite_component_value() + + self.get_gl_entries_for_target_item( + gl_entries, target_account, target_against, precision, composite_component_value + ) return gl_entries @@ -493,34 +498,34 @@ class AssetCapitalization(StockController): for item in self.asset_items: asset = frappe.get_doc("Asset", item.asset) - if asset.calculate_depreciation: - notes = _( - "This schedule was created when Asset {0} was consumed through Asset Capitalization {1}." - ).format( - get_link_to_form(asset.doctype, asset.name), - get_link_to_form(self.doctype, self.get("name")), - ) - depreciate_asset(asset, self.posting_date, notes) - asset.reload() + if not asset.is_composite_component: + if asset.calculate_depreciation: + notes = _( + "This schedule was created when Asset {0} was consumed through Asset Capitalization {1}." + ).format( + get_link_to_form(asset.doctype, asset.name), + get_link_to_form(self.doctype, self.get("name")), + ) + depreciate_asset(asset, self.posting_date, notes) + asset.reload() - fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( - asset, - item.asset_value, - item.get("finance_book") or self.get("finance_book"), - self.get("doctype"), - self.get("name"), - self.get("posting_date"), - ) + fixed_asset_gl_entries = get_gl_entries_on_asset_disposal( + asset, + item.asset_value, + item.get("finance_book") or self.get("finance_book"), + self.get("doctype"), + self.get("name"), + self.get("posting_date"), + ) + + for gle in fixed_asset_gl_entries: + gle["against"] = target_account + gl_entries.append(self.get_gl_dict(gle, item=item)) + target_against.add(gle["account"]) asset.db_set("disposal_date", self.posting_date) - self.set_consumed_asset_status(asset) - for gle in fixed_asset_gl_entries: - gle["against"] = target_account - gl_entries.append(self.get_gl_dict(gle, item=item)) - target_against.add(gle["account"]) - def get_gl_entries_for_consumed_service_items( self, gl_entries, target_account, target_against, precision ): @@ -543,21 +548,33 @@ class AssetCapitalization(StockController): ) ) - def get_gl_entries_for_target_item(self, gl_entries, target_account, target_against, precision): + def get_composite_component_value(self): + composite_component_value = 0 + for item in self.asset_items: + asset = frappe.db.get_value("Asset", item.asset, ["is_composite_component"], as_dict=True) + if asset and asset.is_composite_component: + composite_component_value += flt(item.asset_value, item.precision("asset_value")) + return composite_component_value + + def get_gl_entries_for_target_item( + self, gl_entries, target_account, target_against, precision, composite_component_value + ): if self.target_is_fixed_asset: - # Capitalization - gl_entries.append( - self.get_gl_dict( - { - "account": target_account, - "against": ", ".join(target_against), - "remarks": self.get("remarks") or _("Accounting Entry for Asset"), - "debit": flt(self.total_value, precision), - "cost_center": self.get("cost_center"), - }, - item=self, + total_value = flt(self.total_value - composite_component_value, precision) + if total_value: + # Capitalization + gl_entries.append( + self.get_gl_dict( + { + "account": target_account, + "against": ", ".join(target_against), + "remarks": self.get("remarks") or _("Accounting Entry for Asset"), + "debit": total_value, + "cost_center": self.get("cost_center"), + }, + item=self, + ) ) - ) def create_target_asset(self): if self.capitalization_method != "Create a new composite asset": From 7d9379461aada0e94f0d6621dbbdc633c481d304 Mon Sep 17 00:00:00 2001 From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> Date: Thu, 29 May 2025 00:15:36 +0530 Subject: [PATCH 2/2] test: composite component --- erpnext/assets/doctype/asset/test_asset.py | 1 + .../test_asset_capitalization.py | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 9e2207367ba..919178d32f3 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -1748,6 +1748,7 @@ def create_asset(**args): "asset_owner": args.asset_owner or "Company", "is_existing_asset": args.is_existing_asset or 1, "is_composite_asset": args.is_composite_asset or 0, + "is_composite_component": args.is_composite_component or 0, "asset_quantity": args.get("asset_quantity") or 1, "depr_entry_posting_status": args.depr_entry_posting_status or "", } diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py index 7cc04cfa5fc..fd55dde9bdb 100644 --- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py @@ -340,6 +340,52 @@ class TestAssetCapitalization(IntegrationTestCase): self.assertFalse(get_actual_gle_dict(asset_capitalization.name)) self.assertFalse(get_actual_sle_dict(asset_capitalization.name)) + def test_capitalize_composite_component(self): + company = "_Test Company with perpetual inventory" + set_depreciation_settings_in_company(company=company) + name = frappe.db.get_value( + "Asset Category Account", + filters={"parent": "Computers", "company_name": company}, + fieldname=["name"], + ) + frappe.db.set_value("Asset Category Account", name, "capital_work_in_progress_account", "") + + wip_composite_asset = create_asset( + asset_name="Asset Capitalization WIP Composite Asset", + is_composite_asset=1, + warehouse="Stores - TCP1", + company=company, + ) + + consumed_asset_value = 100000 + + consumed_asset = create_asset( + asset_name="Asset Capitalization Consumable Asset", + asset_value=consumed_asset_value, + submit=1, + warehouse="Stores - _TC", + is_composite_component=1, + company=company, + ) + + # Create and submit Asset Captitalization + asset_capitalization = create_asset_capitalization( + capitalization_method="Choose a WIP composite asset", + target_asset=wip_composite_asset.name, + target_asset_location="Test Location", + consumed_asset=consumed_asset.name, + company=company, + submit=1, + ) + + # Test Asset Capitalization values + self.assertEqual(asset_capitalization.capitalization_method, "Choose a WIP composite asset") + self.assertEqual(asset_capitalization.target_qty, 1) + self.assertEqual(asset_capitalization.asset_items[0].asset_value, consumed_asset_value) + + actual_gle = get_actual_gle_dict(asset_capitalization.name) + self.assertEqual(actual_gle, {}) + def create_asset_capitalization_data(): create_item("Capitalization Target Stock Item", is_stock_item=1, is_fixed_asset=0, is_purchase_item=0)