> ## 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.

# VN VAT and statutory tax

> The input and output VAT register, per-line integrity, the 133 and 3331 ties, the cash deductibility rule, and foreign-contractor tax.

# VN VAT and statutory tax

Sub-ledger 5, migration `0007`.

## What it records

VAT is booked on the document by the sub-ledger that raises it: input VAT (VAS 133) on bills by settlement and costing, output VAT (VAS 3331) on invoices by settlement.

This sub-ledger keeps the **register**: one `tax_entries` row per taxable line, carrying the base amount, the declared rate, the tax amount, the GL account, the document date, the received date, the period and the deductibility flag.

That register is what makes the per-line integrity check and the received-date deductibility rule possible.
It also adds foreign-contractor tax, which has no document-level twin.

## Native and posted-base evidence

`tax_entries.tax_amount` remains the statutory tax amount in the document's native currency.
For every new row, the register also stores the journal line's native currency, exact posted base amount, exact immutable entry/line links, and `journal_line` as the base-evidence kind.

The register writer finds that line inside the same posting transaction by organization, entry, control account, side and native amount.
It does not accept or resolve an FX rate again.
The ledger writer remains the one authority for as-of-date conversion and rounding, and the register records the exact base result already posted.

`VAT-133-TIE` and `VAT-3331-TIE` compare register base to GL base.
Their evidence also reports native totals by currency rather than adding unlike currencies together.
A period-scoped read is cumulative through that fiscal period's end on both sides.

Historical rows were not backfilled.
A legacy row may be valued only when its durable entry link and native facts identify one exact same-organization journal line; missing, ambiguous, cross-organization or contradictory evidence makes the result **partial** or **inconclusive**.
A reversal is never re-rated: it counts only when the reversing line exactly swaps the original native amount, base amount, currency and stored rate.

## The account legs

| Operation                | Entry                                                                       |
| ------------------------ | --------------------------------------------------------------------------- |
| input VAT on a bill      | `Dr 1300` (VAS 133) - booked with the bill                                  |
| output VAT on an invoice | `Cr 2100` (VAS 3331) - booked with the invoice                              |
| FCT withholding          | `Dr <expense>` / `Cr 2130` (VAS 333821 VAT-FCT + 333822 CIT-FCT)            |
| VAT remittance           | `Dr 2100` / `Cr 1300` / `Cr <net payable>`, then `Dr payable` / `Cr <rail>` |

## Input VAT is an asset, not a cost

This is the point most easily got wrong, so it is worth stating plainly.

Vietnamese input VAT (thuế GTGT được khấu trừ) is **recoverable**.
The business offsets it against output VAT rather than bearing it.
So it belongs on `1300` as an asset, not inside the expense or inventory leg it arrived with.

A supplier VAT invoice for 1,000,000 net plus 100,000 VAT posts three legs:

```
Dr 1200  Inventory                1,000,000     net
Dr 1300  Input VAT recoverable      100,000     recoverable
Cr 2000  Accounts payable         1,100,000     gross, what the supplier is owed
```

Booking the whole 1,100,000 to inventory overstates the purchase, understates a real asset, and leaves the VAT return with nothing to declare.
Critically, that two-leg entry **balances**, so no GL invariant catches it: this is a Close-checksum-shaped defect, not an invariant-shaped one.

<Info>
  **Both origins split correctly.**
  A payable raised through the sub-ledgers always did.
  A payable that arrives as a **document** through the intake pipeline now does too: the recoverable VAT is peeled onto `1300`, the gross stays the anchor for the AP credit and its obligation, the net is derived as `gross - VAT`, and a typed `InconsistentVatError` is raised rather than choosing between three extracted figures that do not add up.
  The register line is written in the **same transaction** as the entry, through this sub-ledger's own register writer rather than a second insert.
  Full rule on [Payables and input VAT](/greatbook/gl/rules-payables); the agent that applies it is [the Bookkeeper](/greatbook/agents/bookkeeper).
</Info>

<Note>
  Rows posted **before** that change carry their VAT inside the expense or inventory leg.
  They need a bookkeeping correction rather than a document edit, and no Close checksum fails on them - the register ties at 0 against 0 - which is precisely why the split is asserted directly by a test rather than left to a reconciliation to find.
</Note>

## `1300` is a control account

The same rule that governs AP control `2000` governs input VAT `1300`: a debit to it with nothing in the register behind it is a balance the sub-ledger cannot explain.

`VAT-133-TIE` compares the `tax_entries` register total against the GL `1300` balance.
Two independent paths, one from the register and one from the ledger, that must agree.

That is why the register line has to travel with the leg rather than being written afterwards by a separate process, and in the agent path it is re-derived from the re-read record and written through the backend's own `tax.record_vat_entry` in the **same transaction** as the entry.

## Capability and MCP status

VAT and tax Books is a current, executable registry outcome served through the shared Books family, register and tie-out tools.
That read surface exposes native structures, accounting links, 35-day freshness, exact maker/checker evidence where applicable, Assurance findings and control state.
It does not create or edit a tax entry.
The recoverable input-VAT split onto VAS 133 is finished posting behavior in the canonical Bookkeeper/sub-ledger transaction, not an MCP calculation or a future adapter.

## Per-line integrity

```
tax_amount == ROUND(base_amount x declared_rate)
```

Checked per line, in both directions.
`VAT-INTEGRITY-IN` for input, `VAT-INTEGRITY-OUT` for output.

The output-side twin is a GreatBook addition: the v12 workbook's B54 only covered input VAT, which meant a mistyped output VAT amount had nothing checking it.

<Note>
  This is where [the rounding rule](/greatbook/capabilities/money) becomes load-bearing.
  `ROUND_HALF_UP` at four decimal places is what makes `ROUND(base x rate)` reproduce the supplier's own figure.
  Banker's rounding would differ by one dong on roughly half of all VAT lines, and every one of those would fail this check for a reason invisible in the numbers.
</Note>

## The cash rule

A cash payment at or above **5,000,000 VND** loses input-VAT deductibility under Vietnamese rules.

`VAT-CASH-5M` is the must-be-zero check for it, and `VAT-NONDEDUCTIBLE` is the explainable balance that reports how much input VAT was lost to the rule.
Reporting the amount rather than only the count is deliberate: a business that keeps paying suppliers over the threshold in cash wants to see the number that behaviour costs it.

## The checks

| Code                                                     | Kind        | What it is                                                   |
| -------------------------------------------------------- | ----------- | ------------------------------------------------------------ |
| `VAT-INTEGRITY`, `VAT-INTEGRITY-IN`, `VAT-INTEGRITY-OUT` | zero        | per-line `tax == ROUND(base x rate)`                         |
| `VAT-133-TIE`                                            | zero        | input VAT register equals GL `1300`                          |
| `VAT-3331-TIE`                                           | zero        | output VAT register equals GL `2100`                         |
| `VAT-CASH-5M`                                            | zero        | no input VAT claimed on a cash payment at or above 5,000,000 |
| `VAT-INPUT`, `VAT-OUTPUT`, `VAT-NET`                     | explainable | the current positions, and the net payable or recoverable    |
| `VAT-NONDEDUCTIBLE`                                      | explainable | input VAT lost to the cash rule                              |
| `FCT-PAYABLE`                                            | explainable | foreign-contractor tax payable on `2130`                     |

## Foreign-contractor tax

FCT withholds from a foreign contractor's gross: the expense is recognised gross, the contractor is paid net, and the withholding splits into a VAT component and a CIT component on `2130`.

The split into `333821` (VAT-FCT) and `333822` (CIT-FCT) is a GreatBook design extension.
The workbook carries FCT only as a capture-document shape with a single combined rate, which is not enough to file from.

## Where it is enforced

| Concern                                           | Code                                                                  |
| ------------------------------------------------- | --------------------------------------------------------------------- |
| the register, FCT, remittance                     | `backend/app/logics/finance/tax.py`                                   |
| the account constants and the 5,000,000 threshold | `tax.INPUT_VAT`, `tax.OUTPUT_VAT`, `tax.CASH_VAT_THRESHOLD`           |
| the schema                                        | migrations `0007_vat_statutory` and `0049_vat_register_base_evidence` |
| the derived positions                             | `derive.input_vat_total`, `output_vat_total`, `net_vat_position`      |
| the checks                                        | `close_checks.run_vat_checks`                                         |

## The test that would fail if it broke

`backend/tests/test_vat.py` covers the register, the integrity rule and the ties, against the v12 worked data: input VAT 5,800,000, output 0, net 5,800,000 recoverable.
`backend/tests/test_vat_register_base_truth.py` covers exact journal-line evidence, foreign currency, legacy ambiguity, reversals and period scope.

## What goes wrong without it

The VAT return is filed from the register, and the register is what a tax audit examines line by line.
Without the per-line integrity rule, a mistyped VAT amount on one bill produces a return that is internally consistent and does not match the supplier's invoice, which is exactly the discrepancy an audit finds.

Without the `133` tie, the balance sheet claims a recoverable asset the register cannot substantiate.

## Related

* [Money is Decimal, always](/greatbook/capabilities/money) - the rounding rule this family depends on
* [Settlement, rails and the AP/AR spine](/greatbook/capabilities/subledgers/settlement) - where input and output VAT are booked
* [Statutory reporting](/greatbook/capabilities/statutory-reporting) - the TT200 projection
* [The Bookkeeper](/greatbook/agents/bookkeeper) - the document-sourced posting path
