šŸ’ Monkey Patching and Overriding Anything in Frappe Framework (Python + JavaScript)

Customizing standard functionality in Frappe and ERPNext is often easy — hooks, events, and overrides are there for a reason.
However, there are cases where Frappe’s official extension points are not enough:

  • Some functions aren’t whitelisted.
  • Some reports don’t belong to a Doctype (so override_doctype_class won’t work).
  • Some classes are buried deep and are never exposed for hooks.

In such situations, you can still achieve full control using Monkey Patching — a powerful technique in Python and JavaScript that allows you to override any function, class, or file at runtime.

Let’s understand how you can do this, the right way, using real examples from ERPNext.


:rocket: Problem Statement: Overriding a Report (General Ledger)

Suppose you want to customize ERPNext’s General Ledger report, but:

  • You can’t override it from hooks.py because it’s not tied to a Doctype.
  • You can’t modify core files (bad practice).

Still, you want full control over both the backend (Python) and frontend (JavaScript) of the report.


:snake: Overriding Python Code via __init__.py

Here’s how to override the Python logic without touching core files:

1. Create Your Custom Python File

Path:

sudhanshu_app/custom_script/report/general_ledger/general_ledger.py

In this file:

  • Copy the original code from erpnext/accounts/report/general_ledger/general_ledger.py.
  • Modify it according to your business needs.

Example:

def execute(filters=None):
    # Your custom logic
    return custom_columns, custom_data

2. Monkey Patch via __init__.py

Path:

sudhanshu_app/custom_script/report/general_ledger/__init__.py

Write the following:

import frappe
from sudhanshu_app.custom_script.report.general_ledger.general_ledger import execute as custom_general_ledger
import erpnext.accounts.report.general_ledger.general_ledger

# Replace the original execute function with your custom one
erpnext.accounts.report.general_ledger.general_ledger.execute = custom_general_ledger

Boom! Now whenever General Ledger report is called, your version of execute runs instead of the original.

:white_check_mark: No core file touched.
:white_check_mark: Fully reversible.
:white_check_mark: Upgradable safely (with minimal merge conflicts).


:desktop_computer: Overriding JavaScript Code via hooks.py

The frontend (JavaScript) of reports is loaded dynamically in Frappe. You can override it too!

1. Create Your Custom JS File

Path:

sudhanshu_app/public/js/report/general_ledger.js

In this file:

  • Copy the full original JavaScript code from erpnext/public/js/erpnext/accounts_report/general_ledger.js (or wherever it is).
  • Make your custom changes.

Example:

frappe.query_reports["General Ledger"] = {
    "filters": [...],
    "formatter": function (value, row, column, data, default_formatter) {
        // Your custom formatter
    }
}

2. Include It in hooks.py

In your hooks.py, add:

app_include_js = [
    "/assets/sudhanshu_app/js/report/general_ledger.js"
]

This ensures your JS loads after ERPNext’s base JS and replaces the standard report behavior.


:dart: Key Takeaways

  • Monkey Patching gives you freedom to override any Python function, class, or method in Frappe.
  • Overriding JavaScript is as simple as copying and injecting your own custom script via hooks.py.
  • Best Practice: Always comment clearly that this is a monkey patch so your future team (or your future self) knows it’s intentional.
  • Upgrade-Proofing: Since you’re not editing core files, upgrades are relatively safe — just review changes in the original files after major updates.

:rocket: Beyond Reports: What Else Can You Override?

  • Custom whitelisted functions
  • Server scripts
  • API endpoints
  • Background jobs
  • Page controllers
  • Event handlers
  • Class methods

:zap: Final Thoughts

Monkey patching gives you superpowers, but with great power comes great responsibility.

Use it carefully, transparently, and only when needed — preferably when standard hooks and extension points aren’t available.

By mastering these techniques, you can unlock full customization potential in any Frappe / ERPNext project — without ever touching the core!

8 Likes