The income statement

TL;DR

The recursive statement over the account tree. It has four views, one of which puts the general ledger and CCC's own calculation side by side, and a row of display options that change the presentation without changing a stored figure.

The income statement builds a recursive statement from the account tree: accounts nested under account groups, one column per accounting period in the selected range, with a total row. It is the most-used reporting screen in CCC and the one where the general ledger and the contribution margin calculation meet.

Four views

The view is the next URI segment after the page, so /generalledger/incomestatement/ccctotals is the third one.

ViewURLShows
Account totals(default)The general ledger's own period totals per account
Extended/accounttotalsextendedThe same totals broken down per domain, per category, per sales channel detail or per category detail
CCC totals/ccctotalsThe same tree filled from the impacts CCC's calculation rules booked
CCC vs account/cccaccountcompareBoth, period by period, side by side

CCC vs account is the reconciliation view. It runs the CCC totals and the ledger totals for the same periods and pairs them as compare columns, labelling the CCC column with a CCC suffix. It forces compare on and forces the hide-zero option off, so a line that is zero on one side and not on the other cannot vanish. That combination is the point of the view: a difference is only visible if both sides are shown.

The two will not agree line for line, and that is expected. The ledger is period-based and records what was booked; the contribution calculation is transaction-based and records what rules computed per order. See contribution margin.

The extended view's breakdowns

ViewerBreaks the statement down by
Per domainDomain
Per categoryProduct category
Sales channel detailOne NetSuite sales channel, in detail
Category detailOne NetSuite category, in detail

The two detail viewers take a single sales channel or category from the two selectors beside them. Only NetSuite sales channels that a CCC sales channel maps to a domain are offered, because the extended ledger totals are keyed on those.

Period selection and what is excluded

The period range comes from pages.incomestatementfrom and pages.incomestatementto in config/settings.json, overridden by the date fields. The subsidiary selector picks which set of books to read.

Hide adjustments excludes the adjustment periods, the ones that close a year rather than record a month. It is on by default, and compare and budget both force it on, because comparing a normal period against an adjustment period compares two different kinds of thing.

Display options

None of these change a stored figure. All of them change what you are reading, so establish which are on before comparing the screen to a query.

OptionEffect
CompareAdds a comparison period column beside each period
BudgetCompares against the budget figures instead
InvertFlips the sign of the displayed figures. On by default
Divide by 1000Shows thousands
Percentage of revenueShows each line as a share of revenue instead of an amount
Hide zeroDrops rows that are zero in every column. On by default
CollapseHow deep the tree is opened
RoundingFloor, round or ceiling, at 0, 1 or 2 decimals

Invert is on by default. It reverses every displayed amount: a stored -100 becomes +100, and a stored +60 cost becomes -60. Match this option when comparing the report with a database query; see dates, currency and signs.

Where the figures come from

The account totals views read gl_accounttotalperperiod, gl_accounttotalperperiodextended and gl_accounttotalperperiod_budget, which are filled by the NetSuite account total jobs. The CCC views read the cm_impact_* tables the calculate step wrote. The tree itself is built from accounts and their account groups.

This screen has no app/data/ endpoint: it renders server-side rather than through a bootstrap-table, which is one of the documented exceptions to the page pattern.

Evidence

Views, viewers, defaults and every display option from app/http/generalledger/incomestatement.php. The compare pairing and the forced options in the reconciliation view from incomestatement->getincomestatementcccaccountcompare(). Period defaults from config/settings.json. The missing data endpoint from AGENTS.md, Directory layout. Basis: code-checked against the current implementation.