diff --git a/erpnext/accounts/doctype/payment_gateway_account/__init__.py b/erpnext/accounts/doctype/payment_gateway_account/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.js b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.js deleted file mode 100644 index ab9a50f8285a..000000000000 --- a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.js +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - -frappe.ui.form.on("Payment Gateway Account", { - refresh(frm) { - erpnext.utils.check_payments_app(); - if (!frm.doc.__islocal) { - frm.set_df_property("payment_gateway", "read_only", 1); - } - }, - - setup(frm) { - frm.set_query("payment_account", function () { - return { - filters: { - company: frm.doc.company, - }, - }; - }); - }, -}); diff --git a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.json b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.json deleted file mode 100644 index cb258a89741d..000000000000 --- a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "actions": [], - "creation": "2015-12-23 21:31:52.699821", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "payment_gateway", - "payment_channel", - "company", - "is_default", - "column_break_4", - "payment_account", - "currency", - "payment_request_message", - "message", - "message_examples" - ], - "fields": [ - { - "fieldname": "payment_gateway", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Payment Gateway", - "options": "Payment Gateway", - "reqd": 1 - }, - { - "default": "0", - "fieldname": "is_default", - "fieldtype": "Check", - "label": "Is Default" - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "fieldname": "payment_account", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Payment Account", - "options": "Account", - "reqd": 1 - }, - { - "fetch_from": "payment_account.account_currency", - "fieldname": "currency", - "fieldtype": "Read Only", - "label": "Currency" - }, - { - "depends_on": "eval: doc.payment_channel == 'Email' || (!doc.payment_channel)", - "fieldname": "payment_request_message", - "fieldtype": "Section Break" - }, - { - "default": "Please click on the link below to make your payment", - "fieldname": "message", - "fieldtype": "Small Text", - "label": "Default Payment Request Message" - }, - { - "fieldname": "message_examples", - "fieldtype": "HTML", - "label": "Message Examples", - "options": "
Message Example
\n\n<p> Thank You for being a part of {{ doc.company }}! We hope you are enjoying the service.</p>\n\n<p> Please find enclosed the E Bill statement. The outstanding amount is {{ doc.grand_total }}.</p>\n\n<p> We don't want you to be spending time running around in order to pay for your Bill.
After all, life is beautiful and the time you have in hand should be spent to enjoy it!
So here are our little ways to help you get more time for life! </p>\n\n<a href=\"{{ payment_url }}\"> click here to pay </a>\n\n
\n" - }, - { - "default": "Email", - "fieldname": "payment_channel", - "fieldtype": "Select", - "label": "Payment Channel", - "options": "\nEmail\nPhone\nOther" - }, - { - "fieldname": "company", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Company", - "options": "Company", - "print_hide": 1, - "remember_last_selected_value": 1, - "reqd": 1 - } - ], - "index_web_pages_for_search": 1, - "links": [], - "modified": "2025-07-14 16:49:55.210352", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Payment Gateway Account", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts Manager", - "share": 1, - "write": 1 - } - ], - "row_format": "Dynamic", - "sort_field": "creation", - "sort_order": "DESC", - "states": [] -} diff --git a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.py b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.py deleted file mode 100644 index 7c58949be8be..000000000000 --- a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import frappe -from frappe.model.document import Document - - -class PaymentGatewayAccount(Document): - # begin: auto-generated types - # This code is auto-generated. Do not modify anything in this block. - - from typing import TYPE_CHECKING - - if TYPE_CHECKING: - from frappe.types import DF - - company: DF.Link - currency: DF.ReadOnly | None - is_default: DF.Check - message: DF.SmallText | None - payment_account: DF.Link - payment_channel: DF.Literal["", "Email", "Phone"] - payment_gateway: DF.Link - # end: auto-generated types - - def autoname(self): - abbr = frappe.db.get_value("Company", self.company, "abbr") - self.name = self.payment_gateway + " - " + self.currency + " - " + abbr - - def validate(self): - self.currency = frappe.get_cached_value("Account", self.payment_account, "account_currency") - - self.update_default_payment_gateway() - self.set_as_default_if_not_set() - - def update_default_payment_gateway(self): - if self.is_default: - frappe.db.set_value( - "Payment Gateway Account", - {"is_default": 1, "name": ["!=", self.name], "company": self.company}, - "is_default", - 0, - ) - - def set_as_default_if_not_set(self): - if not frappe.db.exists( - "Payment Gateway Account", {"is_default": 1, "name": ("!=", self.name), "company": self.company} - ): - self.is_default = 1 diff --git a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account_dashboard.py b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account_dashboard.py deleted file mode 100644 index d0aaee88350c..000000000000 --- a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account_dashboard.py +++ /dev/null @@ -1,6 +0,0 @@ -def get_data(): - return { - "fieldname": "payment_gateway_account", - "non_standard_fieldnames": {"Subscription Plan": "payment_gateway"}, - "transactions": [{"items": ["Payment Request"]}, {"items": ["Subscription Plan"]}], - } diff --git a/erpnext/accounts/doctype/payment_gateway_account/test_payment_gateway_account.py b/erpnext/accounts/doctype/payment_gateway_account/test_payment_gateway_account.py deleted file mode 100644 index fe70292144f0..000000000000 --- a/erpnext/accounts/doctype/payment_gateway_account/test_payment_gateway_account.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -from erpnext.tests.utils import ERPNextTestSuite - - -class TestPaymentGatewayAccount(ERPNextTestSuite): - pass diff --git a/erpnext/accounts/doctype/payment_request/payment_request.js b/erpnext/accounts/doctype/payment_request/payment_request.js index 9696a6bfc2ae..76b5e877ed7a 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.js +++ b/erpnext/accounts/doctype/payment_request/payment_request.js @@ -1,7 +1,3 @@ -cur_frm.add_fetch("payment_gateway_account", "payment_account", "payment_account"); -cur_frm.add_fetch("payment_gateway_account", "payment_gateway", "payment_gateway"); -cur_frm.add_fetch("payment_gateway_account", "message", "message"); - frappe.ui.form.on("Payment Request", { setup: function (frm) { frm.set_query("party_type", function () { @@ -10,13 +6,18 @@ frappe.ui.form.on("Payment Request", { }; }); - frm.set_query("payment_gateway_account", function () { - return { - filters: { - company: frm.doc.company, - }, - }; - }); + if (frm.fields_dict.payment_gateway_account) { + frm.set_query("payment_gateway_account", function () { + return { + filters: { + parent: frm.doc.payment_gateway, + parenttype: "Payment Gateway", + }, + }; + }); + frm.set_df_property("payment_account", "read_only", 1); + frm.add_fetch("payment_gateway_account", "payment_account", "payment_account"); + } }, }); @@ -80,7 +81,12 @@ frappe.ui.form.on("Payment Request", "refresh", function (frm) { }); frappe.ui.form.on("Payment Request", "is_a_subscription", function (frm) { - frm.toggle_reqd("payment_gateway_account", frm.doc.is_a_subscription); + if (frm.fields_dict.payment_gateway) { + frm.toggle_reqd("payment_gateway", frm.doc.is_a_subscription); + } + if (frm.fields_dict.payment_gateway_account) { + frm.toggle_reqd("payment_gateway_account", frm.doc.is_a_subscription); + } frm.toggle_reqd("subscription_plans", frm.doc.is_a_subscription); if (frm.doc.is_a_subscription && frm.doc.reference_doctype && frm.doc.reference_name) { diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json index 17d8b74aa14e..58e160a617dc 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.json +++ b/erpnext/accounts/doctype/payment_request/payment_request.json @@ -19,6 +19,7 @@ "column_break_4", "reference_doctype", "reference_name", + "make_sales_invoice", "payment_reference_section", "payment_reference", "transaction_details", @@ -43,28 +44,22 @@ "cost_center", "dimension_col_break", "project", - "recipient_and_message", + "payment_details_section", + "payment_account", + "recipient_details", "print_format", "email_to", "subject", "column_break_9", - "payment_gateway_account", "status", - "make_sales_invoice", - "section_break_10", + "message_details", "message", "message_examples", "mute_email", - "section_break_7", - "payment_gateway", - "payment_account", - "payment_channel", - "payment_order", + "section_break_jfix", "amended_from", - "column_break_pnyv", - "payment_url", - "column_break_iiuv", - "phone_number" + "column_break_ruax", + "payment_order" ], "fields": [ { @@ -270,13 +265,6 @@ "options": "Project" }, { - "depends_on": "eval: doc.payment_request_type == 'Inward'", - "fieldname": "recipient_and_message", - "fieldtype": "Section Break", - "label": "Recipient Message And Payment Details" - }, - { - "depends_on": "eval: doc.payment_channel == \"Email\" || (!doc.payment_channel)", "fieldname": "print_format", "fieldtype": "Select", "label": "Print Format" @@ -288,7 +276,6 @@ "label": "To" }, { - "depends_on": "eval: doc.payment_channel == \"Email\" || (!doc.payment_channel)", "fieldname": "subject", "fieldtype": "Data", "in_global_search": 1, @@ -298,13 +285,6 @@ "fieldname": "column_break_9", "fieldtype": "Column Break" }, - { - "depends_on": "eval: doc.payment_request_type == 'Inward'", - "fieldname": "payment_gateway_account", - "fieldtype": "Link", - "label": "Payment Gateway Account", - "options": "Payment Gateway Account" - }, { "default": "Draft", "fieldname": "status", @@ -325,18 +305,12 @@ "read_only": 1 }, { - "depends_on": "eval: doc.payment_request_type == 'Inward' || doc.payment_channel == \"Email\" || (!doc.payment_channel)", - "fieldname": "section_break_10", - "fieldtype": "Section Break" - }, - { - "depends_on": "eval: doc.payment_channel == \"Email\" || (!doc.payment_channel)", + "fetch_from": "payment_gateway_account.message", "fieldname": "message", "fieldtype": "Text", "label": "Message" }, { - "depends_on": "eval: doc.payment_channel == \"Email\" || (!doc.payment_channel)", "fieldname": "message_examples", "fieldtype": "HTML", "label": "Message Examples", @@ -354,44 +328,6 @@ "read_only": 1, "report_hide": 1 }, - { - "fieldname": "payment_url", - "fieldtype": "Data", - "label": "Payment URL", - "length": 500, - "options": "URL", - "read_only": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "doc.payment_gateway_account", - "depends_on": "eval: doc.payment_request_type == 'Inward'", - "fieldname": "section_break_7", - "fieldtype": "Section Break", - "label": "Payment Gateway Details" - }, - { - "fetch_from": "payment_gateway_account.payment_gateway", - "fieldname": "payment_gateway", - "fieldtype": "Read Only", - "label": "Payment Gateway" - }, - { - "fetch_from": "payment_gateway_account.payment_account", - "fieldname": "payment_account", - "fieldtype": "Read Only", - "label": "Payment Account", - "read_only": 1 - }, - { - "depends_on": "eval: doc.payment_channel==\"Phone\"", - "fetch_from": "payment_gateway_account.payment_channel", - "fieldname": "payment_channel", - "fieldtype": "Select", - "label": "Payment Channel", - "options": "\nEmail\nPhone\nOther", - "read_only": 1 - }, { "fieldname": "payment_order", "fieldtype": "Link", @@ -435,10 +371,6 @@ "options": "Company", "read_only": 1 }, - { - "fieldname": "column_break_pnyv", - "fieldtype": "Column Break" - }, { "fieldname": "party_account_currency", "fieldtype": "Link", @@ -452,15 +384,6 @@ "label": "Party Name", "read_only": 1 }, - { - "fieldname": "column_break_iiuv", - "fieldtype": "Column Break" - }, - { - "fieldname": "phone_number", - "fieldtype": "Data", - "label": "Phone Number" - }, { "fieldname": "payment_reference_section", "fieldtype": "Section Break" @@ -471,6 +394,37 @@ "label": "Payment Reference", "options": "Payment Reference", "read_only": 1 + }, + { + "fieldname": "section_break_jfix", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_ruax", + "fieldtype": "Column Break" + }, + { + "depends_on": "eval: !doc.payment_channel ? doc.payment_request_type == \"Inward\" : doc.payment_channel == \"Email\"", + "fieldname": "recipient_details", + "fieldtype": "Section Break", + "label": "Recipient Details" + }, + { + "depends_on": "eval: !doc.payment_channel ? doc.payment_request_type == \"Inward\" : doc.payment_channel == \"Email\"", + "fieldname": "message_details", + "fieldtype": "Section Break", + "label": "Message Details" + }, + { + "fieldname": "payment_details_section", + "fieldtype": "Section Break", + "label": "Payment Details" + }, + { + "fieldname": "payment_account", + "fieldtype": "Link", + "label": "Payment Account", + "options": "Account" } ], "grid_page_length": 50, @@ -478,7 +432,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2026-02-27 19:11:03.308896", + "modified": "2026-04-29 20:28:38.207170", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Request", diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index c870f0b55d86..7a11ad251d87 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -74,15 +74,10 @@ class PaymentRequest(Document): party_account_currency: DF.Link | None party_name: DF.Data | None party_type: DF.Link | None - payment_account: DF.ReadOnly | None - payment_channel: DF.Literal["", "Email", "Phone", "Other"] - payment_gateway: DF.ReadOnly | None - payment_gateway_account: DF.Link | None + payment_account: DF.Link | None payment_order: DF.Link | None payment_reference: DF.Table[PaymentReference] payment_request_type: DF.Literal["Outward", "Inward"] - payment_url: DF.Data | None - phone_number: DF.Data | None print_format: DF.Literal[None] project: DF.Link | None reference_doctype: DF.Link | None @@ -173,16 +168,19 @@ def validate_currency(self): if self.payment_account and ref_doc.currency != frappe.get_cached_value( "Account", self.payment_account, "account_currency" ): - frappe.throw(_("Transaction currency must be same as Payment Gateway currency")) + frappe.throw(_("Transaction currency must be same as Payment Account currency")) def validate_subscription_details(self): + if "payments" not in frappe.get_installed_apps(): + return + if self.is_a_subscription: amount = 0 for subscription_plan in self.subscription_plans: - payment_gateway = frappe.db.get_value( - "Subscription Plan", subscription_plan.plan, "payment_gateway" + payment_gateway_account = frappe.db.get_value( + "Subscription Plan", subscription_plan.plan, "payment_gateway_account" ) - if payment_gateway != self.payment_gateway_account: + if payment_gateway_account != self.payment_gateway_account: frappe.throw( _( "The payment gateway account in plan {0} is different from the payment gateway account in this payment request" @@ -228,7 +226,7 @@ def before_submit(self): self.status = "Requested" if self.payment_request_type == "Inward": - if self.payment_channel == "Phone": + if hasattr(self, "payment_channel") and self.payment_channel == "Phone": self.request_phone_payment() else: self.set_payment_request_url() @@ -240,6 +238,9 @@ def on_submit(self): self.update_reference_advance_payment_status() def request_phone_payment(self): + if "payments" not in frappe.get_installed_apps(): + return + controller = _get_payment_gateway_controller(self.payment_gateway) request_amount = self.get_request_amount() @@ -288,6 +289,9 @@ def make_invoice(self): si.submit() def payment_gateway_validation(self): + if "payments" not in frappe.get_installed_apps(): + return False + try: controller = _get_payment_gateway_controller(self.payment_gateway) if hasattr(controller, "on_payment_request_submission"): @@ -298,10 +302,16 @@ def payment_gateway_validation(self): return False def set_payment_request_url(self): + if "payments" not in frappe.get_installed_apps(): + return + if self.payment_account and self.payment_gateway and self.payment_gateway_validation(): self.payment_url = self.get_payment_url() def get_payment_url(self): + if "payments" not in frappe.get_installed_apps(): + return False + if self.reference_doctype != "Fees": data = frappe.db.get_value( self.reference_doctype, self.reference_name, ["company", "customer_name"], as_dict=1 @@ -334,7 +344,7 @@ def get_payment_url(self): ) def set_as_paid(self): - if self.payment_channel == "Phone": + if hasattr(self, "payment_channel") and self.payment_channel == "Phone": self.db_set({"status": "Paid", "outstanding_amount": 0}) else: @@ -452,7 +462,7 @@ def get_message(self): context = { "doc": frappe.get_doc(self.reference_doctype, self.reference_name), - "payment_url": self.payment_url, + "payment_url": self.payment_url if hasattr(self, "payment_url") else "", "payment_request": self, } @@ -576,7 +586,7 @@ def make_payment_request(**args): if not args.get("company"): args.company = ref_doc.company - gateway_account = get_gateway_details(args) or frappe._dict() + gateway_account = get_payment_gateway_account_details(args) or frappe._dict() # Schedule-based PRs are allowed only if no Payment Entry exists for this document. # Any existing Payment Entry forces legacy (amount-based) flow. @@ -630,7 +640,9 @@ def make_payment_request(**args): if selected_payment_schedules and not has_payment_entry: grand_total = sum(row.get("payment_amount") for row in selected_payment_schedules) else: - grand_total = get_amount(ref_doc, gateway_account.get("payment_account")) + grand_total = get_amount( + ref_doc, args.get("payment_account") or gateway_account.get("payment_account") + ) if not grand_total: frappe.throw(_("Payment Entry is already created")) @@ -696,10 +708,6 @@ def validate_and_calculate_grand_total(grand_total, existing_payment_request_amo pr.update( { - "payment_gateway_account": gateway_account.get("name"), - "payment_gateway": gateway_account.get("payment_gateway"), - "payment_account": gateway_account.get("payment_account"), - "payment_channel": gateway_account.get("payment_channel"), "payment_request_type": args.get("payment_request_type"), "currency": ref_doc.currency, "party_account_currency": party_account_currency, @@ -724,10 +732,21 @@ def validate_and_calculate_grand_total(grand_total, existing_payment_request_amo or args.order_type == "Shopping Cart" # compat for webshop app or gateway_account.get("payment_channel", "Email") != "Email" ), - "phone_number": args.get("phone_number") if args.get("phone_number") else None, + "payment_account": args.get("payment_account") or gateway_account.get("payment_account"), } ) + # specific fields to payments app + if "payments" in frappe.get_installed_apps(): + pr.update( + { + "payment_gateway": gateway_account.get("payment_gateway"), + "payment_gateway_account": gateway_account.get("gateway_name"), + "payment_channel": gateway_account.get("payment_channel"), + "phone_number": args.get("phone_number"), + } + ) + if selected_payment_schedules: apply_payment_references(pr, payment_reference) @@ -920,19 +939,19 @@ def get_existing_payment_request_amount(ref_doc, statuses: list | None = None) - return os_amount_in_transaction_currency -def get_gateway_details(args): # nosemgrep +def get_payment_gateway_account_details(args): # nosemgrep """ - Return gateway and payment account of default payment gateway + Fetch details of the default or specified Payment Gateway Account """ - gateway_account = args.get("payment_gateway_account", {"is_default": 1, "company": args.company}) - return get_payment_gateway_account(gateway_account) + if "payments" not in frappe.get_installed_apps(): + return + filter = args.get("payment_gateway_account", {"is_default": 1, "company": args.company}) -def get_payment_gateway_account(filter): return frappe.db.get_value( "Payment Gateway Account", filter, - ["name", "payment_gateway", "payment_account", "payment_channel", "message"], + ["name", "payment_account", "payment_channel", "message"], as_dict=1, ) diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json index d8f57e21cdb6..15ab0b72ce34 100644 --- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json +++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json @@ -23,7 +23,6 @@ "payment_plan_section", "product_price_id", "column_break_16", - "payment_gateway", "accounting_dimensions_section", "cost_center", "dimension_col_break" @@ -120,12 +119,6 @@ "fieldname": "column_break_16", "fieldtype": "Column Break" }, - { - "fieldname": "payment_gateway", - "fieldtype": "Link", - "label": "Payment Gateway", - "options": "Payment Gateway Account" - }, { "collapsible": 1, "fieldname": "accounting_dimensions_section", @@ -149,7 +142,7 @@ } ], "links": [], - "modified": "2024-03-27 13:10:47.998597", + "modified": "2026-04-28 13:20:59.817207", "modified_by": "Administrator", "module": "Accounts", "name": "Subscription Plan", @@ -193,8 +186,9 @@ "write": 1 } ], + "row_format": "Dynamic", "sort_field": "creation", "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.py b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py index 932caaa2db24..ce9179d9a542 100644 --- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.py +++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py @@ -27,7 +27,6 @@ class SubscriptionPlan(Document): cost_center: DF.Link | None currency: DF.Link item: DF.Link - payment_gateway: DF.Link | None plan_name: DF.Data price_determination: DF.Literal["", "Fixed Rate", "Based On Price List", "Monthly Rate"] price_list: DF.Link | None diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py index b80ad82c9d33..e8414f4da826 100644 --- a/erpnext/setup/install.py +++ b/erpnext/setup/install.py @@ -41,6 +41,9 @@ def after_install(): toggle_hidden_fields() frappe.db.commit() + if "payments" in frappe.get_installed_apps(): + frappe.get_attr("payments.utils.make_custom_fields_erpnext")() + def make_default_operations(): for operation in ["Assembly"]: