From 6c23d5b682ce8e949c6fd18492d2b01fa7a3ad8c Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Tue, 3 Feb 2026 15:38:57 +0530 Subject: [PATCH 01/11] fix(UI): reposition fields for better UX (cherry picked from commit 4e7794bfc323363cd8eb5789be882abd877a0b30) --- erpnext/assets/doctype/asset/asset.json | 24 ++++++++---------------- erpnext/assets/doctype/asset/asset.py | 1 - 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 832f7c18e68..0374a77c7e1 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -10,16 +10,16 @@ "field_order": [ "naming_series", "item_code", - "item_name", "asset_name", "asset_category", "location", "image", "column_break_3", - "status", "company", "asset_owner", "asset_owner_company", + "customer", + "supplier", "is_existing_asset", "is_composite_asset", "is_composite_component", @@ -30,13 +30,13 @@ "purchase_invoice_item", "purchase_date", "available_for_use_date", + "disposal_date", "column_break_23", "net_purchase_amount", "purchase_amount", "asset_quantity", "additional_asset_cost", "total_asset_cost", - "disposal_date", "depreciation_tab", "calculate_depreciation", "column_break_33", @@ -66,12 +66,11 @@ "accounting_dimensions_section", "cost_center", "section_break_jtou", + "status", "custodian", "default_finance_book", "depr_entry_posting_status", "booked_fixed_asset", - "customer", - "supplier", "column_break_51", "department", "split_from", @@ -106,13 +105,6 @@ "options": "Item", "reqd": 1 }, - { - "depends_on": "item_code", - "fetch_from": "item_code.item_name", - "fieldname": "item_name", - "fieldtype": "Read Only", - "label": "Item Name" - }, { "depends_on": "item_code", "fetch_from": "item_code.asset_category", @@ -229,7 +221,7 @@ { "fieldname": "available_for_use_date", "fieldtype": "Date", - "label": "Available-for-use Date", + "label": "Available for Use Date", "mandatory_depends_on": "eval:(!(doc.is_composite_component || doc.is_composite_asset) || doc.docstatus==1)" }, { @@ -257,6 +249,7 @@ "columns": 10, "fieldname": "finance_books", "fieldtype": "Table", + "label": "Finance Books", "options": "Asset Finance Book" }, { @@ -415,8 +408,7 @@ { "depends_on": "calculate_depreciation", "fieldname": "section_break_36", - "fieldtype": "Section Break", - "label": "Finance Books" + "fieldtype": "Section Break" }, { "fieldname": "split_from", @@ -601,7 +593,7 @@ "link_fieldname": "target_asset" } ], - "modified": "2025-12-18 16:36:40.904246", + "modified": "2026-02-03 15:29:21.504376", "modified_by": "Administrator", "module": "Assets", "name": "Asset", diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 42c8e9f9dfa..681ab8534ed 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -81,7 +81,6 @@ class Asset(AccountsController): is_existing_asset: DF.Check is_fully_depreciated: DF.Check item_code: DF.Link - item_name: DF.ReadOnly | None journal_entry_for_scrap: DF.Link | None location: DF.Link maintenance_required: DF.Check From 87a7bc6f49b560fa81a4e44d0296c2f9ba627346 Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Tue, 3 Feb 2026 17:27:11 +0530 Subject: [PATCH 02/11] refactor: use selectbox instead of checkboxes for asset type (cherry picked from commit f7b9221324d262786449a34e42387628caf0f1ce) --- .../accounting_period/accounting_period.py | 2 +- .../purchase_invoice/purchase_invoice.js | 2 +- .../category_wise_asset_value.json | 4 +- .../location_wise_asset_value.json | 4 +- erpnext/assets/dashboard_fixtures.py | 9 ++- erpnext/assets/doctype/asset/asset.js | 20 +++---- erpnext/assets/doctype/asset/asset.json | 55 +++++++------------ erpnext/assets/doctype/asset/asset.py | 40 +++++++------- erpnext/assets/doctype/asset/depreciation.py | 2 +- erpnext/assets/doctype/asset/test_asset.py | 26 ++++----- .../asset_capitalization.js | 2 +- .../asset_capitalization.py | 10 ++-- .../test_asset_capitalization.py | 14 ++--- .../test_asset_depreciation_schedule.py | 16 +++--- .../doctype/asset_repair/test_asset_repair.py | 4 +- .../fixed_asset_register.py | 6 +- 16 files changed, 100 insertions(+), 116 deletions(-) diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py index c4e51d813b2..16a29bf4591 100644 --- a/erpnext/accounts/doctype/accounting_period/accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py @@ -97,7 +97,7 @@ def validate_accounting_period_on_doc_save(doc, method=None): if doc.doctype == "Bank Clearance": return elif doc.doctype == "Asset": - if doc.is_existing_asset: + if doc.asset_type == "Existing Asset": return else: date = doc.available_for_use_date diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index ac214fdac43..e214d2f4416 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -534,7 +534,7 @@ cur_frm.fields_dict["select_print_heading"].get_query = function (doc, cdt, cdn) cur_frm.set_query("wip_composite_asset", "items", function () { return { - filters: { is_composite_asset: 1, docstatus: 0 }, + filters: { asset_type: "Composite Asset", docstatus: 0 }, }; }); diff --git a/erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json b/erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json index 78611da0036..60551560185 100644 --- a/erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json +++ b/erpnext/assets/dashboard_chart/category_wise_asset_value/category_wise_asset_value.json @@ -6,11 +6,11 @@ "docstatus": 0, "doctype": "Dashboard Chart", "dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_date\":\"frappe.datetime.add_months(frappe.datetime.nowdate(), -12)\",\"to_date\":\"frappe.datetime.nowdate()\"}", - "filters_json": "{\"status\":\"In Location\",\"group_by\":\"Asset Category\",\"is_existing_asset\":0}", + "filters_json": "{\"status\":\"In Location\",\"group_by\":\"Asset Category\",\"asset_type\":[\"!=\",\"Existing Asset\"]}", "idx": 0, "is_public": 1, "is_standard": 1, - "modified": "2020-10-28 23:16:16.939070", + "modified": "2026-02-03 15:48:13.407835", "modified_by": "Administrator", "module": "Assets", "name": "Category-wise Asset Value", diff --git a/erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json b/erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json index 848184cc148..3f89d987ba0 100644 --- a/erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json +++ b/erpnext/assets/dashboard_chart/location_wise_asset_value/location_wise_asset_value.json @@ -6,11 +6,11 @@ "docstatus": 0, "doctype": "Dashboard Chart", "dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_date\":\"frappe.datetime.add_months(frappe.datetime.nowdate(), -12)\",\"to_date\":\"frappe.datetime.nowdate()\"}", - "filters_json": "{\"status\":\"In Location\",\"group_by\":\"Location\",\"is_existing_asset\":0}", + "filters_json": "{\"status\":\"In Location\",\"group_by\":\"Location\",\"asset_type\":[\"!=\",\"Existing Asset\"]}", "idx": 0, "is_public": 1, "is_standard": 1, - "modified": "2020-10-28 23:16:07.883312", + "modified": "2026-02-03 15:48:13.407835", "modified_by": "Administrator", "module": "Assets", "name": "Location-wise Asset Value", diff --git a/erpnext/assets/dashboard_fixtures.py b/erpnext/assets/dashboard_fixtures.py index 3b1d14440cf..0fd6c019f36 100644 --- a/erpnext/assets/dashboard_fixtures.py +++ b/erpnext/assets/dashboard_fixtures.py @@ -100,7 +100,7 @@ def get_charts(fiscal_year, year_start_date, year_end_date): "company": company, "status": "In Location", "group_by": "Asset Category", - "is_existing_asset": 0, + "asset_type": ["!=", "Existing Asset"], } ), "type": "Donut", @@ -126,7 +126,12 @@ def get_charts(fiscal_year, year_start_date, year_end_date): "x_field": "location", "timeseries": 0, "filters_json": json.dumps( - {"company": company, "status": "In Location", "group_by": "Location", "is_existing_asset": 0} + { + "company": company, + "status": "In Location", + "group_by": "Location", + "asset_type": ["!=", "Existing Asset"], + } ), "type": "Donut", "doctype": "Dashboard Chart", diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 28add7cb35d..2b5ea8caa8c 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -81,13 +81,13 @@ frappe.ui.form.on("Asset", { }, before_submit: function (frm) { - if (frm.doc.is_composite_asset && !frm.has_active_capitalization) { + if (frm.doc.asset_type == "Composite Asset" && !frm.has_active_capitalization) { frappe.throw(__("Please capitalize this asset before submitting.")); } }, refresh: function (frm) { - frappe.ui.form.trigger("Asset", "is_existing_asset"); + frappe.ui.form.trigger("Asset", "asset_type"); frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1); if (frm.doc.docstatus == 1) { @@ -167,7 +167,7 @@ frappe.ui.form.on("Asset", { ); } - if (frm.doc.purchase_receipt || !frm.doc.is_existing_asset) { + if (frm.doc.purchase_receipt || !frm.doc.asset_type == "Existing Asset") { frm.add_custom_button( __("View General Ledger"), function () { @@ -195,7 +195,7 @@ frappe.ui.form.on("Asset", { if (frm.doc.docstatus == 0) { frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation); - if (frm.doc.is_composite_asset) { + if (frm.doc.asset_type == "Composite Asset") { frappe.call({ method: "erpnext.assets.doctype.asset.asset.has_active_capitalization", args: { @@ -232,7 +232,8 @@ frappe.ui.form.on("Asset", { toggle_reference_doc: function (frm) { const is_submitted = frm.doc.docstatus === 1; - const is_special_asset = frm.doc.is_existing_asset || frm.doc.is_composite_asset; + const is_special_asset = + frm.doc.asset_type == "Existing Asset" || frm.doc.asset_type == "Composite Asset"; const clear_field = (field) => { if (frm.doc[field]) { @@ -508,18 +509,13 @@ frappe.ui.form.on("Asset", { }); }, - is_existing_asset: function (frm) { - frm.trigger("toggle_reference_doc"); - }, - - is_composite_asset: function (frm) { + asset_type: function (frm) { if (frm.doc.docstatus == 0) { - if (frm.doc.is_composite_asset) { + if (frm.doc.asset_type == "Composite Asset") { frm.set_value("net_purchase_amount", 0); } else { frm.set_df_property("net_purchase_amount", "read_only", 0); } - frm.trigger("toggle_reference_doc"); } }, diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 0374a77c7e1..b97a5d2d1f7 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -20,9 +20,7 @@ "asset_owner_company", "customer", "supplier", - "is_existing_asset", - "is_composite_asset", - "is_composite_component", + "asset_type", "purchase_details_section", "purchase_receipt", "purchase_receipt_item", @@ -199,7 +197,7 @@ "fieldname": "purchase_date", "fieldtype": "Date", "label": "Purchase Date", - "read_only_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset", + "read_only_depends_on": "eval:doc.asset_type != \"Existing Asset\" && doc.asset_type != \"Composite Asset\"", "reqd": 1 }, { @@ -222,24 +220,17 @@ "fieldname": "available_for_use_date", "fieldtype": "Date", "label": "Available for Use Date", - "mandatory_depends_on": "eval:(!(doc.is_composite_component || doc.is_composite_asset) || doc.docstatus==1)" + "mandatory_depends_on": "eval:(!(doc.asset_type == \"Composite Component\" || doc.asset_type == \"Composite Asset\") || doc.docstatus==1)" }, { "default": "0", "fieldname": "calculate_depreciation", "fieldtype": "Check", "label": "Calculate Depreciation", - "read_only_depends_on": "eval:(doc.is_composite_asset && !doc.net_purchase_amount) || doc.is_composite_component" + "read_only_depends_on": "eval:(doc.asset_type == \"Composite Asset\" && !doc.net_purchase_amount) || doc.asset_type == \"Composite Component\"" }, { - "default": "0", - "depends_on": "eval:(!doc.is_composite_asset && !doc.is_composite_component)", - "fieldname": "is_existing_asset", - "fieldtype": "Check", - "label": "Is Existing Asset" - }, - { - "depends_on": "eval:(doc.is_existing_asset)", + "depends_on": "eval:(doc.asset_type == \"Existing Asset\")", "fieldname": "opening_accumulated_depreciation", "fieldtype": "Currency", "label": "Opening Accumulated Depreciation", @@ -357,7 +348,7 @@ "fieldtype": "Column Break" }, { - "depends_on": "eval:!doc.is_composite_asset && !doc.is_existing_asset", + "depends_on": "eval:doc.asset_type != \"Composite Asset\" && doc.asset_type != \"Existing Asset\"", "fieldname": "purchase_receipt", "fieldtype": "Link", "label": "Purchase Receipt", @@ -366,7 +357,7 @@ "print_hide": 1 }, { - "depends_on": "eval:!doc.is_composite_asset && !doc.is_existing_asset", + "depends_on": "eval:doc.asset_type != \"Composite Asset\" && doc.asset_type != \"Existing Asset\"", "fieldname": "purchase_invoice", "fieldtype": "Link", "label": "Purchase Invoice", @@ -392,7 +383,7 @@ "read_only": 1 }, { - "collapsible_depends_on": "is_existing_asset", + "collapsible_depends_on": "eval:doc.asset_type == \"Existing Asset\"", "fieldname": "purchase_details_section", "fieldtype": "Section Break", "label": "Purchase Details" @@ -447,18 +438,11 @@ }, { "default": "0", - "depends_on": "eval:(doc.is_existing_asset)", + "depends_on": "eval:(doc.asset_type == \"Existing Asset\")", "fieldname": "is_fully_depreciated", "fieldtype": "Check", "label": "Is Fully Depreciated" }, - { - "default": "0", - "depends_on": "eval:(!doc.is_existing_asset && !doc.is_composite_component)", - "fieldname": "is_composite_asset", - "fieldtype": "Check", - "label": "Is Composite Asset" - }, { "depends_on": "eval:doc.docstatus > 0", "fieldname": "total_asset_cost", @@ -488,7 +472,7 @@ "read_only": 1 }, { - "depends_on": "eval:(doc.is_existing_asset)", + "depends_on": "eval:(doc.asset_type == \"Existing Asset\")", "fieldname": "opening_number_of_booked_depreciations", "fieldtype": "Int", "label": "Opening Number of Booked Depreciations" @@ -536,20 +520,19 @@ "fieldtype": "Section Break", "label": "Additional Info" }, - { - "default": "0", - "depends_on": "eval:(!doc.is_existing_asset && !doc.is_composite_asset)", - "fieldname": "is_composite_component", - "fieldtype": "Check", - "label": "Is Composite Component" - }, { "fieldname": "net_purchase_amount", "fieldtype": "Currency", "label": "Net Purchase Amount", - "mandatory_depends_on": "eval:(!doc.is_composite_asset || doc.docstatus==1)", + "mandatory_depends_on": "eval:(doc.asset_type != \"Composite Asset\" || doc.docstatus==1)", "options": "Company:company:default_currency", - "read_only_depends_on": "eval: doc.is_composite_asset" + "read_only_depends_on": "eval: doc.asset_type == \"Composite Asset\"" + }, + { + "fieldname": "asset_type", + "fieldtype": "Select", + "label": "Asset Type", + "options": "\nExisting Asset\nComposite Asset\nComposite Component" } ], "idx": 72, @@ -593,7 +576,7 @@ "link_fieldname": "target_asset" } ], - "modified": "2026-02-03 15:29:21.504376", + "modified": "2026-02-03 15:48:13.407835", "modified_by": "Administrator", "module": "Assets", "name": "Asset", diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 681ab8534ed..bbc4ed23824 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -56,6 +56,7 @@ class Asset(AccountsController): asset_owner: DF.Literal["", "Company", "Supplier", "Customer"] asset_owner_company: DF.Link | None asset_quantity: DF.Int + asset_type: DF.Literal["", "Existing Asset", "Composite Asset", "Composite Component"] available_for_use_date: DF.Date | None booked_fixed_asset: DF.Check calculate_depreciation: DF.Check @@ -76,9 +77,6 @@ class Asset(AccountsController): insurance_start_date: DF.Date | None insured_value: DF.Data | None insurer: DF.Data | None - is_composite_asset: DF.Check - is_composite_component: DF.Check - is_existing_asset: DF.Check is_fully_depreciated: DF.Check item_code: DF.Link journal_entry_for_scrap: DF.Link | None @@ -242,7 +240,7 @@ class Asset(AccountsController): self.set_total_booked_depreciations() def before_submit(self): - if self.is_composite_asset and not has_active_capitalization(self.name): + if self.asset_type == "Composite Asset" and not has_active_capitalization(self.name): if self.split_from and has_active_capitalization(self.split_from): return frappe.throw(_("Please capitalize this asset before submitting.")) @@ -251,7 +249,11 @@ class Asset(AccountsController): self.validate_in_use_date() self.make_asset_movement() self.reload() - if not self.booked_fixed_asset and not self.is_composite_component and self.validate_make_gl_entry(): + if ( + not self.booked_fixed_asset + and self.asset_type == "Composite Component" + and self.validate_make_gl_entry() + ): self.make_gl_entries() if self.calculate_depreciation and not self.split_from: convert_draft_asset_depr_schedules_into_active(self) @@ -266,7 +268,7 @@ class Asset(AccountsController): cancel_asset_depr_schedules(self) self.set_status() self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry") - if not self.is_composite_component: + if self.asset_type != "Composite Component": make_reverse_gl_entries(voucher_type="Asset", voucher_no=self.name) self.db_set("booked_fixed_asset", 0) add_asset_activity(self.name, _("Asset cancelled")) @@ -284,7 +286,7 @@ class Asset(AccountsController): add_asset_activity(self.name, _("Asset deleted")) def set_purchase_doc_row_item(self): - if self.is_existing_asset or self.is_composite_asset: + if self.asset_type == "Existing Asset" or self.asset_type == "Composite Asset": return self.purchase_amount = self.net_purchase_amount @@ -327,7 +329,7 @@ class Asset(AccountsController): ) ) - if self.is_existing_asset and self.purchase_invoice: + if self.asset_type == "Existing Asset" and self.purchase_invoice: frappe.throw(_("Purchase Invoice cannot be made against an existing asset {0}").format(self.name)) def validate_item(self): @@ -373,7 +375,7 @@ class Asset(AccountsController): ) def validate_in_use_date(self): - if not self.available_for_use_date and not self.is_composite_component: + if not self.available_for_use_date and self.asset_type != "Composite Component": frappe.throw(_("Available for use date is required")) for d in self.finance_books: @@ -441,13 +443,13 @@ class Asset(AccountsController): if not self.asset_category: self.asset_category = frappe.get_cached_value("Item", self.item_code, "asset_category") - if not flt(self.net_purchase_amount) and not self.is_composite_asset: + if not flt(self.net_purchase_amount) and self.asset_type != "Composite Asset": frappe.throw(_("Net Purchase Amount is mandatory"), frappe.MandatoryError) if is_cwip_accounting_enabled(self.asset_category): if ( - not self.is_existing_asset - and not self.is_composite_asset + not self.asset_type == "Existing Asset" + and not self.asset_type == "Composite Asset" and not self.purchase_receipt and not self.purchase_invoice ): @@ -476,7 +478,7 @@ class Asset(AccountsController): if self.is_fully_depreciated: frappe.throw(_("Depreciation cannot be calculated for fully depreciated assets")) - if self.is_existing_asset: + if self.asset_type == "Existing Asset": return if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date): @@ -548,7 +550,7 @@ class Asset(AccountsController): ) def validate_gross_and_purchase_amount(self): - if self.is_existing_asset: + if self.asset_type == "Existing Asset": return if self.net_purchase_amount and self.net_purchase_amount != self.purchase_amount: @@ -616,7 +618,7 @@ class Asset(AccountsController): self.validate_depreciation_start_date(row) self.validate_total_number_of_depreciations_and_frequency(row) - if not self.is_existing_asset: + if self.asset_type != "Existing Asset": self.opening_accumulated_depreciation = 0 self.opening_number_of_booked_depreciations = 0 else: @@ -769,7 +771,7 @@ class Asset(AccountsController): def get_status(self): """Returns status based on whether it is draft, submitted, scrapped or depreciated""" if self.docstatus == 0: - if self.is_composite_asset: + if self.asset_type == "Composite Asset": status = "Work In Progress" else: status = "Draft" @@ -842,7 +844,7 @@ class Asset(AccountsController): return records def validate_make_gl_entry(self): - if self.is_composite_asset: + if self.asset_type == "Composite Asset": return True purchase_document = self.get_purchase_document() @@ -923,7 +925,7 @@ class Asset(AccountsController): purchase_document = self.get_purchase_document() fixed_asset_account, cwip_account = self.get_fixed_asset_account(), self.get_cwip_account() - if (self.is_composite_asset or (purchase_document and self.purchase_amount)) and getdate( + if (self.asset_type == "Composite Asset" or (purchase_document and self.purchase_amount)) and getdate( self.available_for_use_date ) <= getdate(): gl_entries.append( @@ -963,7 +965,7 @@ class Asset(AccountsController): self.db_set("booked_fixed_asset", 1) def check_asset_capitalization_gl_entries(self): - if self.is_composite_asset: + if self.asset_type == "Composite Asset": result = frappe.db.get_value( "Asset Capitalization", {"target_asset": self.name, "docstatus": 1}, diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 1e0cfedfbb9..c2bc885202d 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -789,7 +789,7 @@ def get_disposal_account_and_cost_center(company): def get_value_after_depreciation_on_disposal_date(asset, disposal_date, finance_book=None): asset_doc = frappe.get_doc("Asset", asset) - if asset_doc.is_composite_component: + if asset_doc.asset_type == "Composite Component": validate_disposal_date(asset_doc.purchase_date, getdate(disposal_date), "purchase") return flt(asset_doc.value_after_depreciation) diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 6733a7f89e3..a71c3826d23 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -71,16 +71,16 @@ class TestAsset(AssetSetup): self.assertRaises(frappe.MandatoryError, asset.save) def test_pr_or_pi_mandatory_if_not_existing_asset(self): - """Tests if either PI or PR is present if CWIP is enabled and is_existing_asset=0.""" + """Tests if either PI or PR is present if CWIP is enabled and asset_type == Existing Asset.""" asset = create_asset(item_code="Macbook Pro", do_not_save=1) - asset.is_existing_asset = 0 + asset.asset_type = "" self.assertRaises(frappe.ValidationError, asset.save) def test_available_for_use_date_is_after_purchase_date(self): asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1, do_not_save=1) - asset.is_existing_asset = 0 + asset.asset_type = "" asset.purchase_date = getdate("2021-10-10") asset.available_for_use_date = getdate("2021-10-1") @@ -183,7 +183,7 @@ class TestAsset(AssetSetup): asset.submit() def test_is_fixed_asset_set(self): - asset = create_asset(is_existing_asset=1) + asset = create_asset(asset_type="Existing Asset") doc = frappe.new_doc("Purchase Invoice") doc.company = "_Test Company" doc.supplier = "_Test Supplier" @@ -710,7 +710,7 @@ class TestAsset(AssetSetup): # create an asset asset = create_asset( item_code="Macbook Pro", - is_existing_asset=1, + asset_type="Existing Asset", calculate_depreciation=1, available_for_use_date=purchase_date, purchase_date=purchase_date, @@ -890,7 +890,7 @@ class TestDepreciationMethods(AssetSetup): asset = create_asset( calculate_depreciation=1, available_for_use_date="2030-06-06", - is_existing_asset=1, + asset_type="Existing Asset", opening_number_of_booked_depreciations=2, opening_accumulated_depreciation=47178.08, expected_value_after_useful_life=10000, @@ -939,7 +939,7 @@ class TestDepreciationMethods(AssetSetup): asset = create_asset( calculate_depreciation=1, available_for_use_date="2030-01-01", - is_existing_asset=1, + asset_type="Existing Asset", depreciation_method="Double Declining Balance", opening_number_of_booked_depreciations=1, opening_accumulated_depreciation=50000, @@ -1680,7 +1680,7 @@ class TestDepreciationBasics(AssetSetup): self.assertEqual(asset.finance_books[0].value_after_depreciation, 100000.0) def test_asset_cost_center(self): - asset = create_asset(is_existing_asset=1, do_not_save=1) + asset = create_asset(asset_type="Existing Asset", do_not_save=1) asset.cost_center = "Main - WP" self.assertRaises(frappe.ValidationError, asset.submit) @@ -1717,7 +1717,7 @@ class TestDepreciationBasics(AssetSetup): def test_manual_depreciation_for_existing_asset(self): asset = create_asset( item_code="Macbook Pro", - is_existing_asset=1, + asset_type="Existing Asset", purchase_date="2020-01-30", available_for_use_date="2020-01-30", submit=1, @@ -1843,7 +1843,7 @@ class TestDepreciationBasics(AssetSetup): # Create composite asset wip_composite_asset = create_asset( asset_name="Asset Capitalization WIP Composite Asset for Split", - is_composite_asset=1, + asset_type="Composite Asset", warehouse="Stores - TCP1", company=company, asset_quantity=2, # Set quantity > 1 to allow splitting @@ -1937,9 +1937,7 @@ def create_asset(**args): "available_for_use_date": args.available_for_use_date or "2020-06-06", "location": args.location or "Test Location", "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_type": args.asset_type or "", "asset_quantity": args.get("asset_quantity") or 1, "depr_entry_posting_status": args.depr_entry_posting_status or "", } @@ -1961,7 +1959,7 @@ def create_asset(**args): }, ) - if asset.is_composite_asset: + if asset.asset_type == "Composite Asset": asset.net_purchase_amount = 0 asset.purchase_amount = 0 diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js index 3857f6411f5..c5db736669f 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js @@ -41,7 +41,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s me.frm.set_query("target_asset", function () { return { - filters: { is_composite_asset: 1, docstatus: 0 }, + filters: { asset_type: "Composite Asset", docstatus: 0 }, }; }); diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 7b9369d7390..8f092489b2b 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -205,7 +205,7 @@ class AssetCapitalization(StockController): if self.target_asset: target_asset = self.get_asset_for_validation(self.target_asset) - if not target_asset.is_composite_asset: + if not target_asset.asset_type == "Composite Asset": frappe.throw(_("Target Asset {0} needs to be composite asset").format(target_asset.name)) if target_asset.item_code != self.target_item_code: @@ -314,7 +314,7 @@ class AssetCapitalization(StockController): return frappe.db.get_value( "Asset", asset, - ["name", "item_code", "company", "status", "docstatus", "is_composite_asset"], + ["name", "item_code", "company", "status", "docstatus", "asset_type"], as_dict=1, ) @@ -489,7 +489,7 @@ class AssetCapitalization(StockController): for item in self.asset_items: asset = frappe.get_doc("Asset", item.asset) - if not asset.is_composite_component: + if asset.asset_type != "Composite Component": if asset.calculate_depreciation: notes = _( "This schedule was created when Asset {0} was consumed through Asset Capitalization {1}." @@ -542,8 +542,8 @@ class AssetCapitalization(StockController): 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: + asset = frappe.db.get_value("Asset", item.asset, ["asset_type"], as_dict=True) + if asset and asset.asset_type == "Composite Component": composite_component_value += flt(item.asset_value, item.precision("asset_value")) return composite_component_value diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py index c87fff0b73e..853e5cac3af 100644 --- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py @@ -61,7 +61,7 @@ class TestAssetCapitalization(IntegrationTestCase): wip_composite_asset = create_asset( asset_name="Asset Capitalization WIP Composite Asset", - is_composite_asset=1, + asset_type="Composite Asset", warehouse="Stores - TCP1", company=company, ) @@ -156,7 +156,7 @@ class TestAssetCapitalization(IntegrationTestCase): wip_composite_asset = create_asset( asset_name="Asset Capitalization WIP Composite Asset", - is_composite_asset=1, + asset_type="Composite Asset", warehouse="Stores - TCP1", company=company, ) @@ -245,7 +245,7 @@ class TestAssetCapitalization(IntegrationTestCase): wip_composite_asset = create_asset( asset_name="Asset Capitalization WIP Composite Asset", - is_composite_asset=1, + asset_type="Composite Asset", warehouse="Stores - TCP1", company=company, ) @@ -313,7 +313,7 @@ class TestAssetCapitalization(IntegrationTestCase): wip_composite_asset = create_asset( asset_name="Asset Capitalization WIP Composite Asset", - is_composite_asset=1, + asset_type="Composite Asset", warehouse="Stores - TCP1", company=company, ) @@ -361,7 +361,7 @@ class TestAssetCapitalization(IntegrationTestCase): wip_composite_asset = create_asset( asset_name="Asset Capitalization WIP Composite Asset", - is_composite_asset=1, + asset_type="Composite Asset", warehouse="Stores - TCP1", company=company, ) @@ -373,7 +373,7 @@ class TestAssetCapitalization(IntegrationTestCase): asset_value=consumed_asset_value, submit=1, warehouse="Stores - _TC", - is_composite_component=1, + asset_type="Composite Component", company=company, ) @@ -516,7 +516,7 @@ def create_depreciation_asset(**args): args = frappe._dict(args) asset = frappe.new_doc("Asset") - asset.is_existing_asset = 1 + asset.asset_type = args.asset_type or "Existing Asset" asset.calculate_depreciation = 1 asset.asset_owner = "Company" diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py index 2cca15a89f7..824c7cbba1f 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py @@ -87,7 +87,7 @@ class TestAssetDepreciationSchedule(IntegrationTestCase): calculate_depreciation=1, depreciation_method="Straight Line", available_for_use_date="2023-10-10", - is_existing_asset=1, + asset_type="Existing Asset", opening_number_of_booked_depreciations=9, opening_accumulated_depreciation=265, depreciation_start_date="2024-07-31", @@ -127,7 +127,7 @@ class TestAssetDepreciationSchedule(IntegrationTestCase): calculate_depreciation=1, depreciation_method="Straight Line", available_for_use_date="2023-10-10", - is_existing_asset=1, + asset_type="Existing Asset", opening_number_of_booked_depreciations=9, opening_accumulated_depreciation=265.30, depreciation_start_date="2024-07-31", @@ -165,7 +165,7 @@ class TestAssetDepreciationSchedule(IntegrationTestCase): calculate_depreciation=1, depreciation_method="Straight Line", available_for_use_date="2023-11-01", - is_existing_asset=1, + asset_type="Existing Asset", opening_number_of_booked_depreciations=4, opening_accumulated_depreciation=223.15, depreciation_start_date="2024-12-31", @@ -529,7 +529,7 @@ class TestAssetDepreciationSchedule(IntegrationTestCase): depreciation_start_date="2023-03-31", frequency_of_depreciation=1, total_number_of_depreciations=12, - is_existing_asset=1, + asset_type="Existing Asset", opening_accumulated_depreciation=64.52, opening_number_of_booked_depreciations=2, submit=1, @@ -851,7 +851,7 @@ class TestAssetDepreciationSchedule(IntegrationTestCase): depreciation_start_date="2023-03-31", frequency_of_depreciation=1, total_number_of_depreciations=12, - is_existing_asset=1, + asset_type="Existing Asset", opening_accumulated_depreciation=64.52, opening_number_of_booked_depreciations=2, submit=1, @@ -925,7 +925,7 @@ class TestAssetDepreciationSchedule(IntegrationTestCase): depreciation_start_date="2021-12-31", frequency_of_depreciation=12, total_number_of_depreciations=3, - is_existing_asset=1, + asset_type="Existing Asset", submit=1, ) post_depreciation_entries(date="2021-12-31") @@ -1014,7 +1014,7 @@ class TestAssetDepreciationSchedule(IntegrationTestCase): depreciation_start_date="2021-12-31", frequency_of_depreciation=12, total_number_of_depreciations=3, - is_existing_asset=1, + asset_type="Existing Asset", submit=1, ) post_depreciation_entries(date="2021-12-31") @@ -1093,7 +1093,7 @@ class TestAssetDepreciationSchedule(IntegrationTestCase): rate_of_depreciation=50, frequency_of_depreciation=12, total_number_of_depreciations=3, - is_existing_asset=1, + asset_type="Existing Asset", submit=1, ) post_depreciation_entries(date="2021-12-31") diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py index d085a4c6e4b..c56622d6665 100644 --- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py @@ -360,7 +360,7 @@ class TestAssetRepair(IntegrationTestCase): self.assertEqual(stock_entry.asset_repair, asset_repair.name) def test_gl_entries_with_capitalized_asset_repair(self): - asset = create_asset(is_existing_asset=1, calculate_depreciation=1, submit=1) + asset = create_asset(asset_type="Existing Asset", calculate_depreciation=1, submit=1) asset_repair = create_asset_repair( asset=asset, capitalize_repair_cost=1, item="_Test Non Stock Item", submit=1 ) @@ -400,7 +400,7 @@ def create_asset_repair(**args): if args.asset: asset = args.asset else: - asset = create_asset(is_existing_asset=1, submit=1, company=args.company) + asset = create_asset(asset_type=args.asset_type or "Existing Asset", submit=1, company=args.company) asset_repair = frappe.new_doc("Asset Repair") asset_repair.update( { diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py index 2103379df93..44bf59fc3ea 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py @@ -144,7 +144,7 @@ def get_conditions(filters): conditions[date_field] = ["between", [filters.year_start_date, filters.year_end_date]] if filters.get("only_existing_assets"): - conditions["is_existing_asset"] = filters.get("only_existing_assets") + conditions["asset_type"] = "Existing Asset" if filters.get("asset_category"): conditions["asset_category"] = filters.get("asset_category") if filters.get("cost_center"): @@ -274,7 +274,7 @@ def get_asset_depreciation_amount_map(filters, finance_book): ) if filters.only_existing_assets: - query = query.where(asset.is_existing_asset == 1) + query = query.where(asset.asset_type == "Existing Asset") if filters.asset_category: query = query.where(asset.asset_category == filters.asset_category) if filters.cost_center: @@ -325,7 +325,7 @@ def get_asset_value_adjustment_map(filters, finance_book): ) if filters.only_existing_assets: - query = query.where(asset.is_existing_asset == 1) + query = query.where(asset.asset_type == "Existing Asset") if filters.asset_category: query = query.where(asset.asset_category == filters.asset_category) if filters.cost_center: From 4d0e28a6083a1d913e2502839cd2cdfcf947b2c5 Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Tue, 3 Feb 2026 23:44:07 +0530 Subject: [PATCH 03/11] fix: patch to migrate checkbox data into select (cherry picked from commit c36fa5bdb69183784bef2faab2a2bc04d128e019) --- erpnext/patches.txt | 1 + .../migrate_asset_type_checkboxes_to_select.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 erpnext/patches/v16_0/migrate_asset_type_checkboxes_to_select.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 3c59e1ff550..0a5141a6eec 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -468,3 +468,4 @@ erpnext.patches.v15_0.replace_http_with_https_in_sales_partner erpnext.patches.v15_0.delete_quotation_lost_record_detail erpnext.patches.v16_0.add_portal_redirects erpnext.patches.v16_0.complete_onboarding_steps_for_older_sites #2 +erpnext.patches.v16_0.migrate_asset_type_checkboxes_to_select diff --git a/erpnext/patches/v16_0/migrate_asset_type_checkboxes_to_select.py b/erpnext/patches/v16_0/migrate_asset_type_checkboxes_to_select.py new file mode 100644 index 00000000000..868d53b8985 --- /dev/null +++ b/erpnext/patches/v16_0/migrate_asset_type_checkboxes_to_select.py @@ -0,0 +1,15 @@ +import frappe +from frappe.query_builder import Case + + +def execute(): + Asset = frappe.qb.DocType("Asset") + + frappe.qb.update(Asset).set( + Asset.asset_type, + Case() + .when(Asset.is_existing_asset == 1, "Existing Asset") + .when(Asset.is_composite_asset == 1, "Composite Asset") + .when(Asset.is_composite_component == 1, "Composite Component") + .else_(""), + ).run() From 78074c0cdd479e0e9a0a20447df0f3e0864e20df Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Thu, 5 Feb 2026 12:50:24 +0530 Subject: [PATCH 04/11] fix(UI): improve asset action buttons group (cherry picked from commit e90a3b5a56c0ad7dac814e82343a638dd4c50330) --- erpnext/assets/doctype/asset/asset.js | 114 +++++++++++++++--------- erpnext/assets/doctype/asset/asset.json | 109 +++++++++++++++------- erpnext/assets/doctype/asset/asset.py | 5 +- 3 files changed, 154 insertions(+), 74 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 2b5ea8caa8c..6dc0a6c8dc4 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -86,47 +86,44 @@ frappe.ui.form.on("Asset", { } }, - refresh: function (frm) { + refresh: async function (frm) { frappe.ui.form.trigger("Asset", "asset_type"); frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1); + let has_create_buttons = false; if (frm.doc.docstatus == 1) { - if (["Submitted", "Partially Depreciated", "Fully Depreciated"].includes(frm.doc.status)) { + if (["Submitted", "Partially Depreciated"].includes(frm.doc.status)) { frm.add_custom_button( - __("Transfer Asset"), + __("Asset Value Adjustment"), function () { - erpnext.asset.transfer_asset(frm); + frm.trigger("create_asset_value_adjustment"); }, - __("Manage") + __("Create") ); frm.add_custom_button( - __("Scrap Asset"), + __("Asset Repair"), function () { - erpnext.asset.scrap_asset(frm); + frm.trigger("create_asset_repair"); }, - __("Manage") + __("Create") ); + has_create_buttons = true; + } + if (!frm.doc.calculate_depreciation) { frm.add_custom_button( - __("Sell Asset"), + __("Depreciation Entry"), function () { - frm.trigger("sell_asset"); + frm.trigger("make_journal_entry"); }, - __("Manage") + __("Create") ); + has_create_buttons = true; + } - frm.add_custom_button( - __("Split Asset"), - function () { - frm.trigger("split_asset"); - }, - __("Manage") - ); - } else if (frm.doc.status == "Scrapped") { - frm.add_custom_button(__("Restore Asset"), function () { - erpnext.asset.restore_asset(frm); - }).addClass("btn-primary"); + if (has_create_buttons) { + cur_frm.page.set_inner_btn_group_as_primary(__("Create")); } if (frm.doc.maintenance_required && !frm.doc.maintenance_schedule) { @@ -135,41 +132,51 @@ frappe.ui.form.on("Asset", { function () { frm.trigger("create_asset_maintenance"); }, - __("Manage") + __("Actions") ); } - if (["Submitted", "Partially Depreciated"].includes(frm.doc.status)) { + if (["Submitted", "Partially Depreciated", "Fully Depreciated"].includes(frm.doc.status)) { frm.add_custom_button( - __("Adjust Asset Value"), + __("Split Asset"), function () { - frm.trigger("create_asset_value_adjustment"); + frm.trigger("split_asset"); }, - __("Manage") + __("Actions") ); frm.add_custom_button( - __("Repair Asset"), + __("Transfer Asset"), function () { - frm.trigger("create_asset_repair"); + erpnext.asset.transfer_asset(frm); }, - __("Manage") + __("Actions") ); + + frm.add_custom_button( + __("Scrap Asset"), + function () { + erpnext.asset.scrap_asset(frm); + }, + __("Actions") + ); + + frm.add_custom_button( + __("Sell Asset"), + function () { + frm.trigger("sell_asset"); + }, + __("Actions") + ); + } else if (frm.doc.status == "Scrapped") { + frm.add_custom_button(__("Restore Asset"), function () { + erpnext.asset.restore_asset(frm); + }).addClass("btn-primary"); } - if (!frm.doc.calculate_depreciation) { + if (await frm.events.should_show_accounting_ledger(frm)) { frm.add_custom_button( - __("Create Depreciation Entry"), - function () { - frm.trigger("make_journal_entry"); - }, - __("Manage") - ); - } - - if (frm.doc.purchase_receipt || !frm.doc.asset_type == "Existing Asset") { - frm.add_custom_button( - __("View General Ledger"), + __("Accounting Ledger"), function () { frappe.route_options = { voucher_no: frm.doc.name, @@ -179,7 +186,7 @@ frappe.ui.form.on("Asset", { }; frappe.set_route("query-report", "General Ledger"); }, - __("Manage") + __("View") ); } @@ -217,6 +224,27 @@ frappe.ui.form.on("Asset", { } }, + should_show_accounting_ledger: async function (frm) { + if (["Capitalized"].includes(frm.doc.status)) { + return false; + } + + if ( + !frm.doc.purchase_receipt && + ["Existing Asset", "Composite Component"].includes(frm.doc.asset_type) + ) { + return false; + } + + const asset_category = await frappe.db.get_value( + "Asset Category", + frm.doc.asset_category, + "enable_cwip_accounting" + ); + + return !!asset_category.message?.enable_cwip_accounting; + }, + set_depr_posting_failure_alert: function (frm) { const alert = `
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index b97a5d2d1f7..da27e206c06 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -9,18 +9,17 @@ "engine": "InnoDB", "field_order": [ "naming_series", + "company", "item_code", + "item_name", "asset_name", - "asset_category", - "location", "image", "column_break_3", - "company", - "asset_owner", - "asset_owner_company", - "customer", - "supplier", + "location", + "asset_category", "asset_type", + "maintenance_required", + "calculate_depreciation", "purchase_details_section", "purchase_receipt", "purchase_receipt_item", @@ -34,25 +33,38 @@ "purchase_amount", "asset_quantity", "additional_asset_cost", + "section_break_uiyd", + "column_break_bbwr", + "column_break_bfkm", "total_asset_cost", "depreciation_tab", - "calculate_depreciation", - "column_break_33", + "column_break_wqzi", "opening_accumulated_depreciation", - "opening_number_of_booked_depreciations", "is_fully_depreciated", + "column_break_33", + "opening_number_of_booked_depreciations", "section_break_36", "finance_books", "section_break_33", "depreciation_method", "value_after_depreciation", - "total_number_of_depreciations", - "column_break_24", "frequency_of_depreciation", + "column_break_24", "next_depreciation_date", + "total_number_of_depreciations", "depreciation_schedule_sb", "depreciation_schedule_view", - "insurance_details_tab", + "other_info_tab", + "accounting_dimensions_section", + "cost_center", + "column_break_rjyw", + "asset_owner_section", + "asset_owner", + "column_break_yeds", + "asset_owner_company", + "customer", + "supplier", + "insurance_section", "policy_number", "insurer", "insured_value", @@ -60,21 +72,17 @@ "insurance_start_date", "insurance_end_date", "comprehensive_insurance", - "other_info_tab", - "accounting_dimensions_section", - "cost_center", "section_break_jtou", "status", "custodian", + "department", "default_finance_book", "depr_entry_posting_status", - "booked_fixed_asset", "column_break_51", - "department", - "split_from", "journal_entry_for_scrap", + "split_from", "amended_from", - "maintenance_required", + "booked_fixed_asset", "connections_tab" ], "fields": [ @@ -246,13 +254,14 @@ { "fieldname": "section_break_33", "fieldtype": "Section Break", - "hidden": 1 + "hidden": 1, + "label": "Depreciation Details" }, { "fieldname": "depreciation_method", "fieldtype": "Select", "label": "Depreciation Method", - "options": "\nStraight Line\nDouble Declining Balance\nManual" + "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual" }, { "fieldname": "value_after_depreciation", @@ -279,6 +288,7 @@ { "fieldname": "next_depreciation_date", "fieldtype": "Date", + "hidden": 1, "label": "Next Depreciation Date", "no_copy": 1 }, @@ -397,7 +407,7 @@ "fieldtype": "Column Break" }, { - "depends_on": "calculate_depreciation", + "depends_on": "eval: doc.calculate_depreciation", "fieldname": "section_break_36", "fieldtype": "Section Break" }, @@ -441,6 +451,7 @@ "depends_on": "eval:(doc.asset_type == \"Existing Asset\")", "fieldname": "is_fully_depreciated", "fieldtype": "Check", + "hidden": 1, "label": "Is Fully Depreciated" }, { @@ -489,15 +500,10 @@ "hidden": 1, "label": "Purchase Invoice Item" }, - { - "fieldname": "insurance_details_tab", - "fieldtype": "Tab Break", - "label": "Insurance" - }, { "fieldname": "other_info_tab", "fieldtype": "Tab Break", - "label": "Other Info" + "label": "More Info" }, { "fieldname": "connections_tab", @@ -506,6 +512,7 @@ "show_dashboard": 1 }, { + "depends_on": "eval: doc.calculate_depreciation || doc.asset_type == \"Existing Asset\"", "fieldname": "depreciation_tab", "fieldtype": "Tab Break", "label": "Depreciation" @@ -533,6 +540,48 @@ "fieldtype": "Select", "label": "Asset Type", "options": "\nExisting Asset\nComposite Asset\nComposite Component" + }, + { + "fieldname": "column_break_wqzi", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_rjyw", + "fieldtype": "Column Break" + }, + { + "fieldname": "insurance_section", + "fieldtype": "Section Break", + "label": "Insurance" + }, + { + "fieldname": "section_break_uiyd", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_bbwr", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_bfkm", + "fieldtype": "Column Break" + }, + { + "fetch_from": "item_code.item_name", + "fetch_if_empty": 1, + "fieldname": "item_name", + "fieldtype": "Read Only", + "hidden": 1, + "label": "Item Name" + }, + { + "fieldname": "asset_owner_section", + "fieldtype": "Section Break", + "label": "Ownership" + }, + { + "fieldname": "column_break_yeds", + "fieldtype": "Column Break" } ], "idx": 72, @@ -576,7 +625,7 @@ "link_fieldname": "target_asset" } ], - "modified": "2026-02-03 15:48:13.407835", + "modified": "2026-02-05 12:42:45.350216", "modified_by": "Administrator", "module": "Assets", "name": "Asset", diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index bbc4ed23824..1546cd6a906 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -68,7 +68,9 @@ class Asset(AccountsController): default_finance_book: DF.Link | None department: DF.Link | None depr_entry_posting_status: DF.Literal["", "Successful", "Failed"] - depreciation_method: DF.Literal["", "Straight Line", "Double Declining Balance", "Manual"] + depreciation_method: DF.Literal[ + "", "Straight Line", "Double Declining Balance", "Written Down Value", "Manual" + ] disposal_date: DF.Date | None finance_books: DF.Table[AssetFinanceBook] frequency_of_depreciation: DF.Int @@ -79,6 +81,7 @@ class Asset(AccountsController): insurer: DF.Data | None is_fully_depreciated: DF.Check item_code: DF.Link + item_name: DF.ReadOnly | None journal_entry_for_scrap: DF.Link | None location: DF.Link maintenance_required: DF.Check From 27c3c1dee0e6520a9e43814720b3626a6e23efe2 Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Thu, 5 Feb 2026 14:50:17 +0530 Subject: [PATCH 05/11] fix: test case (cherry picked from commit f2f509234b939c99bf927d37d326e463ff81b73a) --- erpnext/assets/doctype/asset/asset.js | 2 +- erpnext/assets/doctype/asset/depreciation.py | 6 +++++- erpnext/assets/doctype/asset/test_asset.py | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 6dc0a6c8dc4..a6ad021a99f 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -123,7 +123,7 @@ frappe.ui.form.on("Asset", { } if (has_create_buttons) { - cur_frm.page.set_inner_btn_group_as_primary(__("Create")); + frm.page.set_inner_btn_group_as_primary(__("Create")); } if (frm.doc.maintenance_required && !frm.doc.maintenance_schedule) { diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index c2bc885202d..832e3736e7d 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -786,7 +786,11 @@ def get_disposal_account_and_cost_center(company): @frappe.whitelist() -def get_value_after_depreciation_on_disposal_date(asset, disposal_date, finance_book=None): +def get_value_after_depreciation_on_disposal_date( + asset: str, + disposal_date: str, + finance_book: str | None = None, +) -> float: asset_doc = frappe.get_doc("Asset", asset) if asset_doc.asset_type == "Composite Component": diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index a71c3826d23..6440fcfad62 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -1937,7 +1937,7 @@ def create_asset(**args): "available_for_use_date": args.available_for_use_date or "2020-06-06", "location": args.location or "Test Location", "asset_owner": args.asset_owner or "Company", - "asset_type": args.asset_type or "", + "asset_type": args.asset_type or "Existing Asset", "asset_quantity": args.get("asset_quantity") or 1, "depr_entry_posting_status": args.depr_entry_posting_status or "", } From 3f11d0b8ad02ecbfdfea73b8db3e940bc7121824 Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Fri, 6 Feb 2026 01:06:20 +0530 Subject: [PATCH 06/11] fix: test cases fixes related to new select box change (cherry picked from commit e8e8d233abd7901236c4224fd1053cca103bed20) --- erpnext/assets/doctype/asset/asset.py | 4 +-- .../test_asset_capitalization.py | 29 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 1546cd6a906..95011c8bba1 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -254,7 +254,7 @@ class Asset(AccountsController): self.reload() if ( not self.booked_fixed_asset - and self.asset_type == "Composite Component" + and self.asset_type != "Composite Component" and self.validate_make_gl_entry() ): self.make_gl_entries() @@ -1399,7 +1399,7 @@ def process_asset_split(existing_asset, split_qty, splitted_asset=None, is_new_a def set_split_asset_values(asset_doc, scaling_factor, split_qty, existing_asset, is_new_asset): asset_doc.net_purchase_amount = existing_asset.net_purchase_amount * scaling_factor - asset_doc.purchase_amount = existing_asset.net_purchase_amount + asset_doc.purchase_amount = existing_asset.net_purchase_amount * scaling_factor asset_doc.additional_asset_cost = existing_asset.additional_asset_cost * scaling_factor asset_doc.total_asset_cost = asset_doc.net_purchase_amount + asset_doc.additional_asset_cost asset_doc.opening_accumulated_depreciation = ( diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py index 853e5cac3af..2e80645eab1 100644 --- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py @@ -10,12 +10,14 @@ from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries from erpnext.assets.doctype.asset.test_asset import ( create_asset, create_asset_data, + create_fixed_asset_item, set_depreciation_settings_in_company, ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( get_asset_depr_schedule_doc, ) from erpnext.stock.doctype.item.test_item import create_item +from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt from erpnext.stock.doctype.serial_and_batch_bundle.test_serial_and_batch_bundle import ( make_serial_batch_bundle, ) @@ -368,20 +370,33 @@ class TestAssetCapitalization(IntegrationTestCase): consumed_asset_value = 100000 - consumed_asset = create_asset( - asset_name="Asset Capitalization Consumable Asset", - asset_value=consumed_asset_value, - submit=1, - warehouse="Stores - _TC", - asset_type="Composite Component", + item = create_fixed_asset_item("Asset Capitalization Consumable Asset") + + pr = make_purchase_receipt( + item_code=item.item_code, + qty=1, + rate=consumed_asset_value, company=company, + warehouse="Stores - TCP1", ) + consumed_asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name") + consumed_asset_doc = frappe.get_doc("Asset", consumed_asset_name) + + consumed_asset_doc.update( + { + "asset_type": "Composite Component", + "purchase_date": pr.posting_date, + "available_for_use_date": pr.posting_date, + } + ) + consumed_asset_doc.save() + consumed_asset_doc.submit() # Create and submit Asset Captitalization asset_capitalization = create_asset_capitalization( target_asset=wip_composite_asset.name, target_asset_location="Test Location", - consumed_asset=consumed_asset.name, + consumed_asset=consumed_asset_doc.name, company=company, submit=1, ) From f9b6336dd52798a6365222569af295b2528114d3 Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Fri, 6 Feb 2026 01:55:11 +0530 Subject: [PATCH 07/11] refactor: asset capitalization form cleanup (cherry picked from commit eb7932ed7389652193b6a33a3141849b8c6cc3d9) --- .../asset_capitalization.js | 14 +- .../asset_capitalization.json | 122 +++++++++--------- .../asset_capitalization.py | 77 ++++------- .../test_asset_capitalization.py | 9 -- 4 files changed, 85 insertions(+), 137 deletions(-) diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js index c5db736669f..afa969e6fb3 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js @@ -17,10 +17,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s refresh() { this.show_general_ledger(); - if ( - (this.frm.doc.stock_items && this.frm.doc.stock_items.length) || - !this.frm.doc.target_is_fixed_asset - ) { + if (this.frm.doc.stock_items && this.frm.doc.stock_items.length) { this.show_stock_ledger(); } @@ -240,10 +237,6 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s this.calculate_totals(); } - target_qty() { - this.calculate_totals(); - } - rate() { this.calculate_totals(); } @@ -485,10 +478,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s me.frm.doc.stock_items_total + me.frm.doc.asset_items_total + me.frm.doc.service_items_total; me.frm.doc.total_value = flt(me.frm.doc.total_value, precision("total_value")); - me.frm.doc.target_qty = flt(me.frm.doc.target_qty, precision("target_qty")); - me.frm.doc.target_incoming_rate = me.frm.doc.target_qty - ? me.frm.doc.total_value / flt(me.frm.doc.target_qty) - : me.frm.doc.total_value; + me.frm.doc.target_incoming_rate = me.frm.doc.total_value; me.frm.refresh_fields(); } diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json index 57642e41472..0fc6b454051 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json @@ -9,30 +9,33 @@ "field_order": [ "title", "naming_series", + "company", "target_asset", "target_asset_name", - "target_item_code", - "finance_book", - "target_qty", "column_break_9", - "company", + "finance_book", "posting_date", "posting_time", "set_posting_time", - "target_batch_no", - "target_serial_no", + "target_item_code", "amended_from", - "target_is_fixed_asset", - "target_has_batch_no", - "target_has_serial_no", "section_break_16", "stock_items", + "section_break_urtz", + "column_break_gqep", + "column_break_yvlx", "stock_items_total", "section_break_26", "asset_items", + "section_break_arbh", + "column_break_boeu", + "column_break_qecy", "asset_items_total", "service_expenses_section", "service_items", + "section_break_ptna", + "column_break_szvh", + "column_break_katv", "service_items_total", "totals_section", "total_value", @@ -55,20 +58,12 @@ "depends_on": "eval:(doc.target_item_code && !doc.__islocal)", "fieldname": "target_item_code", "fieldtype": "Link", + "hidden": 1, "in_standard_filter": 1, "label": "Target Item Code", "options": "Item", "read_only": 1 }, - { - "default": "0", - "fetch_from": "target_item_code.is_fixed_asset", - "fieldname": "target_is_fixed_asset", - "fieldtype": "Check", - "hidden": 1, - "label": "Target Is Fixed Asset", - "read_only": 1 - }, { "fieldname": "target_asset", "fieldtype": "Link", @@ -143,6 +138,7 @@ "depends_on": "eval:doc.docstatus == 0 || (doc.stock_items && doc.stock_items.length)", "fieldname": "section_break_16", "fieldtype": "Section Break", + "hide_border": 1, "label": "Consumed Stock Items" }, { @@ -151,49 +147,11 @@ "label": "Stock Items", "options": "Asset Capitalization Stock Item" }, - { - "depends_on": "target_has_batch_no", - "fieldname": "target_batch_no", - "fieldtype": "Link", - "label": "Target Batch No", - "options": "Batch" - }, - { - "default": "1", - "fieldname": "target_qty", - "fieldtype": "Float", - "hidden": 1, - "label": "Target Qty", - "read_only": 1 - }, - { - "default": "0", - "fetch_from": "target_item_code.has_batch_no", - "fieldname": "target_has_batch_no", - "fieldtype": "Check", - "hidden": 1, - "label": "Target Has Batch No", - "read_only": 1 - }, - { - "default": "0", - "fetch_from": "target_item_code.has_serial_no", - "fieldname": "target_has_serial_no", - "fieldtype": "Check", - "hidden": 1, - "label": "Target Has Serial No", - "read_only": 1 - }, - { - "depends_on": "target_has_serial_no", - "fieldname": "target_serial_no", - "fieldtype": "Small Text", - "label": "Target Serial No" - }, { "depends_on": "eval:doc.docstatus == 0 || (doc.asset_items && doc.asset_items.length)", "fieldname": "section_break_26", "fieldtype": "Section Break", + "hide_border": 1, "label": "Consumed Assets" }, { @@ -203,6 +161,7 @@ "options": "Asset Capitalization Asset Item" }, { + "depends_on": "eval: doc.stock_items_total", "fieldname": "stock_items_total", "fieldtype": "Currency", "label": "Consumed Stock Total Value", @@ -210,6 +169,7 @@ "read_only": 1 }, { + "depends_on": "eval: doc.asset_items_total", "fieldname": "asset_items_total", "fieldtype": "Currency", "label": "Consumed Asset Total Value", @@ -226,6 +186,7 @@ "depends_on": "eval:doc.docstatus == 0 || (doc.service_items && doc.service_items.length)", "fieldname": "service_expenses_section", "fieldtype": "Section Break", + "hide_border": 1, "label": "Service Expenses" }, { @@ -235,6 +196,7 @@ "options": "Asset Capitalization Service Item" }, { + "depends_on": "eval: doc.service_items_total", "fieldname": "service_items_total", "fieldtype": "Currency", "label": "Service Expense Total Amount", @@ -277,10 +239,10 @@ "options": "Cost Center" }, { - "fieldname": "project", - "fieldtype": "Link", - "label": "Project", - "options": "Project" + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" }, { "fieldname": "dimension_col_break", @@ -292,12 +254,48 @@ "label": "Target Fixed Asset Account", "options": "Account", "read_only": 1 + }, + { + "fieldname": "section_break_urtz", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_gqep", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_yvlx", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_arbh", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_boeu", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_qecy", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_ptna", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_szvh", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_katv", + "fieldtype": "Column Break" } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2025-05-20 15:15:12.110035", + "modified": "2026-02-06 01:52:41.890713", "modified_by": "Administrator", "module": "Assets", "name": "Asset Capitalization", diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 8f092489b2b..050748189c4 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -39,9 +39,6 @@ force_fields = [ "target_asset_name", "item_name", "asset_name", - "target_is_fixed_asset", - "target_has_serial_no", - "target_has_batch_no", "stock_uom", "fixed_asset_account", "valuation_rate", @@ -76,6 +73,7 @@ class AssetCapitalization(StockController): naming_series: DF.Literal["ACC-ASC-.YYYY.-"] posting_date: DF.Date posting_time: DF.Time + project: DF.Link | None service_items: DF.Table[AssetCapitalizationServiceItem] service_items_total: DF.Currency set_posting_time: DF.Check @@ -83,15 +81,9 @@ class AssetCapitalization(StockController): stock_items_total: DF.Currency target_asset: DF.Link | None target_asset_name: DF.Data | None - target_batch_no: DF.Link | None target_fixed_asset_account: DF.Link | None - target_has_batch_no: DF.Check - target_has_serial_no: DF.Check target_incoming_rate: DF.Currency - target_is_fixed_asset: DF.Check target_item_code: DF.Link | None - target_qty: DF.Float - target_serial_no: DF.SmallText | None title: DF.Data | None total_value: DF.Currency # end: auto-generated types @@ -190,15 +182,6 @@ class AssetCapitalization(StockController): if not target_item.is_fixed_asset: frappe.throw(_("Target Item {0} must be a Fixed Asset item").format(target_item.name)) - if target_item.is_fixed_asset: - self.target_qty = 1 - if flt(self.target_qty) <= 0: - frappe.throw(_("Target Qty must be a positive number")) - if not target_item.has_batch_no: - self.target_batch_no = None - if not target_item.has_serial_no: - self.target_serial_no = "" - self.validate_item(target_item) def validate_target_asset(self): @@ -380,8 +363,7 @@ class AssetCapitalization(StockController): self.total_value = self.stock_items_total + self.asset_items_total + self.service_items_total self.total_value = flt(self.total_value, self.precision("total_value")) - self.target_qty = flt(self.target_qty, self.precision("target_qty")) - self.target_incoming_rate = self.total_value / self.target_qty + self.target_incoming_rate = self.total_value def update_stock_ledger(self): sl_entries = [] @@ -550,22 +532,21 @@ class AssetCapitalization(StockController): def get_gl_entries_for_target_item( self, gl_entries, target_account, target_against, precision, composite_component_value ): - if self.target_is_fixed_asset: - 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, - ) + 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 update_target_asset(self): total_target_asset_value = flt(self.total_value, self.precision("total_value")) @@ -611,14 +592,13 @@ class AssetCapitalization(StockController): def set_consumed_asset_status(self, asset): if self.docstatus == 1: - if self.target_is_fixed_asset: - asset.set_status("Capitalized") - add_asset_activity( - asset.name, - _("Asset capitalized after Asset Capitalization {0} was submitted").format( - get_link_to_form("Asset Capitalization", self.name) - ), - ) + asset.set_status("Capitalized") + add_asset_activity( + asset.name, + _("Asset capitalized after Asset Capitalization {0} was submitted").format( + get_link_to_form("Asset Capitalization", self.name) + ), + ) else: asset.set_status() add_asset_activity( @@ -640,17 +620,6 @@ def get_target_item_details(item_code=None, company=None): # Set Item Details out.target_item_name = item.item_name - out.target_is_fixed_asset = cint(item.is_fixed_asset) - out.target_has_batch_no = cint(item.has_batch_no) - out.target_has_serial_no = cint(item.has_serial_no) - - if out.target_is_fixed_asset: - out.target_qty = 1 - - if not out.target_has_batch_no: - out.target_batch_no = None - if not out.target_has_serial_no: - out.target_serial_no = "" # Cost Center item_defaults = get_item_defaults(item.name, company) diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py index 2e80645eab1..914b87b728f 100644 --- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py @@ -83,7 +83,6 @@ class TestAssetCapitalization(IntegrationTestCase): ) # Test Asset Capitalization values - self.assertEqual(asset_capitalization.target_qty, 1) self.assertEqual(asset_capitalization.stock_items[0].valuation_rate, stock_rate) self.assertEqual(asset_capitalization.stock_items[0].amount, stock_amount) @@ -178,8 +177,6 @@ class TestAssetCapitalization(IntegrationTestCase): ) # Test Asset Capitalization values - self.assertEqual(asset_capitalization.target_qty, 1) - self.assertEqual(asset_capitalization.stock_items[0].valuation_rate, stock_rate) self.assertEqual(asset_capitalization.stock_items[0].amount, stock_amount) self.assertEqual(asset_capitalization.stock_items_total, stock_amount) @@ -264,8 +261,6 @@ class TestAssetCapitalization(IntegrationTestCase): ) # Test Asset Capitalization values - self.assertEqual(asset_capitalization.target_qty, 1) - self.assertEqual(asset_capitalization.stock_items[0].valuation_rate, stock_rate) self.assertEqual(asset_capitalization.stock_items[0].amount, stock_amount) self.assertEqual(asset_capitalization.stock_items_total, stock_amount) @@ -402,7 +397,6 @@ class TestAssetCapitalization(IntegrationTestCase): ) # Test Asset Capitalization values - 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) @@ -436,9 +430,6 @@ def create_asset_capitalization(**args): "target_item_code": target_item_code, "target_asset": target_asset.name, "target_asset_location": "Test Location", - "target_qty": flt(args.target_qty) or 1, - "target_batch_no": args.target_batch_no, - "target_serial_no": args.target_serial_no, "finance_book": args.finance_book, } ) From 194b158e18f4c9624e94b900010e2e3d18a144ee Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Fri, 6 Feb 2026 11:42:24 +0530 Subject: [PATCH 08/11] refactor: asset repair UI changes (cherry picked from commit 9f7bfc0e368fcb8dc850b1737e6c6adc9399727d) --- .../asset_capitalization.py | 4 +-- .../doctype/asset_repair/asset_repair.json | 34 +++++++++++++------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 050748189c4..0894bad2d3d 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -610,7 +610,7 @@ class AssetCapitalization(StockController): @frappe.whitelist() -def get_target_item_details(item_code=None, company=None): +def get_target_item_details(item_code: str | None = None, company: str | None = None) -> frappe._dict: out = frappe._dict() # Get Item Details @@ -636,7 +636,7 @@ def get_target_item_details(item_code=None, company=None): @frappe.whitelist() -def get_target_asset_details(asset=None, company=None): +def get_target_asset_details(asset: str | None = None, company: str | None = None) -> frappe._dict: out = frappe._dict() # Get Asset Details diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json index b840b5a56b3..1d2fb1c67a0 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.json +++ b/erpnext/assets/doctype/asset_repair/asset_repair.json @@ -9,9 +9,9 @@ "engine": "InnoDB", "field_order": [ "naming_series", + "company", "asset", "asset_name", - "company", "column_break_2", "repair_status", "failure_date", @@ -28,10 +28,6 @@ "column_break_ajbh", "column_break_hkem", "repair_cost", - "accounting_dimensions_section", - "cost_center", - "column_break_14", - "project", "stock_consumption_details_section", "stock_items", "section_break_ltbb", @@ -43,7 +39,13 @@ "capitalize_repair_cost", "increase_in_asset_life", "column_break_xebe", - "total_repair_cost" + "total_repair_cost", + "accounting_dimensions_section", + "cost_center", + "column_break_14", + "project", + "accounting_dimension_tab", + "connection_tab" ], "fields": [ { @@ -149,8 +151,7 @@ { "fieldname": "accounting_details", "fieldtype": "Section Break", - "hide_border": 1, - "label": "Repair Purchase Invoices" + "hide_border": 1 }, { "fieldname": "stock_items", @@ -206,6 +207,7 @@ { "fieldname": "invoices", "fieldtype": "Table", + "label": "Repair Purchase Invoices", "mandatory_depends_on": "eval: doc.repair_status == 'Completed' && doc.repair_cost > 0;", "no_copy": 1, "options": "Asset Repair Purchase Invoice" @@ -244,6 +246,7 @@ "fieldtype": "Column Break" }, { + "depends_on": "eval: doc.consumed_items_cost", "fieldname": "consumed_items_cost", "fieldtype": "Currency", "label": "Consumed Items Cost" @@ -256,7 +259,18 @@ "depends_on": "capitalize_repair_cost", "fieldname": "accounting_dimensions_section", "fieldtype": "Section Break", - "label": "Accounting Dimensions" + "label": "Accounting Dimension" + }, + { + "fieldname": "accounting_dimension_tab", + "fieldtype": "Tab Break", + "label": "Accounting Dimension" + }, + { + "fieldname": "connection_tab", + "fieldtype": "Tab Break", + "label": "Connection", + "show_dashboard": 1 } ], "index_web_pages_for_search": 1, @@ -267,7 +281,7 @@ "link_fieldname": "asset_repair" } ], - "modified": "2026-01-06 15:48:13.862505", + "modified": "2026-02-06 02:25:37.536357", "modified_by": "Administrator", "module": "Assets", "name": "Asset Repair", From b619f6d9065f1b497b804254ecef2046d1d4f5aa Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Fri, 6 Feb 2026 15:56:08 +0530 Subject: [PATCH 09/11] fix: implement coderabbit suggested changes (cherry picked from commit d1b81b96a5f251351211282cee6c924564212837) --- erpnext/assets/doctype/asset/asset.js | 25 +++++++++++-------- erpnext/assets/doctype/asset/asset.json | 1 - .../doctype/asset_repair/asset_repair.json | 8 +----- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index a6ad021a99f..5980f265c9d 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -111,7 +111,10 @@ frappe.ui.form.on("Asset", { has_create_buttons = true; } - if (!frm.doc.calculate_depreciation) { + if ( + !frm.doc.calculate_depreciation && + ["Submitted", "Partially Depreciated", "Fully Depreciated"].includes(frm.doc.status) + ) { frm.add_custom_button( __("Depreciation Entry"), function () { @@ -126,17 +129,17 @@ frappe.ui.form.on("Asset", { frm.page.set_inner_btn_group_as_primary(__("Create")); } - if (frm.doc.maintenance_required && !frm.doc.maintenance_schedule) { - frm.add_custom_button( - __("Maintain Asset"), - function () { - frm.trigger("create_asset_maintenance"); - }, - __("Actions") - ); - } - if (["Submitted", "Partially Depreciated", "Fully Depreciated"].includes(frm.doc.status)) { + if (frm.doc.maintenance_required && !frm.doc.maintenance_schedule) { + frm.add_custom_button( + __("Maintain Asset"), + function () { + frm.trigger("create_asset_maintenance"); + }, + __("Actions") + ); + } + frm.add_custom_button( __("Split Asset"), function () { diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index da27e206c06..32f5ce9cf50 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -448,7 +448,6 @@ }, { "default": "0", - "depends_on": "eval:(doc.asset_type == \"Existing Asset\")", "fieldname": "is_fully_depreciated", "fieldtype": "Check", "hidden": 1, diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json index 1d2fb1c67a0..71b9469cfbd 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.json +++ b/erpnext/assets/doctype/asset_repair/asset_repair.json @@ -44,7 +44,6 @@ "cost_center", "column_break_14", "project", - "accounting_dimension_tab", "connection_tab" ], "fields": [ @@ -261,11 +260,6 @@ "fieldtype": "Section Break", "label": "Accounting Dimension" }, - { - "fieldname": "accounting_dimension_tab", - "fieldtype": "Tab Break", - "label": "Accounting Dimension" - }, { "fieldname": "connection_tab", "fieldtype": "Tab Break", @@ -281,7 +275,7 @@ "link_fieldname": "asset_repair" } ], - "modified": "2026-02-06 02:25:37.536357", + "modified": "2026-02-06 14:57:54.257572", "modified_by": "Administrator", "module": "Assets", "name": "Asset Repair", From 7f6b8a3e40879eed7847a13f0d24f75a9670409d Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Fri, 6 Feb 2026 16:22:44 +0530 Subject: [PATCH 10/11] chore: linters check (cherry picked from commit 4f59d580c4c5e838145ae21ac310280cc2b76aa1) --- erpnext/assets/doctype/asset/asset.js | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 5980f265c9d..2a7703495bf 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -234,6 +234,7 @@ frappe.ui.form.on("Asset", { if ( !frm.doc.purchase_receipt && + !frm.doc.purchase_invoice && ["Existing Asset", "Composite Component"].includes(frm.doc.asset_type) ) { return false; From 7b44e412d90bd7a079f920413441d7afeb17db7f Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Thu, 26 Feb 2026 16:35:24 +0530 Subject: [PATCH 11/11] fix: migration patch --- .../v16_0/migrate_asset_type_checkboxes_to_select.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/erpnext/patches/v16_0/migrate_asset_type_checkboxes_to_select.py b/erpnext/patches/v16_0/migrate_asset_type_checkboxes_to_select.py index 868d53b8985..11f341ce65a 100644 --- a/erpnext/patches/v16_0/migrate_asset_type_checkboxes_to_select.py +++ b/erpnext/patches/v16_0/migrate_asset_type_checkboxes_to_select.py @@ -3,6 +3,16 @@ from frappe.query_builder import Case def execute(): + required_columns = [ + "is_existing_asset", + "is_composite_asset", + "is_composite_component", + ] + + # Skip patch if any required column is missing + if not all(frappe.db.has_column("Asset", col) for col in required_columns): + return + Asset = frappe.qb.DocType("Asset") frappe.qb.update(Asset).set(