mirror of
https://github.com/frappe/erpnext.git
synced 2026-09-02 16:13:22 +00:00
perf: batch status check for on-hold/closed documents, remove N+1 queries (#54798)
This commit is contained in:
@@ -683,19 +683,6 @@ class BuyingController(SubcontractingController):
|
||||
)
|
||||
)
|
||||
|
||||
def check_for_on_hold_or_closed_status(self, ref_doctype, ref_fieldname):
|
||||
for d in self.get("items"):
|
||||
if d.get(ref_fieldname):
|
||||
status = frappe.db.get_value(ref_doctype, d.get(ref_fieldname), "status")
|
||||
if status in ("Closed", "On Hold"):
|
||||
frappe.throw(
|
||||
_("{ref_doctype} {ref_name} is {status}.").format(
|
||||
ref_doctype=frappe.bold(_(ref_doctype)),
|
||||
ref_name=frappe.bold(d.get(ref_fieldname)),
|
||||
status=frappe.bold(_(status)),
|
||||
)
|
||||
)
|
||||
|
||||
def update_stock_ledger(self, allow_negative_stock=False, via_landed_cost_voucher=False):
|
||||
self.update_ordered_and_reserved_qty()
|
||||
|
||||
|
||||
@@ -469,11 +469,9 @@ class SellingController(StockController):
|
||||
return so_qty, so_warehouse
|
||||
|
||||
def check_sales_order_on_hold_or_close(self, ref_fieldname):
|
||||
for d in self.get("items"):
|
||||
if d.get(ref_fieldname):
|
||||
status = frappe.db.get_value("Sales Order", d.get(ref_fieldname), "status")
|
||||
if status in ("Closed", "On Hold") and not self.is_return:
|
||||
frappe.throw(_("Sales Order {0} is {1}").format(d.get(ref_fieldname), status))
|
||||
if self.is_return:
|
||||
return
|
||||
self.check_for_on_hold_or_closed_status("Sales Order", ref_fieldname)
|
||||
|
||||
def update_reserved_qty(self):
|
||||
so_map = {}
|
||||
|
||||
@@ -1937,6 +1937,43 @@ class StockController(AccountsController):
|
||||
|
||||
qty -= working_qty
|
||||
|
||||
def check_for_on_hold_or_closed_status(
|
||||
self, ref_doctype: str, ref_fieldname: str, exclude_if_field: str | None = None
|
||||
) -> None:
|
||||
def _include(d):
|
||||
return d.get(ref_fieldname) and not (exclude_if_field and d.get(exclude_if_field))
|
||||
|
||||
included = [(d, d.get(ref_fieldname)) for d in self.get("items") if _include(d)]
|
||||
if not included:
|
||||
return
|
||||
|
||||
status_map = {
|
||||
r.name: r.status
|
||||
for r in frappe.get_all(
|
||||
ref_doctype,
|
||||
filters={"name": ["in", {name for _, name in included}]},
|
||||
fields=["name", "status"],
|
||||
)
|
||||
}
|
||||
|
||||
errors = []
|
||||
seen = set()
|
||||
for _d, ref_name in included:
|
||||
if ref_name in seen:
|
||||
continue
|
||||
seen.add(ref_name)
|
||||
if (status := status_map.get(ref_name)) in ("Closed", "On Hold"):
|
||||
errors.append(
|
||||
_("{ref_doctype} {ref_name} status is {status}.").format(
|
||||
ref_doctype=frappe.bold(_(ref_doctype)),
|
||||
ref_name=frappe.bold(ref_name),
|
||||
status=frappe.bold(_(status)),
|
||||
)
|
||||
)
|
||||
|
||||
if errors:
|
||||
frappe.throw("<br>".join(errors), frappe.InvalidStatusError)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def show_accounting_ledger_preview(company: str, doctype: str, docname: str):
|
||||
|
||||
Reference in New Issue
Block a user