# A custom accounting module for the controls your auditor keeps asking about

Canonical: https://erpfly.com/modules/accounting/
Last updated: September 7, 2026

Category: Finance

ERPNext and Odoo both ship a proper double-entry ledger, and you shouldn't replace it. What finance teams usually need is the layer on top. A custom accounting module adds the journal controls, month-end allocations and branch reports your auditor and your finance director keep asking about, without touching the ledger itself.

### Features

- **Manual journal guardrails.** Mark accounts as restricted, require a reason above a threshold, and keep automated entries such as depreciation out of the rules entirely.
- **Allocations as reviewable drafts.** Shared costs are split by a rule you can read, and the result arrives as a draft journal entry. Finance checks it and posts. The code never posts on its own.
- **Branch and department reporting.** Profit and loss by cost center or analytic account, with the columns your finance director actually asks for, not a generic export.
- **Month-end checklists in the ERP.** Bank reconciled, accruals posted, allocations reviewed. Each step has an owner and a date, so the close doesn't live in someone's notebook.
- **An audit trail in plain view.** Who posted what, when, against which rule and with what reason. Exportable when the auditors arrive.

### What gets generated

**ERPNext / Frappe app:**
- Restrict Manual Posting check field on Account (fixture)
- Journal Entry validate hook in hooks.py
- Overhead Allocation Rule DocType with branch percentages
- Monthly job that drafts allocation Journal Entries
- Branch Profit and Loss Script Report

**Odoo addon:**
- account.account flag for restricted manual posting
- account.move _post guard for manual entries
- Allocation rule model using account.analytic.account
- ir.cron that drafts monthly allocation entries
- Pivot and list views for allocation history

### Leave the general ledger alone

We'll start with the thing we refuse to do. We don't write general ledgers. ERPNext and Odoo already post balanced entries, handle multi-currency, close periods and produce a trial balance that ties. Rewriting any of that is a way to spend a lot of money on a future audit problem.

What does go wrong is everything around the ledger. Someone posts a manual journal to the receivables control account to make a balance look right. Shared rent gets split by gut feel. The branch P&L lives in a spreadsheet that's rebuilt every month and argued over at every board meeting. Those are the problems a module can fix.

### What belongs in a custom accounting module

Three kinds of thing, mostly.

**Controls before posting.** Rules about who can post what, when a reason is required and which accounts should only ever be touched by source documents like invoices and payments.

**Entries drafted by rules.** Allocations, recurring accruals and intercompany recharges, generated as drafts from a rule someone can read, then posted by a person.

**Reports built for your structure.** Branch, department or project P&L from cost centers in ERPNext or analytic accounts in Odoo, laid out the way your board pack wants.

On **ERPNext**, that becomes a Frappe app with hooks on Journal Entry, a rule DocType, a scheduled job and a Script Report. On **Odoo**, it's an addon that guards `account.move` posting, reads `account.analytic.account` for distribution and runs allocations on an `ir.cron`. In both cases the code stays out of core, which is why the approach in our guide to [keeping ERPNext customizations through upgrades](https://erpfly.com/blog/erpnext-upgrade-keep-customizations/) applies here too.

### Worked example: three branches, one rent bill

A group runs three branches from one leased building. Rent is $18,000 a month on a single supplier invoice. The branches occupy 1,000 m², 600 m² and 400 m².

On the first working day of the month, the module drafts a journal entry that moves rent out of the shared cost center: $9,000 to branch one, $5,400 to branch two and $3,600 to branch three. The draft includes the rule name and the floor areas used, in the remark. The finance manager glances at it and submits. If branch two takes an extra 100 m² in March, someone updates the rule once and April's draft follows.

Separately, a junior accountant tries to post a $7,500 manual journal with no remark. The system asks for a reason. Later they try to credit the trade receivables account directly, which has been marked restricted. That's blocked, with a message pointing them to a credit note or payment instead. An accounts manager can still post it when there's a genuine reason, and the entry carries their name.

Notice what the module doesn't do. It doesn't decide whether the $7,500 journal is correct. It makes sure there's a written reason attached, so when the auditor picks it out of a sample in eleven months' time, the accountant who posted it doesn't have to reconstruct the story from memory. Controls like this are less about stopping fraud and more about stopping the slow drift of entries that even their authors can't explain a year later.

The snippet on this page is the journal guard. About 30 lines, and most of it is the error messages.

### Controls we'd skip, or do differently

- **Blocking backdated entries in custom code.** Both platforms have period and lock date features. Use those. A second, homemade lock just confuses people about which one applies.
- **Allocations that post automatically.** A draft costs a finance manager thirty seconds. An automatic wrong posting costs a reversal, a note and a conversation.
- **Approval on every journal entry.** If every entry needs approval, approvers stop reading. Put the gate on restricted accounts and large amounts, and trust the rest.
- **A parallel tax calculation.** If tax is wrong, fix the tax configuration.

### Where accounting meets the rest

The ledger is where the rest of your ERP ends up. Clean data from [invoice management](https://erpfly.com/modules/invoice-management/) and [expense claims](https://erpfly.com/modules/expense-management/) makes month end shorter than any report can. If the control you need depends on how ERPNext is configured rather than on new code, start with our page on [ERPNext customization](https://erpfly.com/erpnext-customization/). And if your finance processes are unusual enough that neither platform fits, [custom ERP development](https://erpfly.com/custom-erp-development/) is the alternative we'd look at.

### FAQ

### Are you going to change how the general ledger works?

No. Every entry still goes through the platform's own posting logic, so trial balance, tax reports and financial statements behave as they always did. The module adds checks before posting and drafts entries for people to review.

### Will this work with our country's localisation and tax reports?

It sits alongside them. We don't generate tax calculations or statutory reports where a localisation already covers them. If yours has a gap, we'll tell you what we'd build and suggest you check the result with your accountant.

### What happens to the controls when we upgrade?

They live in a separate Frappe app or Odoo addon. Journal and account structures are among the more stable parts of both platforms, but accounting is exactly where you should run the tests on a copy before upgrading live.

### Can we migrate our chart of accounts and history from QuickBooks or Xero?

Yes. The usual approach is the chart of accounts, opening balances at a clean cut-off date and open invoices and bills. Full transaction history can come across too, but it's slow and rarely worth the reconciliation effort.

### Do we need ERPNext cost centers or Odoo analytic accounts for branch reporting?

You need one of them, set up before the transactions arrive. Adding branch tags retrospectively is painful on any platform. If you're not using them yet, that's the first job, before any custom report.

### Who can change the rules later?

Thresholds and restricted accounts are settings your finance team can edit. The logic itself is code in your own repository, so changes go through whoever maintains it, which is how you'd want it in finance.