Skip to content
ERPNext · Frappe

ERPNext custom module development, written by AI and reviewed like real code

You know what the module should do. You just don't want to spend a month finding a Frappe developer, writing a spec and waiting. erpfly turns your description into a Frappe app that installs with bench, passes its own tests and never touches core.

ERPNext v16
  • Code in your Git repo
  • Tested on a sandbox first
  • No core files edited

Deliverables

What you walk away with

Not a demo, not a mockup. Files you can open, change and deploy without us.

A real Frappe app

Standard layout with hooks.py, modules.txt, patches and fixtures. It installs with bench get-app and bench install-app like anything from the Frappe marketplace.

DocTypes with sensible permissions

Child tables, naming series, links to Customer, Item and Employee, and role permissions that match who does what in your company.

Workflows, not Server Scripts

Approvals and state changes use Frappe Workflow and Python controllers, so they can be tested, reviewed and versioned.

Reports and print formats

Script Reports for the numbers your manager asks about, and Jinja print formats for the documents that go to customers.

Tests and a migration path

Unit tests for the business rules, plus patches that move existing data when a field changes shape.

A README a human can follow

What was added, which standard DocTypes were extended, and what to check after upgrading ERPNext.

The process

How the work actually goes

  1. 1

    Connect a site, or don't

    Point erpfly at a staging site (read-only API key) so it can see your DocTypes and custom fields. No site yet? It works from a fresh ERPNext v16 install.

  2. 2

    Describe the module

    Plain English, bullet points, a screenshot of the Excel sheet you're replacing. Whatever you'd give a new developer on day one.

  3. 3

    Review it running

    We install the app on a disposable copy of your site. You click through, enter test records and ask for changes in the chat.

  4. 4

    Merge and deploy

    The app lands in your GitHub or GitLab repo as a pull request. Deploy with bench, Frappe Cloud or your own CI.

equipment_rental/equipment_rental/doctype/rental_booking/rental_booking.py
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import date_diff, flt


class RentalBooking(Document):
    def validate(self):
        if date_diff(self.return_date, self.start_date) < 0:
            frappe.throw(_("Return date can't be before the start date"))
        self.check_machine_is_free()
        self.days = date_diff(self.return_date, self.start_date) + 1
        self.rental_amount = flt(self.days) * flt(self.daily_rate)

    def check_machine_is_free(self):
        clash = frappe.db.exists("Rental Booking", {
            "machine": self.machine,
            "docstatus": 1,
            "name": ("!=", self.name),
            "start_date": ("<=", self.return_date),
            "return_date": (">=", self.start_date),
        })
        if clash:
            frappe.throw(_("{0} is already booked on those dates ({1})")
                         .format(self.machine, clash))

    def on_submit(self):
        # Deposit is held as a Payment Entry against the customer
        make_deposit_entry(self)
An excerpt from a generated module. Trimmed for the page.

What “custom module” means in ERPNext

In ERPNext, a module is a group of DocTypes, reports and pages that live inside a Frappe app. When people say they need a custom module, they usually mean one of three things:

  • A brand-new area the standard product doesn’t cover, like equipment rental, clinic appointments or fleet maintenance.
  • A heavy extension of something that exists, like adding territory rules and approvals on top of the standard CRM.
  • Glue between ERPNext and another system, like syncing orders from Shopify or pushing payslips into a bank’s portal.

All three end up as the same thing on disk: a Frappe app with its own hooks.py, installed next to erpnext on your bench. erpfly generates that app. It doesn’t produce a zip of Server Scripts or a set of instructions for you to follow in the UI.

Why teams stop hand-building every module

Frappe is a good framework. The problem is that the work around a module is slow. Someone has to translate “the deposit gets refunded after inspection” into DocTypes, fields, a workflow, permissions and a controller. Then someone writes the report. Then someone remembers the print format. None of it is hard, but all of it takes days, and good Frappe developers are booked months ahead.

What erpfly does is compress that first 80%. You still decide what the module should do, and you still review what it produces. You just don’t wait three weeks to see a first version.

How a generated ERPNext app is laid out

If you open the pull request, you’ll see a structure any Frappe developer will recognise:

equipment_rental/
├── equipment_rental/
│   ├── hooks.py
│   ├── modules.txt
│   ├── patches.txt
│   ├── fixtures/            # custom fields, property setters, roles
│   ├── equipment_rental/
│   │   ├── doctype/
│   │   │   ├── rental_booking/
│   │   │   ├── rental_machine/
│   │   │   └── damage_inspection/
│   │   ├── report/
│   │   │   └── machine_utilisation/
│   │   └── print_format/
│   └── tests/
├── README.md
└── pyproject.toml

Each DocType has its JSON definition, a Python controller and, where needed, a small JavaScript form script. Business rules live in the controller or in functions wired up through doc_events. We keep Client Scripts to UI niceties and never put validation there, because anything enforced only in the browser can be skipped by the API.

Getting it onto your live site

Generated code is only useful once it’s running where your team works. There are three routes we see, and the app is the same in each.

Frappe Cloud. Connect the repository to your bench group, deploy, then install the app on the site. Migrations run as part of the deploy. This is the least work and what we’d pick for most small teams.

Your own server. On the box running bench, it’s the usual sequence: bench get-app with your repo URL, bench --site yoursite install-app, then bench migrate. If you already run other custom apps, nothing about this one is different.

CI pipeline. Larger teams tend to have a staging site that rebuilds on every merge. The generated tests run there with bench run-tests --app, and production only moves when staging is green.

Whichever route you take, we’d strongly suggest one habit: install on a copy of production first, with real data. Most surprises in ERPNext projects aren’t bugs in the new code. They’re old records that don’t fit a new mandatory field, or a naming series that clashes with something set up years ago. The generated patches handle the cases erpfly can see from your schema, and a staging run catches the rest.

When you should not use erpfly for this

We’d rather lose a sale than set you up badly, so here’s where we’d point you elsewhere.

  • You need a feature that’s already in ERPNext. A surprising number of “custom module” requests turn out to be a setting. Check the ERPNext customization page first, and ask us if unsure.
  • Your process isn’t settled yet. If three managers describe the approval flow three different ways, generating code won’t fix that. Agree on the process, then build.
  • You need deep changes to accounting logic. We can generate them, but changes to GL entries deserve a senior ERPNext consultant in the loop. We’ll tell you when a request crosses that line.

Common modules people build on ERPNext

The most requested ERPNext modules we see are a CRM with territory rules, warehouse management with bin locations and pick lists, attendance with biometric device sync and invoice automation for things like milestone billing. Manufacturers often start with production planning and job cards.

If you’re not on ERPNext and are weighing it against Odoo, our ERPNext vs Odoo comparison sets out where each one is the better fit. And if neither fits, there’s always a custom ERP built from scratch.

Modules people build with this

Guides and terms for this work

Questions people ask us

Something missing? Email hello@erpfly.com and a person will answer.

Is a generated Frappe app really production quality?

It follows the same structure and conventions as apps on the Frappe marketplace, with tests. That said, we recommend a developer reviews the pull request before it goes to production, the same as you would for code written by a new hire. On the Partner plan we can do that review for you.

Which ERPNext versions do you support?

ERPNext and Frappe v15 and v16. If you're still on v14, we can generate code for it, but we'd rather help you plan the upgrade first because v14 is out of support.

Does it work on Frappe Cloud?

Yes. Push the generated app to a Git repository, add it to your Frappe Cloud bench group and deploy. Nothing in the app needs server access that Frappe Cloud doesn't allow.

Can it modify standard ERPNext DocTypes like Sales Invoice?

It extends them with custom fields, property setters and doc_events in hooks.py, all shipped as fixtures inside the app. It won't edit files in the erpnext app itself, because that's what breaks upgrades.

What happens when the AI gets something wrong?

You tell it, in plain language, and it changes the code. If you'd rather fix it yourself, it's normal Python and JSON in your repo. Nothing is locked inside erpfly.

How is this different from Server Scripts or Client Scripts?

Server and Client Scripts are fine for a quick tweak. For anything with real business rules, a proper app is easier to test, review and move between sites. erpfly generates apps by default and only suggests scripts for one-line changes.

Other ways we can help

Your next module is one paragraph away

Write it the way you’d explain it to a new hire. We’ll turn it into an app you can read, test and install.

ERPNext v16