From 6c1ceff8eeb1df3224f83210eb889b5066ed57e9 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 18:07:14 +0530 Subject: [PATCH] fix: exclude already consumed purchase receipt items from asset capitalization (backport #46329) (#46336) * fix: exclude already consumed purchase receipt items from asset capitalization (#46329) * feat: link purchase receipt row item to capitalization * fix: avoid fetching already consumed stock and asset items during capitalization * fix(patch): added patch to link purchase receipt item to stock item child table * fix: added nosemgrep * refactor: rename to (cherry picked from commit f50d479bfd77bc27c3c309894474ff0d84160e8e) # Conflicts: # erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json # erpnext/patches.txt * fix: resolved conflicts * fix: resolved conflicts --------- Co-authored-by: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> --- .../asset_capitalization.js | 11 +++- .../asset_capitalization.py | 66 +++++++++++++++---- .../asset_capitalization_stock_item.json | 19 ++++-- .../asset_capitalization_stock_item.py | 1 + erpnext/patches.txt | 1 + ...t_row_item_to_capitalization_stock_item.py | 21 ++++++ 6 files changed, 100 insertions(+), 19 deletions(-) create mode 100644 erpnext/patches/v15_0/set_purchase_receipt_row_item_to_capitalization_stock_item.py diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js index 28a8b81f3ad..848a31c4dfa 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.js @@ -143,14 +143,19 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s } } - set_consumed_stock_items_tagged_to_wip_composite_asset(asset) { + set_consumed_stock_items_tagged_to_wip_composite_asset(target_asset) { var me = this; - if (asset) { + if (target_asset) { return me.frm.call({ method: "erpnext.assets.doctype.asset_capitalization.asset_capitalization.get_items_tagged_to_wip_composite_asset", args: { - asset: asset, + params: { + target_asset: target_asset, + finance_book: me.frm.doc.finance_book, + posting_date: me.frm.doc.posting_date, + posting_time: me.frm.doc.posting_time, + }, }, callback: function (r) { if (!r.exc && r.message) { diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index bed6cda43ed..f4addb66eb9 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -856,7 +856,10 @@ def get_service_item_details(args): @frappe.whitelist() -def get_items_tagged_to_wip_composite_asset(asset): +def get_items_tagged_to_wip_composite_asset(params): + if isinstance(params, str): + params = json.loads(params) + fields = [ "item_code", "item_name", @@ -871,25 +874,66 @@ def get_items_tagged_to_wip_composite_asset(asset): "amount", "is_fixed_asset", "parent", + "name", ] pr_items = frappe.get_all( - "Purchase Receipt Item", filters={"wip_composite_asset": asset, "docstatus": 1}, fields=fields + "Purchase Receipt Item", + filters={"wip_composite_asset": params.get("target_asset"), "docstatus": 1}, + fields=fields, ) stock_items = [] asset_items = [] + for d in pr_items: if not d.is_fixed_asset: - stock_items.append(frappe._dict(d)) + stock_item = process_stock_item(d) + if stock_item: + stock_items.append(stock_item) else: - asset_details = frappe.db.get_value( - "Asset", - {"item_code": d.item_code, "purchase_receipt": d.parent}, - ["name as asset", "asset_name"], - as_dict=1, - ) - d.update(asset_details) - asset_items.append(frappe._dict(d)) + asset_item = process_fixed_asset(d) + if asset_item: + asset_items.append(asset_item) return stock_items, asset_items + + +def process_stock_item(d): + stock_capitalized = frappe.db.exists( + "Asset Capitalization Stock Item", + { + "purchase_receipt_item": d.name, + "parentfield": "stock_items", + "parenttype": "Asset Capitalization", + "docstatus": 1, + }, + ) + + if stock_capitalized: + return None + + stock_item_data = frappe._dict(d) + stock_item_data.purchase_receipt_item = d.name + return stock_item_data + + +def process_fixed_asset(d): + asset_details = frappe.db.get_value( + "Asset", + { + "item_code": d.item_code, + "purchase_receipt": d.parent, + "status": ("not in", ["Draft", "Scrapped", "Sold", "Capitalized"]), + }, + ["name as asset", "asset_name", "company"], + as_dict=1, + ) + + if asset_details: + asset_details.update(d) + asset_details.update(get_consumed_asset_details(asset_details)) + d.update(asset_details) + + return frappe._dict(d) + return None diff --git a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json index da05e930eab..c96681411f7 100644 --- a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json +++ b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json @@ -10,12 +10,13 @@ "column_break_3", "warehouse", "section_break_6", + "purchase_receipt_item", "stock_qty", - "stock_uom", "actual_qty", "column_break_9", "valuation_rate", "amount", + "stock_uom", "batch_and_serial_no_section", "serial_and_batch_bundle", "use_serial_batch_fields", @@ -53,14 +54,14 @@ { "fieldname": "section_break_6", "fieldtype": "Section Break", - "label": "Qty and Rate" + "label": "Purchase Details" }, { "columns": 1, "fieldname": "stock_qty", "fieldtype": "Float", "in_list_view": 1, - "label": "Qty", + "label": "Quantity", "non_negative": 1 }, { @@ -172,18 +173,26 @@ { "fieldname": "column_break_mbuv", "fieldtype": "Column Break" + }, + { + "fieldname": "purchase_receipt_item", + "fieldtype": "Data", + "hidden": 1, + "label": "Purchase Receipt Item" } ], + "grid_page_length": 50, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2024-06-26 17:06:22.564438", + "modified": "2025-03-05 12:46:01.074742", "modified_by": "Administrator", "module": "Assets", "name": "Asset Capitalization Stock Item", "owner": "Administrator", "permissions": [], - "sort_field": "modified", + "row_format": "Dynamic", + "sort_field": "creation", "sort_order": "DESC", "states": [], "track_changes": 1 diff --git a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.py b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.py index 0f06cc7442e..c56f87b67fa 100644 --- a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.py +++ b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.py @@ -23,6 +23,7 @@ class AssetCapitalizationStockItem(Document): parent: DF.Data parentfield: DF.Data parenttype: DF.Data + purchase_receipt_item: DF.Data | None serial_and_batch_bundle: DF.Link | None serial_no: DF.Text | None stock_qty: DF.Float diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 8509989a2ca..505eb81e4e9 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -400,3 +400,4 @@ erpnext.patches.v15_0.rename_sla_fields erpnext.patches.v15_0.update_query_report erpnext.patches.v15_0.rename_field_from_rate_difference_to_amount_difference erpnext.patches.v15_0.recalculate_amount_difference_field +erpnext.patches.v15_0.set_purchase_receipt_row_item_to_capitalization_stock_item diff --git a/erpnext/patches/v15_0/set_purchase_receipt_row_item_to_capitalization_stock_item.py b/erpnext/patches/v15_0/set_purchase_receipt_row_item_to_capitalization_stock_item.py new file mode 100644 index 00000000000..f1d17d1da4d --- /dev/null +++ b/erpnext/patches/v15_0/set_purchase_receipt_row_item_to_capitalization_stock_item.py @@ -0,0 +1,21 @@ +import frappe + + +def execute(): + # nosemgrep + frappe.db.sql( + """ + UPDATE `tabAsset Capitalization Stock Item` ACSI + JOIN `tabAsset Capitalization` AC + ON ACSI.parent = AC.name + JOIN `tabPurchase Receipt Item` PRI + ON + PRI.item_code = ACSI.item_code + AND PRI.wip_composite_asset = AC.target_asset + SET + ACSI.purchase_receipt_item = PRI.name + WHERE + ACSI.purchase_receipt_item IS NULL + AND AC.docstatus = 1 + """ + )