Sales orders
The central object in CCC, built from NetSuite since 2022 and from verkoopdump before it, and the grain every margin figure aggregates to.
The sales order is the centre of CCC. Margin is aggregated to it, customers are grouped by it, and most screens are ultimately a view of it.
What it is in CCC
An order placed by a customer, with its lines, plus everything CCC has computed about it: its classification flags, the impacts calculation rules booked against it, and its aggregated margin.
It is not simply the NetSuite record. The upstream record is the starting point; the object is that record plus CCC's own work on it.
Tables
| Table | Holds |
|---|---|
salesorders | The header |
salesorderlines, salesorderlinesnoninv | Item and non-inventory lines |
salesorderdiscount, salesordertax | Discounts and taxes |
salesorderclassifications | Header flags |
salesorderlineclassifications | Line flags |
cm_impact_salesorders | Aggregated margin per order, plus its processed queue flag |
The same family shape repeats for the other six transaction types.
Provenance
| Period | Source | Notes |
|---|---|---|
| Before 2022 | verkoopdump | Imported by hand, in year slices |
| 2022 onward | NetSuite | Continuous, and backfillable by date |
How much of the pre-2022 window is loaded is a property of the environment, not of the code. The historic import is switched on, drained a slice at a time, and switched off again, so test, acceptance and production each hold whatever was run there. Count the rows in the period you care about before reading a figure that spans 2022.
Acquisition data follows a different seam: source and medium comes from GA4 for recent orders and from verkoopdump for 2022 to 2025, because GA4 cannot be asked for history.
2022 is also a calculation floor, not only a provenance seam. Both margin queues skip any transaction dated before ingest.modernera, so a pre-2022 order is imported, visible, and carries no margin at all. Re-queuing it will not change that. The new-rule default window starts on the same date, but the queue floor is a separate check. See configuration and boundaries.
So one order can carry a header from one source and acquisition data from another. That is by design.
How it is built
- Imported from its source into the header and line tables.
- Classified, writing flags into the two classification tables. See classifications.
- Calculated, with calculation rules booking impacts into the
cm_impact_*tables. - Aggregated into
cm_impact_salesorders, whoseprocessed = 0flag is its own recalculation queue, separate from the batches table.
An order can sit at any of those stages. A record that exists with no margin is usually at stage 2 or 3, not broken.
Where it is used
The sales order screens, the detail view, the income statement, the customer dimension, the exports, and the downstream BI tools.
Known disagreements
- Cancelled and closed orders exist and are stored. Both mean the order did not happen, and both are excluded from customer numbering while remaining part of the customer group.
- A screen filtered on creation date and a customer sequence ordered on transaction date will disagree about which order came first. Both are correct. See dates, currency and signs.
- Margin moves after the order does, because downstream transactions arrive later and rules can be re-run.
Related
- Contribution margin
- Customers
- Trace an order
- The screens:
/transactions/salesordersand its detail view
Evidence
Table family from AGENTS.md, Models and database, and the CREATE TABLE statements in app/jobs/install/install.php. Aggregation and the processed flag from app/jobs/calculate/impactsalesorders.php. Provenance split from AGENTS.md, The application. Basis: code-checked against the current implementation.
How much pre-2022 history an environment holds is a property of that environment rather than of the code, as the provenance section above says.
- Type
object - Status
active - Updated
2026-09-14 - Created
2026-09-13 - Covers
transactions/salesorders