From 93dcba40ec3819a175c9c088d885e37159f848d8 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 25 May 2026 11:40:25 +0530 Subject: [PATCH] fix: stock reco for legacy serial nos (cherry picked from commit 9d5fd11bcd80a1de1c3282de06845648736cfebb) --- erpnext/stock/stock_ledger.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index a50bc4f8325..a1dc9d13a4e 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -887,7 +887,7 @@ class update_entries_after: # Only run in reposting self.get_serialized_values(sle) self.wh_data.qty_after_transaction += flt(sle.actual_qty) - if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no: + if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no and has_correct_data(sle): self.wh_data.qty_after_transaction = sle.qty_after_transaction self.wh_data.stock_value = flt(self.wh_data.qty_after_transaction) * flt( @@ -2517,3 +2517,28 @@ def get_incoming_rate_for_serial_and_batch(item_code, row, sn_obj): @frappe.request_cache def is_repack_entry(stock_entry_id): return frappe.get_cached_value("Stock Entry", stock_entry_id, "purpose") == "Repack" + + +def has_correct_data(sle): + previous_sle = get_previous_sle( + { + "item_code": sle.item_code, + "warehouse": sle.warehouse, + "posting_date": sle.posting_date, + "posting_time": sle.posting_time, + "creation": sle.creation, + "sle": sle.name, + } + ) + + if not previous_sle: + return True + + previous_qty = previous_sle.get("qty_after_transaction") or 0 + if previous_qty and not frappe.db.get_value( + "Stock Ledger Entry", + {"voucher_detail_no": sle.voucher_detail_no, "is_cancelled": 0, "actual_qty": ("<", 0)}, + ): + return False + + return True