fix: time out while submitting the stock transactions with more than 50 items
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index da81911..20f5445 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -171,12 +171,13 @@
 
 			TODO: rename item_tax_amount to valuation_tax_amount
 		"""
+		stock_and_asset_items = []
 		stock_and_asset_items = self.get_stock_items() + self.get_asset_items()
 
 		stock_and_asset_items_qty, stock_and_asset_items_amount = 0, 0
 		last_item_idx = 1
 		for d in self.get("items"):
-			if d.item_code and d.item_code in stock_and_asset_items:
+			if (d.item_code and d.item_code in stock_and_asset_items):
 				stock_and_asset_items_qty += flt(d.qty)
 				stock_and_asset_items_amount += flt(d.base_net_amount)
 				last_item_idx = d.idx
@@ -683,7 +684,8 @@
 			self.process_fixed_asset()
 			self.update_fixed_asset(field)
 
-		update_last_purchase_rate(self, is_submit = 1)
+		if self.doctype in ['Purchase Order', 'Purchase Receipt']:
+			update_last_purchase_rate(self, is_submit = 1)
 
 	def on_cancel(self):
 		super(BuyingController, self).on_cancel()
@@ -691,7 +693,9 @@
 		if self.get('is_return'):
 			return
 
-		update_last_purchase_rate(self, is_submit = 0)
+		if self.doctype in ['Purchase Order', 'Purchase Receipt']:
+			update_last_purchase_rate(self, is_submit = 0)
+
 		if self.doctype in ['Purchase Receipt', 'Purchase Invoice']:
 			field = 'purchase_invoice' if self.doctype == 'Purchase Invoice' else 'purchase_receipt'
 
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 6a7c9e3..35097b9 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -501,7 +501,6 @@
 			check_if_stock_and_account_balance_synced(self.posting_date,
 				self.company, self.doctype, self.name)
 
-
 @frappe.whitelist()
 def make_quality_inspections(doctype, docname, items):
 	if isinstance(items, str):
@@ -533,21 +532,75 @@
 
 	return inspections
 
-
 def is_reposting_pending():
 	return frappe.db.exists("Repost Item Valuation",
 		{'docstatus': 1, 'status': ['in', ['Queued','In Progress']]})
 
+def future_sle_exists(args, sl_entries=None):
+	key = (args.voucher_type, args.voucher_no)
 
-def future_sle_exists(args):
-	sl_entries = frappe.get_all("Stock Ledger Entry",
+	if validate_future_sle_not_exists(args, key, sl_entries):
+		return False
+	elif get_cached_data(args, key):
+		return True
+
+	if not sl_entries:
+		sl_entries = get_sle_entries_against_voucher(args)
+		if not sl_entries:
+			return
+
+	or_conditions = get_conditions_to_validate_future_sle(sl_entries)
+
+	data = frappe.db.sql("""
+		select item_code, warehouse, count(name) as total_row
+		from `tabStock Ledger Entry`
+		where
+			({})
+			and timestamp(posting_date, posting_time)
+				>= timestamp(%(posting_date)s, %(posting_time)s)
+			and voucher_no != %(voucher_no)s
+			and is_cancelled = 0
+		GROUP BY
+			item_code, warehouse
+		""".format(" or ".join(or_conditions)), args, as_dict=1)
+
+	for d in data:
+		frappe.local.future_sle[key][(d.item_code, d.warehouse)] = d.total_row
+
+	return len(data)
+
+def validate_future_sle_not_exists(args, key, sl_entries=None):
+	item_key = ''
+	if args.get('item_code'):
+		item_key = (args.get('item_code'), args.get('warehouse'))
+
+	if not sl_entries and hasattr(frappe.local, 'future_sle'):
+		if (not frappe.local.future_sle.get(key) or
+			(item_key and item_key not in frappe.local.future_sle.get(key))):
+			return True
+
+def get_cached_data(args, key):
+	if not hasattr(frappe.local, 'future_sle'):
+		frappe.local.future_sle = {}
+
+	if key not in frappe.local.future_sle:
+		frappe.local.future_sle[key] = frappe._dict({})
+
+	if args.get('item_code'):
+		item_key = (args.get('item_code'), args.get('warehouse'))
+		count = frappe.local.future_sle[key].get(item_key)
+
+		return True if (count or count == 0) else False
+	else:
+		return frappe.local.future_sle[key]
+
+def get_sle_entries_against_voucher(args):
+	return 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")
 
-	if not sl_entries:
-		return
-
+def get_conditions_to_validate_future_sle(sl_entries):
 	warehouse_items_map = {}
 	for entry in sl_entries:
 		if entry.warehouse not in warehouse_items_map:
@@ -561,17 +614,7 @@
 			f"""warehouse = {frappe.db.escape(warehouse)}
 				and item_code in ({', '.join(frappe.db.escape(item) for item in items)})""")
 
-	return frappe.db.sql("""
-		select name
-		from `tabStock Ledger Entry`
-		where
-			({})
-			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
-		""".format(" or ".join(or_conditions)), args)
+	return or_conditions
 
 def create_repost_item_valuation_entry(args):
 	args = frappe._dict(args)