Merge pull request #39701 from GursheenK/check-paid-amount-for-orders-before-request

fix: check order paid amount before payment request
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index a18104e..1649183 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -3,6 +3,7 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
+from frappe.query_builder.functions import Sum
 from frappe.utils import flt, nowdate
 from frappe.utils.background_jobs import enqueue
 
@@ -106,6 +107,8 @@
 		ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
 		if not hasattr(ref_doc, "order_type") or getattr(ref_doc, "order_type") != "Shopping Cart":
 			ref_amount = get_amount(ref_doc, self.payment_account)
+			if not ref_amount:
+				frappe.throw(_("Payment Entry is already created"))
 
 			if existing_payment_request_amount + flt(self.grand_total) > ref_amount:
 				frappe.throw(
@@ -453,6 +456,8 @@
 	gateway_account = get_gateway_details(args) or frappe._dict()
 
 	grand_total = get_amount(ref_doc, gateway_account.get("payment_account"))
+	if not grand_total:
+		frappe.throw(_("Payment Entry is already created"))
 	if args.loyalty_points and args.dt == "Sales Order":
 		from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
 
@@ -543,6 +548,7 @@
 	dt = ref_doc.doctype
 	if dt in ["Sales Order", "Purchase Order"]:
 		grand_total = flt(ref_doc.rounded_total) or flt(ref_doc.grand_total)
+		grand_total -= get_paid_amount_against_order(dt, ref_doc.name)
 	elif dt in ["Sales Invoice", "Purchase Invoice"]:
 		if not ref_doc.get("is_pos"):
 			if ref_doc.party_account_currency == ref_doc.currency:
@@ -562,10 +568,7 @@
 	elif dt == "Fees":
 		grand_total = ref_doc.outstanding_amount
 
-	if grand_total > 0:
-		return grand_total
-	else:
-		frappe.throw(_("Payment Entry is already created"))
+	return grand_total
 
 
 def get_existing_payment_request_amount(ref_dt, ref_dn):
@@ -748,3 +751,27 @@
 			doc.reference_docname
 		)
 	)
+
+
+def get_paid_amount_against_order(dt, dn):
+	pe_ref = frappe.qb.DocType("Payment Entry Reference")
+	if dt == "Sales Order":
+		inv_dt, inv_field = "Sales Invoice Item", "sales_order"
+	else:
+		inv_dt, inv_field = "Purchase Invoice Item", "purchase_order"
+	inv_item = frappe.qb.DocType(inv_dt)
+	return (
+		frappe.qb.from_(pe_ref)
+		.select(
+			Sum(pe_ref.allocated_amount),
+		)
+		.where(
+			(pe_ref.docstatus == 1)
+			& (
+				(pe_ref.reference_name == dn)
+				| pe_ref.reference_name.isin(
+					frappe.qb.from_(inv_item).select(inv_item.parent).where(inv_item[inv_field] == dn).distinct()
+				)
+			)
+		)
+	).run()[0][0] or 0
diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html
index 6c59a96..97269dc 100644
--- a/erpnext/templates/pages/order.html
+++ b/erpnext/templates/pages/order.html
@@ -40,7 +40,7 @@
 					<p>
 						<a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
 							class="btn btn-primary btn-sm" id="pay-for-order">
-							{{ _("Pay") }} {{doc.get_formatted("grand_total") }}
+							{{ _("Pay") }} {{ pay_amount }}
 						</a>
 					</p>
 				</div>
diff --git a/erpnext/templates/pages/order.py b/erpnext/templates/pages/order.py
index 21d4b86..41b1384 100644
--- a/erpnext/templates/pages/order.py
+++ b/erpnext/templates/pages/order.py
@@ -4,6 +4,8 @@
 import frappe
 from frappe import _
 
+from erpnext.accounts.doctype.payment_request.payment_request import get_amount
+
 
 def get_context(context):
 	context.no_cache = 1
@@ -48,10 +50,7 @@
 			)
 			context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points"))
 
-	context.show_pay_button = (
-		"payments" in frappe.get_installed_apps()
-		and frappe.db.get_single_value("Buying Settings", "show_pay_button")
-	)
+	context.show_pay_button, context.pay_amount = get_payment_details(context.doc)
 	context.show_make_pi_button = False
 	if context.doc.get("supplier"):
 		# show Make Purchase Invoice button based on permission
@@ -64,3 +63,14 @@
 		fields=["name", "file_name", "file_url", "is_private"],
 		filters={"attached_to_name": dn, "attached_to_doctype": dt, "is_private": 0},
 	)
+
+
+def get_payment_details(doc):
+	show_pay_button, amount = (
+		"payments" in frappe.get_installed_apps()
+		and frappe.db.get_single_value("Buying Settings", "show_pay_button")
+	), 0
+	if not show_pay_button:
+		return show_pay_button, amount
+	amount = get_amount(doc)
+	return bool(amount), amount