diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 5e3e493b3d8..2717da14826 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -11,6 +11,7 @@ from frappe.model.document import Document from frappe.query_builder import Field from frappe.query_builder.functions import Count, IfNull, Max, Min, NullIf, Sum from frappe.utils import cint, cstr, flt, get_link_to_form, parse_json +from frappe.utils.caching import request_cache from frappe.website.website_generator import WebsiteGenerator import erpnext @@ -1253,17 +1254,10 @@ def _apply_representative_lines(rows, doctype, bom, keys): row[column] = line.get(column) +@request_cache def _representative_lines(doctype, bom, keys, columns): """Cached per request: get_bom_items_as_dict recurses through phantom BOMs, and the same sub-BOM is commonly reached more than once.""" - cache = getattr(frappe.local, "_bom_representative_lines", None) - if cache is None: - cache = frappe.local._bom_representative_lines = {} - - cache_key = (doctype, bom, keys, columns) - if cache_key in cache: - return cache[cache_key] - representative = {} for line in frappe.get_all( doctype, @@ -1273,7 +1267,6 @@ def _representative_lines(doctype, bom, keys, columns): ): representative.setdefault(tuple(line.get(key) for key in keys), line) - cache[cache_key] = representative return representative diff --git a/erpnext/manufacturing/doctype/production_plan/services/bom_explosion.py b/erpnext/manufacturing/doctype/production_plan/services/bom_explosion.py index 7faea744898..217feb4c814 100644 --- a/erpnext/manufacturing/doctype/production_plan/services/bom_explosion.py +++ b/erpnext/manufacturing/doctype/production_plan/services/bom_explosion.py @@ -5,6 +5,7 @@ import frappe from frappe.query_builder.functions import Count, IfNull, Max, Min, Sum +from frappe.utils.caching import request_cache from erpnext.manufacturing.doctype.production_plan.services.planning_queries import get_uom_conversion_factor @@ -67,16 +68,9 @@ def _apply_representative_lines(rows, doctype, bom_no, keys, include_non_stock_i row.source_warehouse = line.source_warehouse +@request_cache def _representative_lines(doctype, bom_no, keys, include_non_stock_items): """Cached per request: the explosion recurses and commonly revisits the same sub-BOM.""" - cache = getattr(frappe.local, "_bom_explosion_representative_lines", None) - if cache is None: - cache = frappe.local._bom_explosion_representative_lines = {} - - cache_key = (doctype, bom_no, keys, include_non_stock_items) - if cache_key in cache: - return cache[cache_key] - # only BOM Item carries is_phantom_item, and only its query ORs the phantom flag into the stock # filter; the explosion table has neither filters_phantom = doctype == "BOM Item" @@ -112,7 +106,6 @@ def _representative_lines(doctype, bom_no, keys, include_non_stock_items): for line in lines: representative.setdefault(tuple(line.get(key) for key in keys), line) - cache[cache_key] = representative return representative diff --git a/erpnext/manufacturing/doctype/production_plan/services/sub_assembly_queries.py b/erpnext/manufacturing/doctype/production_plan/services/sub_assembly_queries.py index 46384786a5e..ec1760976a4 100644 --- a/erpnext/manufacturing/doctype/production_plan/services/sub_assembly_queries.py +++ b/erpnext/manufacturing/doctype/production_plan/services/sub_assembly_queries.py @@ -6,6 +6,7 @@ import frappe from frappe.query_builder.functions import Count, IfNull, Max, Sum from frappe.utils import flt +from frappe.utils.caching import request_cache from erpnext.manufacturing.doctype.bom.bom import get_children as get_bom_children from erpnext.manufacturing.doctype.production_plan.services.planning_queries import ( @@ -207,15 +208,9 @@ def _apply_representative_lines(rows, bom_no): row.source_warehouse = line.source_warehouse +@request_cache def _representative_lines(bom_no, keys): """Cached per request: sub-assembly resolution recurses and revisits the same BOM.""" - cache = getattr(frappe.local, "_sub_assembly_representative_lines", None) - if cache is None: - cache = frappe.local._sub_assembly_representative_lines = {} - - if bom_no in cache: - return cache[bom_no] - representative = {} for line in frappe.get_all( "BOM Item", @@ -230,7 +225,6 @@ def _representative_lines(bom_no, keys): ): representative.setdefault(tuple(line.get(key) for key in keys), line) - cache[bom_no] = representative return representative