perf: cache item metadata retrieval (#47929)
* perf(get_item_details): use cached doc, avoid full get_doc * perf: short-circuit common usecase of same UOM * perf: use cached doc for inspection * perf: use cached valuation method and other item props It rarely if ever changes after initial configuration
This commit is contained in:
@@ -1053,7 +1053,7 @@ class StockController(AccountsController):
|
||||
|
||||
for row in self.get("items"):
|
||||
qi_required = False
|
||||
if inspection_required_fieldname and frappe.db.get_value(
|
||||
if inspection_required_fieldname and frappe.get_cached_value(
|
||||
"Item", row.item_code, inspection_required_fieldname
|
||||
):
|
||||
qi_required = True
|
||||
@@ -1769,7 +1769,7 @@ def get_conditions_to_validate_future_sle(sl_entries):
|
||||
for warehouse, items in warehouse_items_map.items():
|
||||
or_conditions.append(
|
||||
f"""warehouse = {frappe.db.escape(warehouse)}
|
||||
and item_code in ({', '.join(frappe.db.escape(item) for item in items)})"""
|
||||
and item_code in ({", ".join(frappe.db.escape(item) for item in items)})"""
|
||||
)
|
||||
|
||||
return or_conditions
|
||||
|
||||
@@ -45,6 +45,7 @@ class TestStockReconciliation(IntegrationTestCase, StockTestMixin):
|
||||
def test_reco_for_moving_average(self):
|
||||
self._test_reco_sle_gle("Moving Average")
|
||||
|
||||
@IntegrationTestCase.change_settings("Stock Settings", {"allow_negative_stock": 1})
|
||||
def _test_reco_sle_gle(self, valuation_method):
|
||||
item_code = self.make_item(properties={"valuation_method": valuation_method}).name
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
import json
|
||||
import typing
|
||||
from functools import WRAPPER_ASSIGNMENTS, wraps
|
||||
|
||||
import frappe
|
||||
@@ -366,7 +367,7 @@ def get_basic_details(ctx: ItemDetailsCtx, item, overwrite_warehouse=True) -> It
|
||||
"""
|
||||
|
||||
if not item:
|
||||
item = frappe.get_doc("Item", ctx.item_code)
|
||||
item = frappe.get_cached_doc("Item", ctx.item_code)
|
||||
|
||||
if item.variant_of and not item.taxes and frappe.db.exists("Item Tax", {"parent": item.variant_of}):
|
||||
item.update_template_tables()
|
||||
@@ -532,8 +533,8 @@ def get_basic_details(ctx: ItemDetailsCtx, item, overwrite_warehouse=True) -> It
|
||||
out.manufacturer_part_no = None
|
||||
out.manufacturer = None
|
||||
else:
|
||||
data = frappe.get_value(
|
||||
"Item", item.name, ["default_item_manufacturer", "default_manufacturer_part_no"], as_dict=1
|
||||
data = frappe.get_cached_value(
|
||||
"Item", item.name, ["default_item_manufacturer", "default_manufacturer_part_no"], as_dict=True
|
||||
)
|
||||
|
||||
if data:
|
||||
@@ -1178,9 +1179,8 @@ def check_packing_list(price_list_rate_name, desired_qty, item_code):
|
||||
"""
|
||||
|
||||
flag = True
|
||||
item_price = frappe.get_doc("Item Price", price_list_rate_name)
|
||||
if item_price.packing_unit:
|
||||
packing_increment = desired_qty % item_price.packing_unit
|
||||
if packing_unit := frappe.db.get_value("Item Price", price_list_rate_name, "packing_unit", cache=True):
|
||||
packing_increment = desired_qty % packing_unit
|
||||
|
||||
if packing_increment != 0:
|
||||
flag = False
|
||||
@@ -1317,15 +1317,20 @@ def get_pos_profile(company, pos_profile=None, user=None):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_conversion_factor(item_code, uom):
|
||||
variant_of = frappe.db.get_value("Item", item_code, "variant_of", cache=True)
|
||||
item = frappe.get_cached_value("Item", item_code, ["variant_of", "stock_uom"], as_dict=True)
|
||||
if not item_code or not item:
|
||||
return {"conversion_factor": 1.0}
|
||||
|
||||
if uom == item.stock_uom:
|
||||
return {"conversion_factor": 1.0}
|
||||
|
||||
filters = {"parent": item_code, "uom": uom}
|
||||
|
||||
if variant_of:
|
||||
filters["parent"] = ("in", (item_code, variant_of))
|
||||
if item.variant_of:
|
||||
filters["parent"] = ("in", (item_code, item.variant_of))
|
||||
conversion_factor = frappe.db.get_value("UOM Conversion Detail", filters, "conversion_factor")
|
||||
if not conversion_factor:
|
||||
stock_uom = frappe.db.get_value("Item", item_code, "stock_uom")
|
||||
conversion_factor = get_uom_conv_factor(uom, stock_uom)
|
||||
conversion_factor = get_uom_conv_factor(uom, item.stock_uom)
|
||||
|
||||
return {"conversion_factor": conversion_factor or 1.0}
|
||||
|
||||
@@ -1447,7 +1452,7 @@ def apply_price_list(ctx: ItemDetailsCtx, as_doc=False, doc=None):
|
||||
|
||||
|
||||
def apply_price_list_on_item(ctx, doc=None):
|
||||
item_doc = frappe.db.get_value("Item", ctx.item_code, ["name", "variant_of"], as_dict=1)
|
||||
item_doc = frappe.get_cached_doc("Item", ctx.item_code)
|
||||
item_details = get_price_list_rate(ctx, item_doc)
|
||||
item_details.update(get_pricing_rule_for_item(ctx, doc=doc))
|
||||
|
||||
@@ -1515,7 +1520,6 @@ def get_valuation_rate(item_code, company, warehouse=None):
|
||||
item = get_item_defaults(item_code, company)
|
||||
item_group = get_item_group_defaults(item_code, company)
|
||||
brand = get_brand_defaults(item_code, company)
|
||||
# item = frappe.get_doc("Item", item_code)
|
||||
if item.get("is_stock_item"):
|
||||
if not warehouse:
|
||||
warehouse = (
|
||||
|
||||
@@ -2189,9 +2189,9 @@ def validate_reserved_batch_nos(item_code, warehouse, batch_nos):
|
||||
|
||||
|
||||
def is_negative_stock_allowed(*, item_code: str | None = None) -> bool:
|
||||
if cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock", cache=True)):
|
||||
if frappe.get_cached_doc("Stock Settings").allow_negative_stock:
|
||||
return True
|
||||
if item_code and cint(frappe.db.get_value("Item", item_code, "allow_negative_stock", cache=True)):
|
||||
if item_code and cint(frappe.get_cached_value("Item", item_code, "allow_negative_stock")):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -374,9 +374,9 @@ def get_avg_purchase_rate(serial_nos):
|
||||
|
||||
def get_valuation_method(item_code):
|
||||
"""get valuation method from item or default"""
|
||||
val_method = frappe.db.get_value("Item", item_code, "valuation_method", cache=True)
|
||||
val_method = frappe.get_cached_value("Item", item_code, "valuation_method")
|
||||
if not val_method:
|
||||
val_method = frappe.db.get_single_value("Stock Settings", "valuation_method", cache=True) or "FIFO"
|
||||
val_method = frappe.get_cached_doc("Stock Settings").valuation_method or "FIFO"
|
||||
return val_method
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user