Most home-grown order and invoicing systems have the same defect, and it is nearly always discovered by accident. The totals are worked out in the browser, which means they are worked out somewhere the user can reach — and anything that writes to the line table without going through a form leaves every total downstream quietly wrong.
Build an ERP we can actually bill from.
Derived values computed on the client are not really derived. They are a suggestion the browser makes and the database accepts, and any path into the data that does not go through that browser — an import, an API call, a support fix run directly against the database, a second screen written later — bypasses it entirely.
This is not a rare edge case; it is the normal operation of a growing business. You import a price list. You take orders through an API. Someone corrects a line in the admin panel. Each of those is a moment where a header total can stop matching its lines, and because nothing complains, the error is only found when a customer or an accountant notices.
The related failure is numbering. Order and invoice numbers assigned by counting existing rows, or by a nightly job, will eventually produce a duplicate or a gap under concurrency — and an invoice number is exactly the field where neither is acceptable.
Derived values are computed on the server, where the user cannot reach them. A calculated field works out a line's net from quantity, price and discount; a rollup sums those lines into the order or invoice header. Both recalculate on every save, evaluate in a defined order so a header total can consume a line's result, and can filter which child rows count — so cancelled lines are excluded by the rule rather than by hoping nobody forgot.
Because it runs server-side, it does not matter how the data arrived. A form, an import, an API call and a custom function all trigger the same recalculation, and a consistency sweep catches anything that got in another way. A formula that fails leaves the previous value alone rather than writing a wrong number, which is the correct behaviour and not the usual one.
On top of that sit the document lifecycle — quote to order to despatch to invoice, with permitted transitions rather than free-form status edits, and line-level provenance so partial fulfilment and partial invoicing do not require editing the original — plus number schemes that allocate atomically, price lists with quantity breaks, and discount rules with explicit stacking control.
Headers and lines as linked datastores, with the relationship explicit rather than implied by a shared reference column. Almost every totals problem in a home-grown system traces back to this being loose.
Calculated fields for line-level values, rollups for header totals, with an explicit evaluation order so a total can consume a result computed earlier in the same save. Rollups can filter which child rows count, so cancelled or draft lines are excluded structurally.
Number schemes allocate atomically, so two users raising an invoice at the same moment cannot receive the same number, and a failed transaction does not leave a gap that finance has to explain.
Quote to order to despatch to invoice, expressed as permitted transitions rather than an editable status field, with line-level provenance so a partial despatch or partial invoice references the lines it came from instead of mutating the original document.
Price lists with quantity breaks, and discount rules with explicit control over what stacks with what. This is usually where the recovered margin is, because inconsistent discounting is rarely deliberate and almost never measured.
Nothing here is written specially for this use case — it is the same platform every ActiveManage application is built from. The full feature list is on the platform page.
| Feature | What it does | Why it matters here |
|---|---|---|
| Calculated fields | Server-side field arithmetic, recomputed on every save. | The value cannot be edited into disagreeing with its inputs, because it is not the user who computes it. |
| Rollups | Header totals summed from child lines, with filtering over which rows count and a defined evaluation order. | Handles the case client-side totals always get wrong: data that arrived without passing through a form. |
| Consistency sweep | A pass that recalculates and catches values that drifted — after imports or direct database writes. | The safety net for the paths nobody anticipated, which in a real business is most of them. |
| Number schemes | Atomic allocation of order, invoice and document numbers. | No duplicates under concurrency, no gaps to explain to an auditor. |
| Transactional documents | Quote to order to despatch to invoice, as permitted transitions with line-level provenance. | Partial fulfilment stops meaning "edit the original and hope", which is where the audit trail usually dies. |
| Pricing & commissions | Price lists with quantity breaks, discount rules with explicit stacking control, margin-based commission. | Discounting rules become enforceable rather than cultural. |
The document model and the arithmetic, validated against your existing figures. Reconciling a month of real orders against the old system is the test that matters.
Lifecycle, numbering, pricing rules and the routes data arrives by — usually where the integration work sits.
Formulas, price lists and discount rules are configuration, so commercial changes do not queue behind a developer.
Because the browser is only one of the ways data reaches your database. Imports, API calls, custom functions and direct fixes all bypass it. Server-side calculation means every one of those paths produces the same, correct total.
It leaves the existing value alone rather than writing a wrong number. Silently storing a bad figure is far more damaging than declining to update one, particularly on anything you bill from.
Yes. Recalculation is triggered by the save, not by the form, so an import recalculates exactly as a user would. The consistency sweep then covers anything that got in by an unanticipated route.
Yes. The lifecycle is a set of permitted transitions with line-level provenance, so a partial despatch or invoice references the lines it derives from instead of editing the original document.
No, and usually you should not. This is the operational side — quotes, orders, despatch, invoicing. There are connections to Xero, QuickBooks, Sage and bank feeds, so the finished figures go where your accountant expects them.
Tell us what you are trying to fix and we will tell you whether this is the right shape for it — including when it is not.