Building Seamless Payment Integrations with Frappe Payments

In today's digital economy, offering smooth payment processing is crucial for any business application. Frappe's Payments app provides an elegant framework for integrating various payment gateways.

 · 2 min read

Payments app is a best example to maintaining clean code architecture. Let's explore how this system works and how you can extend it for custom payment gateways.

The Power of Frappe's Payment Integration Structure

Frappe's payment integration follows a well-designed pattern that makes adding new gateways straightforward while keeping the implementation clean and maintainable. The key components of this architecture are:

  1. Standardized Settings Documents: Each payment gateway has its own Settings document
  2. Gateway Controller Classes: Python classes that handle gateway-specific logic
  3. Payment URL Generation: A consistent interface for initiating payments

The Settings Document Pattern

Every payment gateway integration follows a naming convention where the settings document is named [PaymentGatewayName] Settings. For example:

  • Razorpay Settings
  • PayPal Settings

This pattern makes it easy to locate and manage gateway configurations.

How It Works

1.Each gateway has a Settings DocType

  • Example: CCAvenue Settings, Razorpay Settings
  • Stores API keys and configurations.

2. A matching Python class

  • Example: CCAvenueSettings, RazorpaySettings
  • Contains gateway-specific logic.

3. Standard methods

  • get_payment_url() – Generates the payment link.
  • validate_transaction_currency() – Checks if the currency is supported.

The Gateway Controller Class

Each payment gateway has a corresponding Python class that handles its specific logic. The class name matches the settings document name (without spaces). Here's the basic structure:


class PaymentGatewaySettings(Document):
    def validate_transaction_currency(self, currency):
        # Validate if currency is supported
        pass
        
    def get_payment_url(self, **kwargs):
        # Generate payment URL for this gateway
        pass

The magic happens in the get_payment_gateway_controller function from payments/utils/utils.py:


# payment_gatway parameters having a same value which you have selected in Payment Getway field
def get_payment_gateway_controller(payment_gateway):
    """Return payment gateway controller"""
    gateway = frappe.get_doc("Payment Gateway", payment_gateway)
    if gateway.gateway_controller is None:
        try:
            return frappe.get_doc(f"{payment_gateway} Settings")
        except Exception:
            frappe.throw(_("{0} Settings not found").format(payment_gateway))
    else:
        try:
            return frappe.get_doc(gateway.gateway_settings, gateway.gateway_controller)
        except Exception:
            frappe.throw(_("{0} Settings not found").format(payment_gateway))

  1. Takes a payment gateway name as input
  2. Looks up the Payment Gateway record
  3. Returns the appropriate settings document/controller class
  4. Provides clear error handling if the gateway isn't properly configured

Implementing a Custom Payment Gateway

Let's walk through adding a new payment gateway called "CCAvenue" to demonstrate how cleanly this architecture extends.

1. create a settings doctype

Naming of the Setting doctype: CCAvenue Settings

Add a necessary fields

2. Implement the Controller Class

This class should have a method get_payment_url


import frappe
from frappe.model.document import Document

class CCAvenueSettings(Document):
    def validate(self):
        self.validate_credentials()
        
    def validate_credentials(self):
        # Test the API keys are valid
        # Write a code to validate credential with payment getway
        pass
        
    def get_payment_url(self, **kwargs):
        # Implement the logic to call payment getway api
        pass
        

Key Benefits of This Architecture

  1. Consistency: All payment gateways follow the same pattern
  2. Extensibility: Easy to add new gateways without modifying core code
  3. Maintainability: Gateway-specific code is isolated in its own class
  4. Reusability: Common utilities are shared across all integrations

Ready To Unleash The Power of ERPNext?

We might just be the right partner you need.


No comments yet.

Add a comment
Ctrl+Enter to add comment