From 808214fd9517248c72e6e1d6a113b0eb147e5e42 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 08:53:07 +0000 Subject: [PATCH] perf: max recursion depth error in serial no (backport #54629) (#54631) perf: max recursion depth error in serial no (#54629) (cherry picked from commit 503b5bf1404d15cf52de7167d59f0af3c2f83eaa) Co-authored-by: Mihir Kandoi --- .../serial_and_batch_bundle.py | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py index bd8b0af1db2..3d018eece22 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py @@ -8,11 +8,10 @@ from collections import Counter, defaultdict import frappe import frappe.query_builder -import frappe.query_builder.functions from frappe import _, _dict, bold from frappe.model.document import Document from frappe.model.naming import make_autoname -from frappe.query_builder.functions import Concat_ws, Locate, Sum +from frappe.query_builder.functions import Concat_ws, Sum from frappe.utils import ( cint, cstr, @@ -3358,22 +3357,21 @@ def get_stock_ledgers_for_serial_nos(kwargs): serial_nos = [serial_nos] if serial_nos: + import re + + escaped_serial_nos = [re.escape(sn) for sn in serial_nos if sn] + regex_pattern = r"\n(" + "|".join(escaped_serial_nos) + r")\n" + query = ( query.left_join(serial_batch_entry) .on(stock_ledger_entry.serial_and_batch_bundle == serial_batch_entry.parent) + .where( + serial_batch_entry.serial_no.isin(serial_nos) + | Concat_ws("", "\n", stock_ledger_entry.serial_no, "\n").regexp(regex_pattern) + ) .distinct() ) - bundle_match = serial_batch_entry.serial_no.isin(serial_nos) - - padded_serial_no = Concat_ws("", "\n", stock_ledger_entry.serial_no, "\n") - direct_match = None - for sn in serial_nos: - cond = Locate(f"\n{sn}\n", padded_serial_no) > 0 - direct_match = cond if direct_match is None else (direct_match | cond) - - query = query.where(bundle_match | direct_match) - if kwargs.ignore_voucher_detail_no: query = query.where(stock_ledger_entry.voucher_detail_no != kwargs.ignore_voucher_detail_no)