mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-03 13:38:27 +00:00
perf: optimize validate_qty method to eliminate N+1 query problem
This commit is contained in:
@@ -265,6 +265,8 @@ class StatusUpdater(Document):
|
|||||||
# if target_ref_field is not specified, the programmer does not want to validate qty / amount
|
# if target_ref_field is not specified, the programmer does not want to validate qty / amount
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
items_to_validate = []
|
||||||
|
|
||||||
# get unique transactions to update
|
# get unique transactions to update
|
||||||
for d in self.get_all_children():
|
for d in self.get_all_children():
|
||||||
if hasattr(d, "qty") and d.qty < 0 and not self.get("is_return"):
|
if hasattr(d, "qty") and d.qty < 0 and not self.get("is_return"):
|
||||||
@@ -286,31 +288,63 @@ class StatusUpdater(Document):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if d.doctype == args["source_dt"] and d.get(args["join_field"]):
|
if d.doctype == args["source_dt"] and d.get(args["join_field"]):
|
||||||
args["name"] = d.get(args["join_field"])
|
items_to_validate.append(
|
||||||
|
frappe._dict(
|
||||||
is_from_pp = (
|
{
|
||||||
hasattr(d, "production_plan_sub_assembly_item")
|
"name": d.get(args["join_field"]),
|
||||||
and frappe.db.get_value(
|
"production_plan_sub_assembly_item": d.get(
|
||||||
"Production Plan Sub Assembly Item",
|
"production_plan_sub_assembly_item"
|
||||||
d.production_plan_sub_assembly_item,
|
),
|
||||||
"type_of_manufacturing",
|
"idx": d.idx,
|
||||||
|
"child_doc": d,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
== "Subcontract"
|
|
||||||
)
|
)
|
||||||
args["item_code"] = "production_item" if is_from_pp else "item_code"
|
|
||||||
|
|
||||||
# get all qty where qty > target_field
|
if items_to_validate:
|
||||||
item = frappe.db.sql(
|
pp_sub_assembly_items = [
|
||||||
"""select `{item_code}` as item_code, `{target_ref_field}`,
|
item.production_plan_sub_assembly_item
|
||||||
`{target_field}`, parenttype, parent from `tab{target_dt}`
|
for item in items_to_validate
|
||||||
where `{target_ref_field}` < `{target_field}`
|
if item.production_plan_sub_assembly_item
|
||||||
and name=%s and docstatus=1""".format(**args),
|
]
|
||||||
args["name"],
|
|
||||||
as_dict=1,
|
pp_subcontract_items = []
|
||||||
|
if pp_sub_assembly_items:
|
||||||
|
pp_subcontract_items = frappe.db.get_all(
|
||||||
|
"Production Plan Sub Assembly Item",
|
||||||
|
filters={
|
||||||
|
"name": ("in", pp_sub_assembly_items),
|
||||||
|
"type_of_manufacturing": "Subcontract",
|
||||||
|
},
|
||||||
|
pluck="name",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
regular_items = []
|
||||||
|
pp_items = []
|
||||||
|
|
||||||
|
for item in items_to_validate:
|
||||||
|
if item.production_plan_sub_assembly_item in pp_subcontract_items:
|
||||||
|
pp_items.append(item.name)
|
||||||
|
else:
|
||||||
|
regular_items.append(item.name)
|
||||||
|
|
||||||
|
item_details = []
|
||||||
|
|
||||||
|
# Query regular items with item_code field
|
||||||
|
if regular_items:
|
||||||
|
item_details.extend(self.fetch_items_with_pending_qty(args, "item_code", regular_items))
|
||||||
|
|
||||||
|
# Query production plan items with production_item field
|
||||||
|
if pp_items:
|
||||||
|
item_details.extend(self.fetch_items_with_pending_qty(args, "production_item", pp_items))
|
||||||
|
|
||||||
|
item_lookup = {item.name: item for item in item_details}
|
||||||
|
|
||||||
|
for child_item in items_to_validate:
|
||||||
|
item = item_lookup.get(child_item.name)
|
||||||
|
|
||||||
if item:
|
if item:
|
||||||
item = item[0]
|
item["idx"] = child_item.idx
|
||||||
item["idx"] = d.idx
|
|
||||||
item["target_ref_field"] = args["target_ref_field"].replace("_", " ")
|
item["target_ref_field"] = args["target_ref_field"].replace("_", " ")
|
||||||
|
|
||||||
# if not item[args['target_ref_field']]:
|
# if not item[args['target_ref_field']]:
|
||||||
@@ -323,6 +357,21 @@ class StatusUpdater(Document):
|
|||||||
elif item[args["target_ref_field"]]:
|
elif item[args["target_ref_field"]]:
|
||||||
self.check_overflow_with_allowance(item, args)
|
self.check_overflow_with_allowance(item, args)
|
||||||
|
|
||||||
|
def fetch_items_with_pending_qty(self, args, item_field, items):
|
||||||
|
return frappe.db.sql(
|
||||||
|
"""select name,`{item_code}` as item_code, `{target_ref_field}`,
|
||||||
|
`{target_field}`, parenttype, parent from `tab{target_dt}`
|
||||||
|
where `{target_ref_field}` < `{target_field}`
|
||||||
|
and name in %(names)s and docstatus=1""".format(
|
||||||
|
item_code=item_field,
|
||||||
|
target_ref_field=args["target_ref_field"],
|
||||||
|
target_field=args["target_field"],
|
||||||
|
target_dt=args["target_dt"],
|
||||||
|
),
|
||||||
|
{"names": items},
|
||||||
|
as_dict=1,
|
||||||
|
)
|
||||||
|
|
||||||
def check_overflow_with_allowance(self, item, args):
|
def check_overflow_with_allowance(self, item, args):
|
||||||
"""
|
"""
|
||||||
Checks if there is overflow condering a relaxation allowance
|
Checks if there is overflow condering a relaxation allowance
|
||||||
|
|||||||
Reference in New Issue
Block a user