Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: allow multiple payment requests through customer portal #43689

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 77 additions & 6 deletions erpnext/accounts/doctype/payment_request/payment_request.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import json

import frappe
from frappe import _
from frappe import _, qb
from frappe.model.document import Document
from frappe.query_builder.functions import Sum
from frappe.utils import flt, nowdate
Expand Down Expand Up @@ -563,11 +563,24 @@ def make_payment_request(**args):
# fetches existing payment request `grand_total` amount
existing_payment_request_amount = get_existing_payment_request_amount(ref_doc.doctype, ref_doc.name)

if existing_payment_request_amount:
def validate_and_calculate_grand_total(grand_total, existing_payment_request_amount):
grand_total -= existing_payment_request_amount

if not grand_total:
frappe.throw(_("Payment Request is already created"))
return grand_total

if existing_payment_request_amount:
if args.order_type == "Shopping Cart":
# If Payment Request is in an advanced stage, then create for remaining amount.
if get_existing_payment_request_amount(
ref_doc.doctype, ref_doc.name, ["Initiated", "Partially Paid", "Payment Ordered", "Paid"]
):
grand_total = validate_and_calculate_grand_total(grand_total, existing_payment_request_amount)
else:
# If PR's are processed, cancel all of them.
cancel_old_payment_requests(ref_doc.doctype, ref_doc.name)
else:
grand_total = validate_and_calculate_grand_total(grand_total, existing_payment_request_amount)

if draft_payment_request:
frappe.db.set_value(
Expand Down Expand Up @@ -683,21 +696,65 @@ def get_amount(ref_doc, payment_account=None):
frappe.throw(_("Payment Entry is already created"))


def get_existing_payment_request_amount(ref_dt, ref_dn):
def get_irequest_status(payment_requests: None | list = None) -> list:
IR = frappe.qb.DocType("Integration Request")
res = []
if payment_requests:
res = (
frappe.qb.from_(IR)
.select(IR.name)
.where(IR.reference_doctype.eq("Payment Request"))
.where(IR.reference_docname.isin(payment_requests))
.where(IR.status.isin(["Authorized", "Completed"]))
.run(as_dict=True)
)
return res


def cancel_old_payment_requests(ref_dt, ref_dn):
PR = frappe.qb.DocType("Payment Request")

if res := (
frappe.qb.from_(PR)
.select(PR.name)
.where(PR.reference_doctype == ref_dt)
.where(PR.reference_name == ref_dn)
.where(PR.docstatus == 1)
.where(PR.status.isin(["Draft", "Requested"]))
.run(as_dict=True)
):
if get_irequest_status([x.name for x in res]):
frappe.throw(_("Another Payment Request is already processed"))
else:
for x in res:
doc = frappe.get_doc("Payment Request", x.name)
doc.flags.ignore_permissions = True
doc.cancel()

if ireqs := get_irequests_of_payment_request(doc.name):
for ireq in ireqs:
frappe.db.set_value("Integration Request", ireq.name, "status", "Cancelled")


def get_existing_payment_request_amount(ref_dt, ref_dn, statuses: list | None = None) -> list:
"""
Return the total amount of Payment Requests against a reference document.
"""
PR = frappe.qb.DocType("Payment Request")

response = (
query = (
frappe.qb.from_(PR)
.select(Sum(PR.grand_total))
.where(PR.reference_doctype == ref_dt)
.where(PR.reference_name == ref_dn)
.where(PR.docstatus == 1)
.run()
)

if statuses:
query = query.where(PR.status.isin(statuses))

response = query.run()

return response[0][0] if response[0] else 0


Expand Down Expand Up @@ -915,3 +972,17 @@ def get_open_payment_requests_query(doctype, txt, searchfield, start, page_len,
)
for pr in open_payment_requests
]


def get_irequests_of_payment_request(doc: str | None = None) -> list:
res = []
if doc:
res = frappe.db.get_all(
"Integration Request",
{
"reference_doctype": "Payment Request",
"reference_docname": doc,
"status": "Queued",
},
)
return res
Loading