Sales orders

TL;DR

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

TableHolds
salesordersThe header
salesorderlines, salesorderlinesnoninvItem and non-inventory lines
salesorderdiscount, salesordertaxDiscounts and taxes
salesorderclassificationsHeader flags
salesorderlineclassificationsLine flags
cm_impact_salesordersAggregated margin per order, plus its processed queue flag

The same family shape repeats for the other six transaction types.

Provenance

PeriodSourceNotes
Before 2022verkoopdumpImported by hand, in year slices
2022 onwardNetSuiteContinuous, 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

  1. Imported from its source into the header and line tables.
  2. Classified, writing flags into the two classification tables. See classifications.
  3. Calculated, with calculation rules booking impacts into the cm_impact_* tables.
  4. Aggregated into cm_impact_salesorders, whose processed = 0 flag 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.

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.

About this document