From 7de15b74d411236f0244e71c11e79f220df9c5a6 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 27 Jun 2025 14:50:49 +0530 Subject: [PATCH 1/4] fix: option to pick serial / batch for asset repair (cherry picked from commit ae77c609fff563223d6730413b354e4c340c0589) # Conflicts: # erpnext/assets/doctype/asset_repair/asset_repair.py # erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json --- .../doctype/asset_repair/asset_repair.js | 35 +++++++++++++++++++ .../doctype/asset_repair/asset_repair.py | 13 +++++++ .../asset_repair_consumed_item.json | 20 +++++++++-- erpnext/public/js/controllers/transaction.js | 2 +- .../stock/doctype/stock_entry/stock_entry.py | 22 ++++++++++++ erpnext/stock/serial_batch_bundle.py | 22 ++++++++---- 6 files changed, 104 insertions(+), 10 deletions(-) diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js index 67ce6e6f7ef..e4c55d4363d 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.js +++ b/erpnext/assets/doctype/asset_repair/asset_repair.js @@ -3,6 +3,8 @@ frappe.ui.form.on("Asset Repair", { setup: function (frm) { + frm.ignore_doctypes_on_cancel_all = ["Serial and Batch Bundle"]; + frm.fields_dict.cost_center.get_query = function (doc) { return { filters: { @@ -167,4 +169,37 @@ frappe.ui.form.on("Asset Repair Consumed Item", { var row = locals[cdt][cdn]; frappe.model.set_value(cdt, cdn, "total_value", row.consumed_quantity * row.valuation_rate); }, + + pick_serial_and_batch(frm, cdt, cdn) { + let item = locals[cdt][cdn]; + let doc = frm.doc; + + frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"]).then((r) => { + if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) { + item.has_serial_no = r.message.has_serial_no; + item.has_batch_no = r.message.has_batch_no; + item.qty = item.consumed_quantity; + item.type_of_transaction = item.consumed_quantity > 0 ? "Outward" : "Inward"; + + item.title = item.has_serial_no ? __("Select Serial No") : __("Select Batch No"); + + if (item.has_serial_no && item.has_batch_no) { + item.title = __("Select Serial and Batch"); + } + frm.doc.posting_date = frappe.datetime.get_today(); + frm.doc.posting_time = frappe.datetime.now_time(); + + new erpnext.SerialBatchPackageSelector(frm, item, (r) => { + if (r) { + frappe.model.set_value(item.doctype, item.name, { + serial_and_batch_bundle: r.name, + use_serial_batch_fields: 0, + valuation_rate: r.avg_rate, + consumed_quantity: Math.abs(r.total_qty), + }); + } + }); + } + }); + }, }); diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 3938ae06b50..3b73da133df 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -96,6 +96,7 @@ class AssetRepair(AccountsController): if self.get("stock_consumption") or self.get("capitalize_repair_cost"): self.asset_doc.flags.increase_in_asset_value_due_to_repair = True +<<<<<<< HEAD self.increase_asset_value() total_repair_cost = self.get_total_value_of_stock_consumed() @@ -132,6 +133,16 @@ class AssetRepair(AccountsController): ) def before_cancel(self): +======= + def cancel_sabb(self): + for row in self.stock_items: + if sabb := row.serial_and_batch_bundle: + row.db_set("serial_and_batch_bundle", None) + doc = frappe.get_doc("Serial and Batch Bundle", sabb) + doc.cancel() + + def on_cancel(self): +>>>>>>> ae77c609ff (fix: option to pick serial / batch for asset repair) self.asset_doc = frappe.get_doc("Asset", self.asset) self.asset_doc.flags.increase_in_asset_value_due_to_repair = False @@ -172,6 +183,8 @@ class AssetRepair(AccountsController): ), ) + self.cancel_sabb() + def after_delete(self): frappe.get_doc("Asset", self.asset).set_status() diff --git a/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json index c4c13ce413b..76ff7f5e399 100644 --- a/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json +++ b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json @@ -11,6 +11,8 @@ "consumed_quantity", "total_value", "serial_no", + "column_break_xzfr", + "pick_serial_and_batch", "serial_and_batch_bundle" ], "fields": [ @@ -61,19 +63,33 @@ "label": "Warehouse", "options": "Warehouse", "reqd": 1 + }, + { + "fieldname": "pick_serial_and_batch", + "fieldtype": "Button", + "label": "Pick Serial / Batch" + }, + { + "fieldname": "column_break_xzfr", + "fieldtype": "Column Break" } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2024-06-13 12:01:47.147333", + "modified": "2025-06-27 14:52:56.311166", "modified_by": "Administrator", "module": "Assets", "name": "Asset Repair Consumed Item", "owner": "Administrator", "permissions": [], +<<<<<<< HEAD "sort_field": "modified", +======= + "row_format": "Dynamic", + "sort_field": "creation", +>>>>>>> ae77c609ff (fix: option to pick serial / batch for asset repair) "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index bb0c69b3a94..3f6f9ca5e20 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -8,7 +8,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe let me = this; this.set_fields_onload_for_line_item(); - this.frm.ignore_doctypes_on_cancel_all = ['Serial and Batch Bundle']; + this.frm.ignore_doctypes_on_cancel_all = ["Serial and Batch Bundle"]; frappe.flags.hide_serial_batch_dialog = true; frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) { diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 45afd1a0ad4..d204a421f68 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -263,6 +263,7 @@ class StockEntry(StockController): self.set_material_request_transfer_status("Completed") def on_cancel(self): + self.delink_asset_repair_sabb() self.validate_closed_subcontracting_order() self.update_subcontract_order_supplied_items() self.update_subcontracting_order_status() @@ -364,6 +365,27 @@ class StockEntry(StockController): ): frappe.delete_doc("Stock Entry", d.name) + def delink_asset_repair_sabb(self): + if not self.asset_repair: + return + + for row in self.items: + if row.serial_and_batch_bundle: + voucher_detail_no = frappe.db.get_value( + "Asset Repair Consumed Item", + {"parent": self.asset_repair, "serial_and_batch_bundle": row.serial_and_batch_bundle}, + "name", + ) + + doc = frappe.get_doc("Serial and Batch Bundle", row.serial_and_batch_bundle) + doc.db_set( + { + "voucher_type": "Asset Repair", + "voucher_no": self.asset_repair, + "voucher_detail_no": voucher_detail_no, + } + ) + def set_transfer_qty(self): self.validate_qty_is_not_zero() for item in self.get("items"): diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py index 99ad11326ea..8d9634db965 100644 --- a/erpnext/stock/serial_batch_bundle.py +++ b/erpnext/stock/serial_batch_bundle.py @@ -257,7 +257,7 @@ class SerialBatchBundle: frappe.throw(_(msg)) def delink_serial_and_batch_bundle(self): - if self.is_pos_transaction(): + if self.is_pos_or_asset_repair_transaction(): return update_values = { @@ -306,21 +306,29 @@ class SerialBatchBundle: self.cancel_serial_and_batch_bundle() def cancel_serial_and_batch_bundle(self): - if self.is_pos_transaction(): + if self.is_pos_or_asset_repair_transaction(): return doc = frappe.get_cached_doc("Serial and Batch Bundle", self.sle.serial_and_batch_bundle) if doc.docstatus == 1: doc.cancel() - def is_pos_transaction(self): + def is_pos_or_asset_repair_transaction(self): + voucher_type = frappe.get_cached_value( + "Serial and Batch Bundle", self.sle.serial_and_batch_bundle, "voucher_type" + ) + if ( self.sle.voucher_type == "Sales Invoice" and self.sle.serial_and_batch_bundle - and frappe.get_cached_value( - "Serial and Batch Bundle", self.sle.serial_and_batch_bundle, "voucher_type" - ) - == "POS Invoice" + and voucher_type == "POS Invoice" + ): + return True + + if ( + self.sle.voucher_type == "Stock Entry" + and self.sle.serial_and_batch_bundle + and voucher_type == "Asset Repair" ): return True From ab61b46a01efd0acb074716cd53f542d4a04848f Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Mon, 30 Jun 2025 10:09:59 +0530 Subject: [PATCH 2/4] chore: fix conflicts --- .../asset_repair_consumed_item.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json index 76ff7f5e399..c502b65ab7f 100644 --- a/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json +++ b/erpnext/assets/doctype/asset_repair_consumed_item/asset_repair_consumed_item.json @@ -83,12 +83,7 @@ "name": "Asset Repair Consumed Item", "owner": "Administrator", "permissions": [], -<<<<<<< HEAD "sort_field": "modified", -======= - "row_format": "Dynamic", - "sort_field": "creation", ->>>>>>> ae77c609ff (fix: option to pick serial / batch for asset repair) "sort_order": "DESC", "states": [], "track_changes": 1 From 352642096e37f2035b3ba28d5a1a72f381531796 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Mon, 30 Jun 2025 10:12:54 +0530 Subject: [PATCH 3/4] chore: fix conflicts --- erpnext/assets/doctype/asset_repair/asset_repair.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 3b73da133df..5cd9d522494 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -96,7 +96,6 @@ class AssetRepair(AccountsController): if self.get("stock_consumption") or self.get("capitalize_repair_cost"): self.asset_doc.flags.increase_in_asset_value_due_to_repair = True -<<<<<<< HEAD self.increase_asset_value() total_repair_cost = self.get_total_value_of_stock_consumed() @@ -132,17 +131,15 @@ class AssetRepair(AccountsController): ), ) - def before_cancel(self): -======= + def cancel_sabb(self): for row in self.stock_items: if sabb := row.serial_and_batch_bundle: row.db_set("serial_and_batch_bundle", None) doc = frappe.get_doc("Serial and Batch Bundle", sabb) doc.cancel() - - def on_cancel(self): ->>>>>>> ae77c609ff (fix: option to pick serial / batch for asset repair) + + def before_cancel(self): self.asset_doc = frappe.get_doc("Asset", self.asset) self.asset_doc.flags.increase_in_asset_value_due_to_repair = False From ac587b9c94c60e9ac436ba0da3b7b3a6fad47803 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Mon, 30 Jun 2025 10:55:56 +0530 Subject: [PATCH 4/4] chore: fix conflicts --- erpnext/assets/doctype/asset_repair/asset_repair.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 5cd9d522494..c50b70adeca 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -131,14 +131,13 @@ class AssetRepair(AccountsController): ), ) - def cancel_sabb(self): for row in self.stock_items: if sabb := row.serial_and_batch_bundle: row.db_set("serial_and_batch_bundle", None) doc = frappe.get_doc("Serial and Batch Bundle", sabb) doc.cancel() - + def before_cancel(self): self.asset_doc = frappe.get_doc("Asset", self.asset)