How can we override ERPNext core functions?

FYI, you can also use monkey patching with Python. I needed to override erpnext.controllers.taxes_and_totals.calculate_taxes_and_totals. Here is what I did:

  1. Create a new module called my_app.my_module and a file inside it called override_calculate_taxes_and_totals.py with a new class like this:
from erpnext.controllers import taxes_and_totals

class my_app_calculate_taxes_and_totals(
        taxes_and_totals.calculate_taxes_and_totals
):
    """Override for calculating taxes and totals in MyApp."""
    <your changes here>

taxes_and_totals.calculate_taxes_and_totals = my_app_calculate_taxes_and_totals

Note that I import the module, not the class, and reference the class as taxes_and_totals.calculate_taxes_and_totals.

The last line changes the reference for taxes_and_totals.calculate_taxes_and_totals to my_app_calculate_taxes_and_totals so any other imports in standard ERPNext code get my class instead of the original class.

  1. Make sure your code runs before any other imports:

This only works if the code above runs before the standard code imports taxes_and_totals.calculate_taxes_and_totals so you can add the following line to hooks.py:

extend_bootinfo = [
	"my_app.startup.boot.boot_session",
]

and create a module called my_app.startup with a file called boot.py as so:

# This is the important line
from my_app.my_module import override_calculate_taxes_and_totals


def boot_session(bootinfo):
    """boot session."""

We don’t need the boot_session function to do anything. It is the import at the top that matters. Because this code runs every time a user logs in, the patch is set and the modified code will run. Of course, because I am inheriting from the original class, the original function is available as a super() reference.

3 Likes