perf: reduce number of queries for checking if future SL entry exists (#25064)
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 11ac703..f352bae 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -495,7 +495,7 @@
"voucher_no": self.name,
"company": self.company
})
- if check_if_future_sle_exists(args):
+ if future_sle_exists(args):
create_repost_item_valuation_entry(args)
elif not is_reposting_pending():
check_if_stock_and_account_balance_synced(self.posting_date,
@@ -506,37 +506,42 @@
{'docstatus': 1, 'status': ['in', ['Queued','In Progress']]})
-def check_if_future_sle_exists(args):
- sl_entries = frappe.db.get_all("Stock Ledger Entry",
+def future_sle_exists(args):
+ sl_entries = frappe.get_all("Stock Ledger Entry",
filters={"voucher_type": args.voucher_type, "voucher_no": args.voucher_no},
fields=["item_code", "warehouse"],
order_by="creation asc")
- distinct_item_warehouses = list(set([(d.item_code, d.warehouse) for d in sl_entries]))
+ if not sl_entries:
+ return
- sle_exists = False
- for item_code, warehouse in distinct_item_warehouses:
- args.update({
- "item_code": item_code,
- "warehouse": warehouse
- })
- if get_sle(args):
- sle_exists = True
- break
- return sle_exists
+ warehouse_items_map = {}
+ for entry in sl_entries:
+ if entry.warehouse not in warehouse_items_map:
+ warehouse_items_map[entry.warehouse] = set()
-def get_sle(args):
+ warehouse_items_map[entry.warehouse].add(entry.item_code)
+
+ or_conditions = []
+ for warehouse, items in warehouse_items_map.items():
+ or_conditions.append(
+ "warehouse = '{}' and item_code in ({})".format(
+ warehouse,
+ ", ".join(frappe.db.escape(item) for item in items)
+ )
+ )
+
return frappe.db.sql("""
select name
from `tabStock Ledger Entry`
where
- item_code=%(item_code)s
- and warehouse=%(warehouse)s
- and timestamp(posting_date, posting_time) >= timestamp(%(posting_date)s, %(posting_time)s)
+ ({})
+ and timestamp(posting_date, posting_time)
+ >= timestamp(%(posting_date)s, %(posting_time)s)
and voucher_no != %(voucher_no)s
and is_cancelled = 0
limit 1
- """, args)
+ """.format(" or ".join(or_conditions)), args)
def create_repost_item_valuation_entry(args):
args = frappe._dict(args)
@@ -554,4 +559,4 @@
repost_entry.allow_zero_rate = args.allow_zero_rate
repost_entry.flags.ignore_links = True
repost_entry.save()
- repost_entry.submit()
\ No newline at end of file
+ repost_entry.submit()
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index f54b3c1..121c51c 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -207,11 +207,11 @@
def build(self):
- from erpnext.controllers.stock_controller import check_if_future_sle_exists
+ from erpnext.controllers.stock_controller import future_sle_exists
if self.args.get("sle_id"):
self.process_sle_against_current_timestamp()
- if not check_if_future_sle_exists(self.args):
+ if not future_sle_exists(self.args):
self.update_bin()
else:
entries_to_fix = self.get_future_entries_to_fix()
@@ -856,4 +856,4 @@
and qty_after_transaction < 0
order by timestamp(posting_date, posting_time) asc
limit 1
- """, args, as_dict=1)
\ No newline at end of file
+ """, args, as_dict=1)