feat: Allowed multiple payment requests against a reference document (#18988)
This commit is contained in:
parent
7bcb24efbf
commit
ff09b412f4
@ -20,7 +20,7 @@ class PaymentRequest(Document):
|
|||||||
if self.get("__islocal"):
|
if self.get("__islocal"):
|
||||||
self.status = 'Draft'
|
self.status = 'Draft'
|
||||||
self.validate_reference_document()
|
self.validate_reference_document()
|
||||||
self.validate_payment_request()
|
self.validate_payment_request_amount()
|
||||||
self.validate_currency()
|
self.validate_currency()
|
||||||
self.validate_subscription_details()
|
self.validate_subscription_details()
|
||||||
|
|
||||||
@ -28,10 +28,19 @@ class PaymentRequest(Document):
|
|||||||
if not self.reference_doctype or not self.reference_name:
|
if not self.reference_doctype or not self.reference_name:
|
||||||
frappe.throw(_("To create a Payment Request reference document is required"))
|
frappe.throw(_("To create a Payment Request reference document is required"))
|
||||||
|
|
||||||
def validate_payment_request(self):
|
def validate_payment_request_amount(self):
|
||||||
if frappe.db.get_value("Payment Request", {"reference_name": self.reference_name,
|
existing_payment_request_amount = \
|
||||||
"name": ("!=", self.name), "status": ("not in", ["Initiated", "Paid"]), "docstatus": 1}, "name"):
|
get_existing_payment_request_amount(self.reference_doctype, self.reference_name)
|
||||||
frappe.throw(_("Payment Request already exists {0}".format(self.reference_name)))
|
|
||||||
|
if existing_payment_request_amount:
|
||||||
|
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
|
||||||
|
if (hasattr(ref_doc, "order_type") \
|
||||||
|
and getattr(ref_doc, "order_type") != "Shopping Cart"):
|
||||||
|
ref_amount = get_amount(ref_doc)
|
||||||
|
|
||||||
|
if existing_payment_request_amount + flt(self.grand_total)> ref_amount:
|
||||||
|
frappe.throw(_("Total Payment Request amount cannot be greater than {0} amount"
|
||||||
|
.format(self.reference_doctype)))
|
||||||
|
|
||||||
def validate_currency(self):
|
def validate_currency(self):
|
||||||
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
|
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
|
||||||
@ -271,7 +280,7 @@ def make_payment_request(**args):
|
|||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|
||||||
ref_doc = frappe.get_doc(args.dt, args.dn)
|
ref_doc = frappe.get_doc(args.dt, args.dn)
|
||||||
grand_total = get_amount(ref_doc, args.dt)
|
grand_total = get_amount(ref_doc)
|
||||||
if args.loyalty_points and args.dt == "Sales Order":
|
if args.loyalty_points and args.dt == "Sales Order":
|
||||||
from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
|
from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points
|
||||||
loyalty_amount = validate_loyalty_points(ref_doc, int(args.loyalty_points))
|
loyalty_amount = validate_loyalty_points(ref_doc, int(args.loyalty_points))
|
||||||
@ -281,17 +290,25 @@ def make_payment_request(**args):
|
|||||||
|
|
||||||
gateway_account = get_gateway_details(args) or frappe._dict()
|
gateway_account = get_gateway_details(args) or frappe._dict()
|
||||||
|
|
||||||
existing_payment_request = frappe.db.get_value("Payment Request",
|
|
||||||
{"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": ["!=", 2]})
|
|
||||||
|
|
||||||
bank_account = (get_party_bank_account(args.get('party_type'), args.get('party'))
|
bank_account = (get_party_bank_account(args.get('party_type'), args.get('party'))
|
||||||
if args.get('party_type') else '')
|
if args.get('party_type') else '')
|
||||||
|
|
||||||
|
existing_payment_request = None
|
||||||
|
if args.order_type == "Shopping Cart":
|
||||||
|
existing_payment_request = frappe.db.get_value("Payment Request",
|
||||||
|
{"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": ("!=", 2)})
|
||||||
|
|
||||||
if existing_payment_request:
|
if existing_payment_request:
|
||||||
frappe.db.set_value("Payment Request", existing_payment_request, "grand_total", grand_total, update_modified=False)
|
frappe.db.set_value("Payment Request", existing_payment_request, "grand_total", grand_total, update_modified=False)
|
||||||
pr = frappe.get_doc("Payment Request", existing_payment_request)
|
pr = frappe.get_doc("Payment Request", existing_payment_request)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
if args.order_type != "Shopping Cart":
|
||||||
|
existing_payment_request_amount = \
|
||||||
|
get_existing_payment_request_amount(args.dt, args.dn)
|
||||||
|
|
||||||
|
if existing_payment_request_amount:
|
||||||
|
grand_total -= existing_payment_request_amount
|
||||||
|
|
||||||
pr = frappe.new_doc("Payment Request")
|
pr = frappe.new_doc("Payment Request")
|
||||||
pr.update({
|
pr.update({
|
||||||
"payment_gateway_account": gateway_account.get("name"),
|
"payment_gateway_account": gateway_account.get("name"),
|
||||||
@ -327,8 +344,9 @@ def make_payment_request(**args):
|
|||||||
|
|
||||||
return pr.as_dict()
|
return pr.as_dict()
|
||||||
|
|
||||||
def get_amount(ref_doc, dt):
|
def get_amount(ref_doc):
|
||||||
"""get amount based on doctype"""
|
"""get amount based on doctype"""
|
||||||
|
dt = ref_doc.doctype
|
||||||
if dt in ["Sales Order", "Purchase Order"]:
|
if dt in ["Sales Order", "Purchase Order"]:
|
||||||
grand_total = flt(ref_doc.grand_total) - flt(ref_doc.advance_paid)
|
grand_total = flt(ref_doc.grand_total) - flt(ref_doc.advance_paid)
|
||||||
|
|
||||||
@ -347,6 +365,17 @@ def get_amount(ref_doc, dt):
|
|||||||
else:
|
else:
|
||||||
frappe.throw(_("Payment Entry is already created"))
|
frappe.throw(_("Payment Entry is already created"))
|
||||||
|
|
||||||
|
def get_existing_payment_request_amount(ref_dt, ref_dn):
|
||||||
|
existing_payment_request_amount = frappe.db.sql("""
|
||||||
|
select sum(grand_total)
|
||||||
|
from `tabPayment Request`
|
||||||
|
where
|
||||||
|
reference_doctype = %s
|
||||||
|
and reference_name = %s
|
||||||
|
and docstatus = 1
|
||||||
|
""", (ref_dt, ref_dn))
|
||||||
|
return flt(existing_payment_request_amount[0][0]) if existing_payment_request_amount else 0
|
||||||
|
|
||||||
def get_gateway_details(args):
|
def get_gateway_details(args):
|
||||||
"""return gateway and payment account of default payment gateway"""
|
"""return gateway and payment account of default payment gateway"""
|
||||||
if args.get("payment_gateway"):
|
if args.get("payment_gateway"):
|
||||||
|
@ -100,3 +100,23 @@ class TestPaymentRequest(unittest.TestCase):
|
|||||||
self.assertEqual(expected_gle[gle.account][1], gle.debit)
|
self.assertEqual(expected_gle[gle.account][1], gle.debit)
|
||||||
self.assertEqual(expected_gle[gle.account][2], gle.credit)
|
self.assertEqual(expected_gle[gle.account][2], gle.credit)
|
||||||
self.assertEqual(expected_gle[gle.account][3], gle.against_voucher)
|
self.assertEqual(expected_gle[gle.account][3], gle.against_voucher)
|
||||||
|
|
||||||
|
def test_multiple_payment_entries_against_sales_order(self):
|
||||||
|
# Make Sales Order, grand_total = 1000
|
||||||
|
so = make_sales_order()
|
||||||
|
|
||||||
|
# Payment Request amount = 200
|
||||||
|
pr1 = make_payment_request(dt="Sales Order", dn=so.name,
|
||||||
|
recipient_id="nabin@erpnext.com", return_doc=1)
|
||||||
|
pr1.grand_total = 200
|
||||||
|
pr1.submit()
|
||||||
|
|
||||||
|
# Make a 2nd Payment Request
|
||||||
|
pr2 = make_payment_request(dt="Sales Order", dn=so.name,
|
||||||
|
recipient_id="nabin@erpnext.com", return_doc=1)
|
||||||
|
|
||||||
|
self.assertEqual(pr2.grand_total, 800)
|
||||||
|
|
||||||
|
# Try to make Payment Request more than SO amount, should give validation
|
||||||
|
pr2.grand_total = 900
|
||||||
|
self.assertRaises(frappe.ValidationError, pr2.save)
|
Loading…
Reference in New Issue
Block a user