Skip to content
Finance · Subscription billing module

Subscription billing software that lives inside your ERP, usage charges included

Recurring invoices are easy. Recurring invoices with metered usage, a customer who upgrades on the 11th and a finance team that wants it all in the ledger are not. If you've been eyeing separate subscription billing software and dreading the sync, erpfly can build that logic into the ERP you already run.

ERPNext v16

Works with ERPNext v15 and v16, and Odoo 17, 18 and 19.

Features

What your subscription billing module can do

Plans that match your price list

Monthly, quarterly or annual, per seat or per unit. Plans stay in the standard subscription objects so your accountant recognises them.

Metered usage on the same invoice

Usage records from an app, an API or a CSV land against the subscription. At billing time the overage becomes a normal invoice line with a clear description.

No double billing

Each usage record is stamped with the invoice that charged it. Cancel the invoice and the records free up again.

Mid-cycle changes handled

Adding units part way through a period creates a prorated line you can check on paper. No mystery credits.

Failed payment follow-up

A scheduled job chases overdue subscription invoices on a cadence you choose and can pause service after a grace period.

The output

What actually gets generated

Real files in a real repository. Here’s the typical output when someone asks for subscription billing.

ERPNext / Frappe app

  • Usage Record DocType linked to Subscription
  • Custom fields on Subscription for included units and overage rate
  • Sales Invoice before_insert, after_insert and on_cancel hooks
  • Overdue follow-up job in scheduler_events
  • Recurring Revenue Script Report

Odoo addon

  • Usage record model linked to sale.order
  • Overage line creation on account.move
  • ir.cron for usage import and renewal checks
  • Portal page showing usage history (QWeb)
  • Access rules in ir.model.access.csv
metered_billing/usage.py
import frappe
from frappe import _
from frappe.utils import flt

OVERAGE_ITEM = "COOLER-EXTRA-LITRE"


def add_overage(doc, method=None):
    """Sales Invoice.before_insert: bill usage above the plan allowance."""
    if not doc.get("subscription") or not (doc.from_date and doc.to_date):
        return
    sub = frappe.db.get_value(
        "Subscription", doc.subscription, ["included_units", "overage_rate"], as_dict=True
    )
    records = frappe.get_all("Usage Record", fields=["name", "units"], filters={
        "subscription": doc.subscription,
        "reading_date": ["between", [doc.from_date, doc.to_date]],
        "sales_invoice": ["is", "not set"],
    })
    extra = max(sum(flt(r.units) for r in records) - flt(sub.included_units), 0)
    if extra:
        doc.append("items", {
            "item_code": OVERAGE_ITEM,
            "qty": extra,
            "rate": flt(sub.overage_rate),
            "description": _("{0} over the {1} included").format(extra, sub.included_units),
        })
    doc.flags.usage_records = [r.name for r in records]


def stamp_usage(doc, method=None):
    """Sales Invoice.after_insert: the invoice now has a name, link the readings."""
    for name in doc.flags.get("usage_records") or []:
        frappe.db.set_value("Usage Record", name, "sales_invoice", doc.name)
Trimmed excerpt. The full module includes tests, fixtures and a README.

How it works

From a paragraph to a pull request

The long version
  1. 01

    Describe it

    In your own words. Paste the spreadsheet or a photo of the paper form if that's easier.

  2. 02

    Answer a couple of questions

    It asks only what it can't work out from your setup, like who's allowed to override.

  3. 03

    Try it on a sandbox

    A copy of your site with the module installed. Break it, then ask for changes.

  4. 04

    Merge when it's right

    Code lands as a pull request with tests. Your developer, or ours, reviews it first.

Why the recurring invoice is the easy bit

Every ERP can send the same invoice every month. That’s not where subscription businesses struggle. The trouble starts with the exceptions, and a subscription business is mostly exceptions: usage over an allowance, upgrades part way through a period, a paused account, a card that failed three times, a customer on an old price you promised never to change.

Dedicated billing tools handle those well, then hand you a new problem. Customers, invoices and payments now live in two systems, and someone spends the first week of every month reconciling them. For many businesses a well-built module inside ERPNext or Odoo is the simpler answer. For some it isn’t, and we cover that further down.

A worked example with water coolers

A water cooler rental company bills monthly. Each cooler costs $35 a month and includes 60 litres. Extra water costs $0.40 a litre. Drivers record meter readings in a delivery app, which posts them to the ERP.

An office customer has 12 coolers, so the allowance is 720 litres. In August they use 910. The subscription invoice for August shows 12 cooler rentals at $35, which is $420, plus 190 extra litres at $0.40, which is $76. That’s $496 before tax, ignoring for a moment the change they made mid-month.

On 11 August they add three more coolers for a new floor. With a 31-day month, that’s 21 days of the new units, or 3 × $35 × 21/31, about $71.13. That appears as its own line on the August invoice, the litre allowance for August stays at 720 (a choice, not a law), and September starts at 15 coolers with 900 litres included.

The code in this page’s snippet does the usage part. When the Subscription creates its Sales Invoice, the hook finds unbilled readings for the period and adds one overage line. Once the invoice is saved, each reading is stamped with its number, so a second run for the same period finds nothing left to charge. If finance cancels the invoice, the readings are released and picked up next time. Billing code should be exactly this predictable.

One detail worth deciding before you build: what happens when the delivery app sends a reading late, after August has already been invoiced? We’d put it on the next invoice with its real reading date in the description. Some businesses prefer a separate adjustment invoice. Either is fine. Guessing isn’t.

What our subscription billing software module contains

On ERPNext, the module extends the standard Subscription and Subscription Plan DocTypes. A new Usage Record DocType holds readings. Hooks in hooks.py attach to Sales Invoice events, and follow-up jobs go in scheduler_events. Nothing is written as a Server Script, since billing logic deserves version control and tests. The reasons are laid out in our post on Server Scripts vs a custom app.

On Odoo, it depends on edition. With Enterprise we extend the subscription app. On Community we build recurring logic around sale.order, generate account.move records on an ir.cron, and add a portal page where customers can see their usage.

Both versions ship with tests for the maths. Proration is the kind of thing that’s right in the demo and wrong on the 31st.

Billing rules we’d argue with

  • A custom price for every customer, in code. Use price lists or plan variants. Code is for rules, not for the special deal you gave one client in 2023.
  • Retroactive rebilling of old periods. If a reading was wrong, issue a credit note or an adjustment line on the next invoice. Rewriting posted invoices upsets auditors and customers equally.
  • Daily dunning emails. A reminder at 3, 10 and 21 days overdue gets paid. Daily messages get filtered.
  • Replacing a billing platform that already works. If you’re doing complex usage pricing across thousands of self-serve customers and a dedicated tool is handling it well, keep it. Sync the invoices into the ERP instead.

Where the invoices go next

Subscription invoices are still invoices. They need the same follow-up and dispute handling as any other, which is what invoice management covers. Upfront annual plans also create deferred income questions for your accounting setup, so bring your accountant in early.

For platform choice, the ERPNext vs Odoo comparison is worth reading before you commit, particularly the part about what’s in Odoo Community and what isn’t.

Guides and terms for subscription billing

Subscription billing module questions

Something missing? Email [email protected] and a person will answer.

Does ERPNext already have subscriptions?

Yes. ERPNext has Subscription and Subscription Plan DocTypes that generate recurring Sales Invoices. We build on those rather than replacing them, and add what they don't cover, such as usage, custom proration or dunning rules.

What about Odoo Community?

Odoo's subscription app is part of Enterprise. On Community we generate recurring billing on top of sale.order and account.move instead. It's more code, so we'll say so if Enterprise would be cheaper for your case.

Can it take payments through Stripe or GoCardless?

We can generate the integration that creates payment requests or pulls payment status back into the ERP. Card details stay with the payment provider, never in your database. Webhooks and retries are part of the brief, not an afterthought.

How does this affect revenue recognition?

Annual plans billed upfront usually need deferred revenue, and both platforms have tools for that. We wire the subscription items into those settings rather than writing our own recognition schedule. Have your accountant confirm the treatment before go-live.

We bill from a spreadsheet and a separate SaaS tool today. How do we move?

We generate an import for active subscriptions with their next billing date, so nothing bills twice or gets skipped. Run old and new side by side for one cycle and compare the invoices line by line before switching off the old tool.

Will usage records slow the ERP down?

Not at the volumes most businesses bill on. If you're recording millions of events a month, we'd aggregate them outside the ERP and send daily totals instead. That's cleaner anyway.

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

Create your account

Free to start. No card needed.

By signing up you agree to our terms and privacy policy.