perf(stock): cache is_serial_batch_item via Item document cache

The @frappe.request_cache decorator keyed on `self`, which after the service
extraction is a transient SerialBatchBundleService built per delegated call, so the
request-wide dedup was lost and dead instances were pinned in request_cache. Use
frappe.get_cached_value on the Item instead: caching is keyed by the item (request-
local + redis), effective regardless of service-instance churn, and the redundant
frappe.db.exists query is dropped.

Verified: ledger snapshots + serial and batch bundle suite stay green.
This commit is contained in:
Nabin Hait
2026-06-05 12:12:36 +05:30
parent a02ef40a5b
commit f1f66bdf2f

View File

@@ -376,17 +376,14 @@ class SerialBatchBundleService:
return field, reference_ids
@frappe.request_cache
def is_serial_batch_item(self, item_code) -> bool:
if not frappe.db.exists("Item", item_code):
item_details = frappe.get_cached_value(
"Item", item_code, ["has_serial_no", "has_batch_no"], as_dict=True
)
if not item_details:
frappe.throw(_("Item {0} does not exist.").format(bold(item_code)))
item_details = frappe.db.get_value("Item", item_code, ["has_serial_no", "has_batch_no"], as_dict=1)
if item_details.has_serial_no or item_details.has_batch_no:
return True
return False
return bool(item_details.has_serial_no or item_details.has_batch_no)
def update_bundle_details(self, bundle_details, table_name, row, is_rejected=False, parent_details=None):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos