> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vinmake.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Statutory reporting

> Trial balance, P&L, balance sheet and the Circular-200 projection, all built from one posted-lines base so they cannot disagree.

# Statutory reporting

## What it guarantees

Four reports, **all built from the same posted-lines base**, so they can never disagree with each other.

Two rules they obey, both structural rather than promised:

1. **Posted only.** Every query filters `journal_entries.status = 'posted'`. Nothing draft or reversed-out leaks into a statement.
2. **Base currency.** Amounts come from `debit_base` and `credit_base` - the columns the engine itself balances on. So a statement built here nets to zero for exactly the same reason the ledger's balance invariant does.

## The four reports

| Report              | What it is                                                                                                          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------- |
| **Trial balance**   | per-account debit, credit and net in base currency, plus the zero-sum check. The spine the other three project from |
| **Profit and loss** | revenue minus cost of sales and operating expense for a period, sectioned by account type                           |
| **Balance sheet**   | assets equal liabilities plus equity as of a date, with the period's result carried into equity                     |
| **TT200 report**    | the Circular-200 statutory projection, each IFRS account rolled up to its VAS codes                                 |

### The balance sheet carries the result into equity

An un-closed year's earnings are not yet in the current-year-earnings account, so without this the balance sheet would appear off by **exactly the profit**.

That is not a rounding difference or an edge case; it is a structural consequence of when a year-end close happens, and every accounting system has to handle it.
Handling it in the statement rather than by requiring a close first is what lets you look at a balance sheet mid-year.

### Everything projects from the trial balance

The P\&L and the balance sheet are not independent queries over the ledger.
They are projections of the same trial balance.

That is why they cannot disagree.
Two independent aggregations over the same rows *should* agree, and in practice one of them eventually has a different period boundary or a different status filter, and then nobody knows which report is right.

## The TT200 projection

The chart's [statutory layer](/greatbook/capabilities/chart-of-accounts) maps each GreatBook account to zero or more Circular-200 codes.
The report rolls the balances up through that map.

It also reports **the accounts with activity that have no mapping**, which would otherwise silently vanish from the return.
That is the difference between a report that produces a number and one that tells you what it left out.

### The one caveat, stated rather than hidden

The map is one IFRS account to **N** VAS codes.

Where an account maps to several codes, the report attributes its **full balance to each of them** and flags the account as `split`.

Splitting a balance across VAS codes needs an **allocation basis** that the map does not carry, and inventing one would produce a statutory return nobody could tie back.
So those accounts are reported for a human to allocate.

<Note>
  This is a deliberate refusal, and it is the same instinct as the [suspense-account rule](/greatbook/capabilities/chart-of-accounts) and the [FX quarantine](/greatbook/capabilities/fx): where the system does not have the information to decide, it says so rather than choosing plausibly.
  A statutory return produced by a guess is worse than one that arrives incomplete, because the guess is invisible in the filed document.
</Note>

Two accounts affected in the seeded chart are social insurance payable, which maps to three VAS codes, and depreciation, which maps to two.

## Read-only, end to end

Every connection is opened through the Auditor's [provably read-only channel](/greatbook/agents/auditor#read-only-enforced-by-the-database), so the database rejects a write regardless of what the module asks for.

A report that could change the book it reports on is not a report.

## Where it is enforced

| Concern                                     | Code                                                                        |
| ------------------------------------------- | --------------------------------------------------------------------------- |
| all four reports                            | `langgraph_chat/agents/accountant/statutory.py`                             |
| the account-to-VAS map                      | `backend/app/logics/finance/coa_seed.py`, migration `0002_gl_guards_fx_rls` |
| the read-only channel                       | `langgraph_chat/agents/accountant/gl_read.py`                               |
| the HTTP surface                            | `langgraph_chat/devcenter/stmt_api.py`                                      |
| the close step that checks mapping coverage | `agents/accountant/close.py`, the `statutory` step                          |

The close checklist's `statutory` step is a **warning**, not a block on the books.
An account with no TT200 mapping means the return cannot be produced from it, which is a problem for filing rather than a problem with the ledger.

## The test that would fail if it broke

`langgraph_chat/agents/accountant/tests/` covers the four reports against a real migrated GL, including the trial balance's zero-sum property, the balance-sheet equity carry, and the unmapped-account report.

## What goes wrong without it

**Independent report queries.**
The P\&L says one profit and the balance sheet's equity movement says another, and the difference is one query's `status` filter.
Reconciling two reports that should be the same report is a recurring monthly cost and it never gets easier.

**A silent statutory projection.**
Accounts with activity and no mapping drop out of the return with no indication, so the filed numbers are lower than the book's and nothing says which accounts went missing.

**A guessed split.**
An account attributed across VAS codes by an invented allocation basis produces a return that cannot be tied back to the ledger by anyone, including the person who filed it.

## Related

* [The dual IFRS + TT200 chart](/greatbook/capabilities/chart-of-accounts) - the map this projects through
* [Fiscal periods and closing](/greatbook/capabilities/periods-and-close) - the close step that checks mapping coverage
* [The Accountant](/greatbook/agents/accountant) - who produces these
* [VN VAT and statutory tax](/greatbook/capabilities/subledgers/vat-statutory) - the other statutory surface
