# Conformance of the generated documents

`validate-cii.py` runs a CII document through the three stages a platform runs it through:

1. the CII D22B **XSD**;
2. the **XSLT of the profile the document declares** (BT-24) — the stage that carries the EN 16931
   arithmetic (`BR-CO-*`, `BR-S-*`) and the `FX-SCH-A-*` rules. Skipping it answers "0 failure" on
   documents an access point refuses;
3. the French CTC rules, **BR-FR-Flux2**.

The rules come from the FNFE `France_RFE` package (EUPL,
<https://github.com/fnfempe/France_RFE>), and Saxon-HE runs the compiled XSLT of that package.
Neither is vendored here: the CI fetches a pinned release, and so do you.

A Schematron refuses in two ways, and both are read. Besides the assertion that fails
(`svrl:failed-assert`), a `<report>` that fires produces an `svrl:successful-report`, and that is how
a profile XSLT states *"Element 'ram:X' is marked as not used in the given context"* for everything
the profile leaves out. A platform returns those as `REJ_COH`, so a document that fires one is
reported `INVALID` here, counted apart in the `N report(s)` of the stage line.

## The negative controls

A green run says something only once the chain is shown to refuse something. Two scripts build that
proof, from the very documents that were just accepted:

| script | the defect it rebuilds | what must refuse it |
|---|---|---|
| `damage-vat-rate.php` | #709, BT-119 at 0.00 against a non-zero BT-117 | `BR-CO-17`, a failed assertion |
| `damage-line-exemption.php` | #974, a VAT exemption reason on the invoice lines | the profile stage, as a **report** |

The second one exists for the shape of the first column, not only for its rule: it is refused by a
`<report>` alone, so a validator that reads only the failed assertions calls it valid. That is what
happened before this defect was found, and what the control keeps from happening again.

## Running it locally

```sh
curl -sSL -o france-rfe.tar.gz https://github.com/fnfempe/France_RFE/archive/refs/tags/v1.4.0.04.tar.gz
mkdir -p /tmp/france-rfe && tar xz -C /tmp/france-rfe --strip-components=1 -f france-rfe.tar.gz
curl -sSL -o /tmp/saxon.jar https://repo1.maven.org/maven2/net/sf/saxon/Saxon-HE/10.9/Saxon-HE-10.9.jar

export FNFE_ROOT=/tmp/france-rfe/FNFE_RFE_INVOICE SAXON_JAR=/tmp/saxon.jar
python3 einvoicing/test/conformance/validate-cii.py --quiet einvoicing/test/phpunit/fixtures/einvoicing_samples/*.xml
```

`--quiet` prints one line per document, `--strict` runs the fatal variant of the CTC-FR rules
instead of the warning one the online validator uses. The exit code is 1 as soon as one document
fails, and a profile the package ships no validator for is reported `SKIP` — never green.

Any CII document works, not only the ones committed here: point it at the XML of a real invoice
generated by the module when a change touches the generation.
