From 1b81db4754883486e5c993ba25e6063b81501b1e Mon Sep 17 00:00:00 2001 From: Vishnu Priya Baskaran <145791817+ervishnucs@users.noreply.github.com> Date: Wed, 26 Aug 2026 11:47:04 +0530 Subject: [PATCH] fix/payment-request-subscription-plans-population (#57494) * fix(payment-request): populate subscription plans * test: add coverage for subscription plans in payment request --------- Co-authored-by: Dharanidharan2813 --- .../payment_request/payment_request.js | 1 + .../payment_request/payment_request.py | 46 ++++++++++----- .../payment_request/test_payment_request.py | 57 +++++++++++++++++++ 3 files changed, 90 insertions(+), 14 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.js b/erpnext/accounts/doctype/payment_request/payment_request.js index 31963793da2..60b191ebd8d 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.js +++ b/erpnext/accounts/doctype/payment_request/payment_request.js @@ -92,6 +92,7 @@ frappe.ui.form.on("Payment Request", "is_a_subscription", function (frm) { freeze: true, callback: function (data) { if (!data.exc) { + frm.clear_table("subscription_plans"); $.each(data.message || [], function (i, v) { var d = frappe.model.add_child( frm.doc, diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index e415be096c9..d0d176f20d7 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -874,7 +874,7 @@ def make_payment_request(**args): if not party_account_currency: party_account = get_party_account(party_type, ref_doc.get(party_type.lower()), ref_doc.company) party_account_currency = get_account_currency(party_account) - + is_a_subscription = 1 if ref_doc.get("subscription") else 0 pr.update( { "payment_gateway_account": gateway_account.get("name"), @@ -906,12 +906,25 @@ def make_payment_request(**args): or gateway_account.get("payment_channel", "Email") != "Email" ), "phone_number": args.get("phone_number") if args.get("phone_number") else None, + "is_a_subscription": is_a_subscription, } ) if selected_payment_schedules: apply_payment_references(pr, payment_reference) + if is_a_subscription: + values = get_subscription_details(ref_doc.doctype, ref_doc.name) + pr.set( + "subscription_plans", + [ + { + "plan": row.plan, + "qty": row.qty, + } + for row in values + ], + ) # Dimensions pr.update( { @@ -1226,19 +1239,24 @@ def get_dummy_message(doc): @frappe.whitelist() def get_subscription_details(reference_doctype: str, reference_name: str): - if reference_doctype == "Sales Invoice": - subscriptions = frappe.get_all( - "Subscription Invoice", - filters={"invoice": reference_name}, - fields=["parent as sub_name"], - order_by="", # match the original query (no ORDER BY); avoid get_all's default sort - ) - subscription_plans = [] - for subscription in subscriptions: - plans = frappe.get_doc("Subscription", subscription.sub_name).plans - for plan in plans: - subscription_plans.append(plan) - return subscription_plans + if reference_doctype != "Sales Invoice": + return [] + + subscription = frappe.db.get_value("Sales Invoice", reference_name, "subscription") + + if not subscription: + return [] + + subscription_plan = frappe.get_all( + "Subscription Plan Detail", + filters={"parent": subscription, "parenttype": "Subscription", "parentfield": "plans"}, + fields=[ + "plan", + "qty", + ], + ) + + return subscription_plan @frappe.whitelist() diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py index 440933360d1..851f7d41e71 100644 --- a/erpnext/accounts/doctype/payment_request/test_payment_request.py +++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py @@ -14,9 +14,15 @@ from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_pay from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice +from erpnext.accounts.doctype.subscription.test_subscription import ( + create_plan, + create_subscription, + make_plans, +) from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.setup.utils import get_exchange_rate +from erpnext.stock.doctype.item.test_item import make_item from erpnext.tests.utils import ERPNextTestSuite PAYMENT_URL = "https://example.com/payment" @@ -2009,3 +2015,54 @@ class TestPaymentRequestV2Gateway(ERPNextTestSuite): call_kwargs = mock_log_error.call_args self.assertIn("Payment Initialization Failed", str(call_kwargs)) self.assertIn("_Test Gateway", str(call_kwargs)) + + def test_payment_request_with_subscription(self): + make_plans() + + subscription_plan = frappe.get_doc("Subscription Plan", "_Test Plan Name") + subscription_plan.payment_gateway = "_Test Gateway - INR - _TC" + subscription_plan.save() + + subscription = create_subscription( + plans=[{"plan": "_Test Plan Name", "qty": 1}], + start_date=nowdate(), + generate_invoice_at="Prepaid (bill at period start)", + submit_invoice=1, + ) + invoice_name = frappe.get_value( + "Sales Invoice", + { + "subscription": subscription.name, + "docstatus": 1, + "is_return": 0, + }, + "name", + order_by="from_date asc", + ) + + payment_request = make_payment_request( + dt="Sales Invoice", + dn=invoice_name, + recipient_id="test@example.com", + ) + + self.assertEqual(payment_request.is_a_subscription, 1) + self.assertEqual(len(payment_request.subscription_plans), 1) + + subscription_plan = payment_request.subscription_plans[0] + self.assertEqual(subscription_plan.plan, "_Test Plan Name") + self.assertEqual(subscription_plan.qty, 1) + self.assertEqual(payment_request.reference_doctype, "Sales Invoice") + self.assertEqual(payment_request.reference_name, invoice_name) + + def test_payment_request_without_subscription(self): + si = create_sales_invoice() + payment_request = make_payment_request( + dt="Sales Invoice", + dn=si.name, + recipient_id="test@example.com", + ) + self.assertEqual(payment_request.is_a_subscription, 0) + self.assertEqual(len(payment_request.subscription_plans), 0) + self.assertEqual(payment_request.reference_doctype, "Sales Invoice") + self.assertEqual(payment_request.reference_name, si.name)