perf: pull latest details only for referenced vouchers
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index c6576f7..ac31e8a 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -230,84 +230,88 @@
 		return False
 
 	def validate_allocated_amount_with_latest_data(self):
-		latest_references = get_outstanding_reference_documents(
-			{
-				"posting_date": self.posting_date,
-				"company": self.company,
-				"party_type": self.party_type,
-				"payment_type": self.payment_type,
-				"party": self.party,
-				"party_account": self.paid_from if self.payment_type == "Receive" else self.paid_to,
-				"get_outstanding_invoices": True,
-				"get_orders_to_be_billed": True,
-			},
-			validate=True,
-		)
+		if self.references:
+			uniq_vouchers = set([(x.reference_doctype, x.reference_name) for x in self.references])
+			vouchers = [frappe._dict({"voucher_type": x[0], "voucher_no": x[1]}) for x in uniq_vouchers]
+			latest_references = get_outstanding_reference_documents(
+				{
+					"posting_date": self.posting_date,
+					"company": self.company,
+					"party_type": self.party_type,
+					"payment_type": self.payment_type,
+					"party": self.party,
+					"party_account": self.paid_from if self.payment_type == "Receive" else self.paid_to,
+					"get_outstanding_invoices": True,
+					"get_orders_to_be_billed": True,
+					"vouchers": vouchers,
+				},
+				validate=True,
+			)
 
-		# Group latest_references by (voucher_type, voucher_no)
-		latest_lookup = {}
-		for d in latest_references:
-			d = frappe._dict(d)
-			latest_lookup.setdefault((d.voucher_type, d.voucher_no), frappe._dict())[d.payment_term] = d
+			# Group latest_references by (voucher_type, voucher_no)
+			latest_lookup = {}
+			for d in latest_references:
+				d = frappe._dict(d)
+				latest_lookup.setdefault((d.voucher_type, d.voucher_no), frappe._dict())[d.payment_term] = d
 
-		for idx, d in enumerate(self.get("references"), start=1):
-			latest = latest_lookup.get((d.reference_doctype, d.reference_name)) or frappe._dict()
+			for idx, d in enumerate(self.get("references"), start=1):
+				latest = latest_lookup.get((d.reference_doctype, d.reference_name)) or frappe._dict()
 
-			# If term based allocation is enabled, throw
-			if (
-				d.payment_term is None or d.payment_term == ""
-			) and self.term_based_allocation_enabled_for_reference(
-				d.reference_doctype, d.reference_name
-			):
-				frappe.throw(
-					_(
-						"{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section"
-					).format(frappe.bold(d.reference_name), frappe.bold(idx))
-				)
-
-			# if no payment template is used by invoice and has a custom term(no `payment_term`), then invoice outstanding will be in 'None' key
-			latest = latest.get(d.payment_term) or latest.get(None)
-
-			# The reference has already been fully paid
-			if not latest:
-				frappe.throw(
-					_("{0} {1} has already been fully paid.").format(_(d.reference_doctype), d.reference_name)
-				)
-			# The reference has already been partly paid
-			elif latest.outstanding_amount < latest.invoice_amount and flt(
-				d.outstanding_amount, d.precision("outstanding_amount")
-			) != flt(latest.outstanding_amount, d.precision("outstanding_amount")):
-				frappe.throw(
-					_(
-						"{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' or the 'Get Outstanding Orders' button to get the latest outstanding amounts."
-					).format(_(d.reference_doctype), d.reference_name)
-				)
-
-			fail_message = _("Row #{0}: Allocated Amount cannot be greater than outstanding amount.")
-
-			if (
-				d.payment_term
-				and (
-					(flt(d.allocated_amount)) > 0
-					and latest.payment_term_outstanding
-					and (flt(d.allocated_amount) > flt(latest.payment_term_outstanding))
-				)
-				and self.term_based_allocation_enabled_for_reference(d.reference_doctype, d.reference_name)
-			):
-				frappe.throw(
-					_(
-						"Row #{0}: Allocated amount:{1} is greater than outstanding amount:{2} for Payment Term {3}"
-					).format(
-						d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term
+				# If term based allocation is enabled, throw
+				if (
+					d.payment_term is None or d.payment_term == ""
+				) and self.term_based_allocation_enabled_for_reference(
+					d.reference_doctype, d.reference_name
+				):
+					frappe.throw(
+						_(
+							"{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section"
+						).format(frappe.bold(d.reference_name), frappe.bold(idx))
 					)
-				)
 
-			if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount):
-				frappe.throw(fail_message.format(d.idx))
+				# if no payment template is used by invoice and has a custom term(no `payment_term`), then invoice outstanding will be in 'None' key
+				latest = latest.get(d.payment_term) or latest.get(None)
 
-			# Check for negative outstanding invoices as well
-			if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount):
-				frappe.throw(fail_message.format(d.idx))
+				# The reference has already been fully paid
+				if not latest:
+					frappe.throw(
+						_("{0} {1} has already been fully paid.").format(_(d.reference_doctype), d.reference_name)
+					)
+				# The reference has already been partly paid
+				elif latest.outstanding_amount < latest.invoice_amount and flt(
+					d.outstanding_amount, d.precision("outstanding_amount")
+				) != flt(latest.outstanding_amount, d.precision("outstanding_amount")):
+					frappe.throw(
+						_(
+							"{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' or the 'Get Outstanding Orders' button to get the latest outstanding amounts."
+						).format(_(d.reference_doctype), d.reference_name)
+					)
+
+				fail_message = _("Row #{0}: Allocated Amount cannot be greater than outstanding amount.")
+
+				if (
+					d.payment_term
+					and (
+						(flt(d.allocated_amount)) > 0
+						and latest.payment_term_outstanding
+						and (flt(d.allocated_amount) > flt(latest.payment_term_outstanding))
+					)
+					and self.term_based_allocation_enabled_for_reference(d.reference_doctype, d.reference_name)
+				):
+					frappe.throw(
+						_(
+							"Row #{0}: Allocated amount:{1} is greater than outstanding amount:{2} for Payment Term {3}"
+						).format(
+							d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term
+						)
+					)
+
+				if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount):
+					frappe.throw(fail_message.format(d.idx))
+
+				# Check for negative outstanding invoices as well
+				if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount):
+					frappe.throw(fail_message.format(d.idx))
 
 	def delink_advance_entry_references(self):
 		for reference in self.references:
@@ -1587,6 +1591,7 @@
 			min_outstanding=args.get("outstanding_amt_greater_than"),
 			max_outstanding=args.get("outstanding_amt_less_than"),
 			accounting_dimensions=accounting_dimensions_filter,
+			vouchers=args.get("vouchers") or None,
 		)
 
 		outstanding_invoices = split_invoices_based_on_payment_terms(
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index c24442e..bccf6f1 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -908,6 +908,7 @@
 	min_outstanding=None,
 	max_outstanding=None,
 	accounting_dimensions=None,
+	vouchers=None,
 ):
 
 	ple = qb.DocType("Payment Ledger Entry")
@@ -933,6 +934,7 @@
 
 	ple_query = QueryPaymentLedger()
 	invoice_list = ple_query.get_voucher_outstandings(
+		vouchers=vouchers,
 		common_filter=common_filter,
 		posting_date=posting_date,
 		min_outstanding=min_outstanding,