Skip to content

fix: keep legal mentions, route buyers on their SIREN and surface PDP rejections - #21

Merged
btouchard merged 1 commit into
mainfrom
fix/pdp-rejection-2026015
Sep 5, 2026
Merged

btouchard merged 1 commit into
mainfrom
fix/pdp-rejection-2026015

Conversation

@btouchard

Copy link
Copy Markdown
Contributor

Follow-up of the SuperPDP rejection of invoice 2026015 (fr:213, BR-FR-05). Three root causes and one minor defect, each with tests.

Legal mentions survive user notes. Spec notes are merged with PMD/PMT/AAB instead of replacing them; a note without subject_code becomes AAI; a note carrying a legal code replaces the default of that code. Validate enforces exactly one note per legal code (BR-FR-05), so the CLI and create_invoice refuse before generation.

Buyer routing (BT-49). Resolution order: explicit electronic_address → SIREN (from SIRET) in 0225 → e-mail in EM only without any legal identifier. create_invoice writes the resolved address into the sidecar; send_invoice refuses a buyer whose scheme is not 0225/0002 and points to find_routing_address.

Rejection reasons. The SuperPDP client decodes data.reason and details[].notes[].contents[].content; send_invoice re-reads the lifecycle right after the deposit and returns the rejection with its reasons line by line; get_invoice_status exposes rejected/reasons; the journal gets pdp_rejected; the CLI prints them.

Registry label. New optional title field used as projet, first line name as last resort.

Tests: notes merge and BR-FR-05 (spec_test, rules_test), buyer routing, a regression replaying the 2026015 spec, SuperPDP reason decoding, and MCP tests for the sidecar routing, the refusal and a mocked fr:213 (httptest). Existing sidecars load unchanged.

Local CI replay: act -j cross green; test and oracle cannot run under act (Chrome fails to start in the container), so go vet ./..., go test ./... and go test -tags=ci ./internal/facturx -run TestOracle were replayed by hand with a real Chrome and Java — all green, Mustang PDF:valid XML:valid.

… rejections

Invoice 2026015 was rejected by the platform (fr:213) although the local
EN 16931 validator had passed it. Three defects lined up.

Notes replaced the legal mentions. A single context note in the spec
dropped PMD, PMT and AAB from the CII, which violates BR-FR-05. Notes are
now merged: the three mentions are always emitted, a spec note carrying
one of these codes replaces the default of the same code, and a note
without subject_code goes out as AAI. Validate enforces exactly one note
per legal code, so neither the CLI nor create_invoice can produce a file
that lacks one.

The buyer was routed on its e-mail. Without electronic_address, BT-49 was
EM:<email>, which no directory knows. Buyers now resolve like sellers:
explicit address, else SIREN (derived from the SIRET) with scheme 0225,
else e-mail only when no legal identifier exists. create_invoice writes
the resolved address into the sidecar so the file reflects the XML, and
send_invoice refuses a buyer whose address is not routable (0225/0002)
instead of letting the platform reject it.

The rejection reason never reached the user. The SuperPDP client only
read status_code and status_text; the reasons live in data.reason and
details[].notes[].contents[]. They are decoded, exposed on each event,
summarised as rejected/reasons by send_invoice and get_invoice_status,
and journaled as pdp_rejected. send_invoice reads the lifecycle once
right after the deposit, so a rejection comes back immediately rather
than as api:uploaded. The CLI prints them too.

Also: an optional title field is the registry's project label, with the
first line name as last resort only.

Documentation, the MCP prompt and the tool schema describe the new
behaviour. Existing sidecars load unchanged.
@btouchard
btouchard merged commit b15069d into main Sep 5, 2026
5 checks passed
@btouchard
btouchard deleted the fix/pdp-rejection-2026015 branch September 5, 2026 20:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant