French CTC: split into per-flow addons + validation fault-ignore mechanism (APP-509)#820
French CTC: split into per-flow addons + validation fault-ignore mechanism (APP-509)#820alvarolivie wants to merge 37 commits into
Conversation
Introduce two new French CTC addons — reporting (Flow 10, on bill.Invoice and bill.Payment) and lifecycle status (Flow 6, on bill.Status) — and reorganise Flow 2 under addons/fr/ctc/flow2/ so the three variants sit side by side. Flow 10 (e-reporting) covers B2B and B2C invoices plus B2B and B2C payments, gated by a b2c tag. Validates billing mode (G1.02), allowed UNTDID document types, final-after-advance invariant (G1.60), currency convertibility to EUR, address country, supplier/customer legal scheme (G2.19), VAT ID when scheme is SIREN/EU-VAT (G2.33), exempt categories, G1.24 rate whitelist on invoices and payments, B2C transaction category (G1.68), and payment receipt/lines/document refs. Normalizes SIREN and EU VAT identities from TaxID, defaults billing mode (M1/M2) and the B2C category (TNT1), and maps rate keys to UNTDID 5305 categories. Flow 6 (CDV lifecycle) is standalone — does not require Flow 2. Carries the authoritative tables gobl.cii reads for the CDAR round-trip: ProcessConditionCode 200–213 (extends bill.StatusEvents with 8 France-specific keys), 45 ReasonCodes with bucket + default-for-key flag, 7 RequestedActionCodes. Three extensions (fr-ctc-role, fr-ctc-reason-code) plus a Characteristic complement covering MDT-207 and the MEN for paid lines. Validations for the rules surfaced in BR-FR-CDV (supplier SIREN, doc code/issue-date, reason required on rejection-like statuses, TypeCode whitelist, characteristic ReasonCode link to sibling Reason); the Type-dependent role and recipient routing rules are intentionally left to PPF-side business logic. The Flow 2 move (addons/fr/ctc/ → addons/fr/ctc/flow2/) renames the package to flow2 and shortens Flow2Key/Flow2V1 to Key/V1. addons.go blank-imports all three flows. Tests are one _test.go per source file in each package (internal package so unexported helpers are reachable), with individual named tests wired to tiny per-axis helpers instead of table-driven loops. Coverage: flow2 93.0%, flow10 90.1%, flow6 96.4%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #820 +/- ##
==========================================
+ Coverage 93.50% 93.87% +0.36%
==========================================
Files 369 380 +11
Lines 20259 21783 +1524
==========================================
+ Hits 18944 20449 +1505
- Misses 877 898 +21
+ Partials 438 436 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
- Five GOBL example documents covering the new addons: - Flow 10 B2B invoice, B2C invoice, B2B payment - Flow 6 accepted status, paid status with MEN complement - Flow 6 now enforces exactly one StatusLine per bill.Status (CDAR carries a single status per CDV message) - Tighten Flow 2 description copy Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each source file now matches a single domain: bill_invoice.go owns the invoice rules, normalizers, and shared VAT-key map; bill_payment.go owns the payment rules and helpers. The catch-all bill.go file is removed; tests follow the same split. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merge bill.go (invoice helpers) and bill_invoices.go (invoice rules) into a single bill_invoice.go matching the flow10 layout. Tests follow the rename. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Tighten descriptions on rules 03/04 (corrective preceding), 09 (factoring vs advance-payment doc type), 24/25 (consolidated credit note contracts) so each message says what it actually checks. - Default the flow2 billing mode the same way flow10 does — M2 if Totals.Paid(), M1 otherwise; user-supplied values are preserved. - Auto-fill the three BR-FR-05 regulatory mentions (PMT / PMD / AAB) with minimal, business-neutral text when missing. - Auto-fill the BR-FR-CO-14 TXD / MEMBRE_ASSUJETTI_UNIQUE note when the supplier carries an STC-scheme (0231) identity. - Regenerate data/ artefacts via go generate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The flow2 test files were external (package flow2_test) so the defensive nil / wrong-type paths in unexported helpers were unreachable, dragging coverage below the rest of the suite. Switching to package flow2 lets the same one-test-per-source layout reach the helpers; adding a focused set of nil/wrong-type tests pushes coverage to 97.5%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lint flagged "TXD", "MEMBRE_ASSUJETTI_UNIQUE", and "peppol" as repeated literals. Lift the first two into noteSubjectTXD / stcMembreAssujettiUnique constants in flow2/bill_invoice.go, and switch all "peppol" references to the existing org.InboxKeyPeppol constant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pull "BAR" / "B2B" out of bill_invoice.go into noteSubjectBAR and barTreatmentB2B so the goconst lint stops complaining and the isB2BTransaction / notesValidBARText helpers read clearly. No behaviour change: the BAR note is intentionally not auto-defaulted — its value (B2B / B2BINT / B2C / OUTOFSCOPE / ARCHIVEONLY) is transaction-specific and must come from the caller. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per BR-FR-22 ("règle à exécuter si la facture fait l'objet d'un
traitement B2B ou si elle contient une note (BG-1) avec un code sujet
(BT-21) = BAR et un contenu (BT-22) = B2B"), the B2B-specific rules
should fire whenever flow2 is in scope — flow2 *is* the B2B addon —
unless the caller explicitly opts the invoice out via a BAR note with
a non-B2B treatment (B2BINT / B2C / OUTOFSCOPE / ARCHIVEONLY).
Previously isB2BTransaction returned true only when an explicit BAR=B2B
note was present, which silently let invoices skip the customer-SIREN,
supplier-SIREN-inbox and self-billed-customer-inbox checks. Flip the
default so absence of a BAR note keeps the B2B path active.
The international b2bint example is updated to carry an explicit
BAR=B2BINT note to opt out, with no Key on the note so the en16931
normalizer doesn't rewrite the subject code based on note.Key.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR expands the France CTC support by introducing two new addons (Flow 10 e-reporting and Flow 6 lifecycle statuses), while reorganizing and tightening the existing Flow 2 addon implementation and updating rules, schemas, and examples accordingly.
Changes:
- Add
fr-ctc-flow10-v1(Flow 10) addon with scenarios/tags, validation + normalization for invoices and payments, and new examples. - Add
fr-ctc-flow6-v1(Flow 6) addon forbill.Statuslifecycle messages, including aCharacteristiccomplement schema, code tables, validation/normalization, and new examples. - Move/rename Flow 2 into
addons/fr/ctc/flow2(package rename + API rename), add normalization defaults (billing mode + required mentions), and refine rule descriptions.
Reviewed changes
Copilot reviewed 48 out of 54 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/ops/bulk_test.go | Updates schema list fixture to include the new Flow 6 characteristic schema. |
| examples_test.go | Skips an additional path during examples scanning. |
| examples/fr/status-fr-fr-ctc-flow6-paid.yaml | New Flow 6 “paid” status example (includes characteristic/MEN). |
| examples/fr/status-fr-fr-ctc-flow6-accepted.yaml | New Flow 6 “accepted” status example. |
| examples/fr/payment-fr-fr-ctc-flow10-b2b.yaml | New Flow 10 B2B payment receipt example. |
| examples/fr/out/status-fr-fr-ctc-flow6-paid.json | Generated output for the Flow 6 “paid” status example. |
| examples/fr/out/status-fr-fr-ctc-flow6-accepted.json | Generated output for the Flow 6 “accepted” status example. |
| examples/fr/out/payment-fr-fr-ctc-flow10-b2b.json | Generated output for the Flow 10 B2B payment example. |
| examples/fr/out/invoice-fr-fr-ctc-flow10-b2c.json | Generated output for the Flow 10 B2C invoice example. |
| examples/fr/out/invoice-fr-fr-ctc-flow10-b2b.json | Generated output for the Flow 10 B2B invoice example. |
| examples/fr/out/invoice-fr-de-ctc-b2bint.json | Updates generated output (adds BAR note + digest changes). |
| examples/fr/invoice-fr-fr-ctc-flow10-b2c.yaml | New Flow 10 B2C invoice input example. |
| examples/fr/invoice-fr-fr-ctc-flow10-b2b.yaml | New Flow 10 B2B invoice input example. |
| examples/fr/invoice-fr-de-ctc-b2bint.yaml | Updates input example to include BAR note. |
| data/schemas/tax/addon-list.json | Registers Flow 6 and Flow 10 addon keys in the addon list schema. |
| data/schemas/addons/fr/ctc/flow6/characteristic.json | New JSON Schema for the Flow 6 characteristic complement. |
| data/rules/fr-ctc-flow6.json | New rule definitions for Flow 6 validations. |
| data/rules/fr-ctc-flow2.json | Updates Flow 2 rule descriptions for clarity/accuracy. |
| data/rules/fr-ctc-flow10.json | New rule definitions for Flow 10 validations. |
| data/addons/fr-ctc-flow6-v1.json | New addon definition for Flow 6 (extensions + sources). |
| data/addons/fr-ctc-flow2-v1.json | Updates Flow 2 addon definition text (removes currency conversion note). |
| data/addons/fr-ctc-flow10-v1.json | New addon definition for Flow 10 (extensions, tags, scenarios). |
| addons/fr/ctc/item_test.go | Removes old CTC-level item meta validation tests (moved under Flow 2 tests). |
| addons/fr/ctc/flow6/org_party_test.go | Adds Flow 6 party extension/scheme validation tests. |
| addons/fr/ctc/flow6/org_party.go | Adds Flow 6 org.Party validation for role code + allowed identity schemes. |
| addons/fr/ctc/flow6/flow6.go | Registers Flow 6 addon, schema objects, rules, and normalizer. |
| addons/fr/ctc/flow6/extensions_test.go | Tests helper for unwrapping extensions passed by pointer/value. |
| addons/fr/ctc/flow6/extensions.go | Defines Flow 6 extensions + builds reason-code value list from table. |
| addons/fr/ctc/flow6/complements.go | Defines Flow 6 Characteristic type + MDT-207 type-code whitelist. |
| addons/fr/ctc/flow6/codes_test.go | Tests Process/Reason/Action code-table mappings and round-trips. |
| addons/fr/ctc/flow6/codes.go | Implements ProcessCondition/Reason/Action code tables and lookups. |
| addons/fr/ctc/flow6/bill_status_test.go | Adds Flow 6 status validation + normalization tests. |
| addons/fr/ctc/flow6/bill_status.go | Implements Flow 6 bill.Status/bill.Reason/bill.Action validation + normalization. |
| addons/fr/ctc/flow2/tags.go | Renames package from ctc to flow2. |
| addons/fr/ctc/flow2/org_test.go | Updates Flow 2 tests for package/API rename; adds/moves item meta tests here. |
| addons/fr/ctc/flow2/org_party.go | Renames package to flow2. |
| addons/fr/ctc/flow2/org.go | Renames package; switches inbox peppol key handling to constants. |
| addons/fr/ctc/flow2/flow2.go | Renames Flow 2 package and exports (Key/V1); updates registration/guard. |
| addons/fr/ctc/flow2/extensions.go | Renames package to flow2. |
| addons/fr/ctc/flow2/bill_invoice.go | Adds Flow 2 normalization defaults (billing mode + required mentions + TXD note) and BAR logic; updates rule descriptions. |
| addons/fr/ctc/flow10/tags.go | Adds Flow 10 B2C tag definition for invoices/payments. |
| addons/fr/ctc/flow10/scenarios.go | Adds Flow 10 scenarios mapping invoice types/tags → UNTDID document types. |
| addons/fr/ctc/flow10/party_test.go | Adds unit tests for Flow 10 party normalization/helpers. |
| addons/fr/ctc/flow10/party.go | Adds Flow 10 party normalization + legal scheme selection helpers. |
| addons/fr/ctc/flow10/flow10.go | Registers Flow 10 addon, rules, scenarios, tags, and normalizer. |
| addons/fr/ctc/flow10/extensions.go | Defines Flow 10 extensions and billing mode / B2C category values. |
| addons/fr/ctc/flow10/bill_payment_test.go | Adds Flow 10 payment validation tests. |
| addons/fr/ctc/flow10/bill_payment.go | Adds Flow 10 payment validation (receipt-only, value date, VAT whitelist, supplier SIREN, B2B doc refs). |
| addons/fr/ctc/flow10/bill_invoice_test.go | Adds Flow 10 invoice validation + normalization tests (B2B/B2C). |
| addons/fr/ctc/flow10/bill_invoice.go | Adds Flow 10 invoice validation + normalization (billing mode default, VAT whitelist, exempt rules, party scheme rules). |
| addons/fr/ctc/bill.go | Removes old shared CTC bill helpers (now Flow 2–scoped). |
| addons/addons.go | Registers new Flow 2/6/10 addon packages instead of the old monolithic CTC package. |
| CHANGELOG.md | Documents addition of Flow 6 and Flow 10 addons. |
Comments suppressed due to low confidence (1)
addons/fr/ctc/flow2/bill_invoice.go:838
- notesValidBARText currently allows a BAR note with an empty Text value to pass validation, but the corresponding rule message states the BAR text must be one of the allowed treatment values. If a BAR note is present, its Text should be non-empty and within allowedBARTreatments; otherwise return false so invalid/blank BAR notes don’t silently disable B2B processing.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The b2c distinction is naturally captured by Customer presence — a B2C sale is to an unidentified consumer, so the Customer slot is left unset. Drop the addon-specific TagB2C tag, the tags.go file, and the Tags wiring on the addon definition; flip invoiceIsB2C / paymentIsB2C to read Customer == nil. The b2c example loses its $tags and customer block accordingly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The supplier-SIREN rule fires on both B2B and B2C, so the addon must also derive a SIREN-scheme identity from a French TaxID for B2C suppliers that ship without an Identities entry. Move normalizeParty calls before the B2C early return — Customer is nil for B2C so its call is a harmless no-op — and keep the B2C-specific bits (default TNT1 category) after. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The per-code Go comments said "Deposit of an already paid X invoice" (and similar) which contradicted the documented suffix semantics — the 2-suffix means "already paid", not "deposit". Rewrite each comment to state the actual meaning (B/S/M = goods / services / mixed; suffix = payment context), and add a header summarising the convention. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Require Issuer and Recipient (MDG-16, MDG-23) with valid roles per BR-FR-CDV-CL-03 / CL-04; recipient must carry an inbox unless its role is WK or DFH (BR-FR-CDV-08). - Add a CDV "side" mapping (Annexe A "Acteurs CDV") that pins each process code to buyer-issued / seller-issued / platform-issued, and use it in normalize to fill the fr-ctc-role on Issuer and Recipient when the caller leaves it empty. - Propagate the SE-roled party's SIREN onto Supplier when missing so ref.IssuerTradeParty (MDT-129) is populated without forcing the caller to repeat the seller in a separate slot. - Add the BR-FR-CDV-CL-09 per-status allowed-reason-code table and validate it at the bill.Status level. - Reuse stock GOBL keys: paid + update -> 211, paid + response -> 212, acknowledged + response -> 202, querying + response -> 208 (drop payment-forwarded / received-by-platform / suspended additions). - Move the BR-FR-CDV-14 paid-MEN check to the status level so it only fires for response-phase paid (CDV-212), not transmission (CDV-211). - Refresh the FR Flow 6 examples to match. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Share the inbox-when-not-WK/DFH helper across issuer and recipient. CDAR DocumentTypeCode 23 is always the case for this addon, so BR-FR-CDV-08 applies unconditionally to both parties; malformed imports are rejected on the CII side instead. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror the paid/211/212 pattern: the `issued` key now covers both update/200 (Déposée) and response/201 (Émise par la plateforme), with Status.Type distinguishing the two. Callers reporting platform-side issuance no longer need a separate event key. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add fr-ctc-status-code, populated by the normalizer from (line.Key, Status.Type) and cross-checked at validation time. Makes the wire-level event identifier visible on the GOBL document and gives callers round-tripping a parsed CDV a place to pin a specific code. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror normalizeReason: the ext and the (key, type) pair are two sides of the same lookup. When the caller pins a CDAR ProcessConditionCode but leaves the line's Key (and the Status.Type) blank, the normalizer fills them from the process table. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Folds the three former sub-addons (fr-ctc-flow2-v1, fr-ctc-flow6-v1, fr-ctc-flow10-v1) into a single fr-ctc-v1 addon under addons/fr/ctc. Invoice rule sets are now dispatched at validation time based on whether both parties resolve as French (SIREN identity or French tax ID): both French → Flow 2 clearance, otherwise → Flow 10 e-reporting. Flow 6 lifecycle messages (bill.Status) and payment receipts (bill.Payment) run their own rule sets unconditionally. eu-en16931-v2017 is no longer a hard Requires; the Flow 2 branch enforces it as a soft assertion so Flow 10 / Flow 6 callers don't have to pull it in. Examples renamed for clarity: payment-fr-fr-ctc-flow10-b2b is replaced by payment-fr-de-ctc-b2bint (cross-border B2B receipt), and invoice-fr-fr-ctc-flow10-b2b is removed (a domestic FR-FR B2B invoice belongs in Flow 2, not Flow 10). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…/ status Ports the deleted flow2/flow6/flow10 test files into the consolidated addons/fr/ctc package: - codes_test.go: CDAR ProcessConditionCode / ActionCode / ReasonCode round-trip + lookup misses - extensions_test.go: extValue defensive branches - org_test.go: SIREN-inbox validation, peppol-key normalisation, identity scheme format (BR-FR-CO-10), private-id (0224) normalisation, SIREN-from-SIRET derivation, party / inbox / item meta edge cases (flow2 + flow10 + flow6 merged) - bill_payment_test.go: payment receipt rules — VAT rate whitelist, supplier SIREN, per-line invoice refs for B2B - bill_status_test.go: Flow 6 lifecycle rules — exactly-one-line, SIREN propagation, MEN amount on paid response, reason-code link, MDT-207 type codes - helpers_test.go: shared addonContext / runNormalize / party builders Coverage rises from 0% to ~57%. bill_invoice tests still to port. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Combines the deleted flow2/bill_invoice_test.go and flow10/bill_invoice_test.go into a single test file against the merged addon. Adaptations: - declare eu-en16931-v2017 alongside fr-ctc-v1 on Flow 2 fixtures (the addon no longer hard-Requires it; rule 02 enforces it softly) - carry iso-scheme-id ext on every identity so BR-FR-CO-10 accepts them - swap renamed helpers (extensionsValue -> extValue, invoiceIsB2BAny -> invoiceIsCrossBorderB2BAny, normalizeInvoiceBillingMode -> normalizeBillingMode) - drop BAR-note dispatcher tests (the merged code routes on party residency, not on the BAR note); Flow 10 cross-border cases now use deCustomerWithVATID() - match on rule messages instead of the renumbered fault codes Coverage rises from ~57% to 92% on the fr-ctc package. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes the addon-wide org.Party identity scheme allow-list. It was a Flow 6 (CDV) constraint that had crept into the addon-wide ruleset, rejecting legitimate Flow 10 cross-border B2B invoices whose foreign counterparty carries a secondary identifier in a scheme outside the French / CDAR list. - org.go: keep only allowedFlow6IdentitySchemes; STC (0231) stays out - org_party.go: drop rule 04 (partyIdentitySchemeAllowed) and the helper; SIRET/SIREN coherence + scheme-format checks remain - bill_status.go: new rule 22 enforces allowedFlow6IdentitySchemes across the four party slots on a bill.Status (Supplier, Customer, Issuer, Recipient), so STC and other non-CDV schemes are still rejected where they actually matter - Tests: add the STC invoice happy-path (now reachable because rule 04 no longer blocks 0231), the tax-rep exempt path via a non-EU supplier, and the CDV-rejects-STC case; replace the now-obsolete "unknown scheme rejected addon-wide" test with its inverse Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts: # addons/fr/ctc/bill_test.go # addons/fr/ctc/org_test.go # internal/ops/bulk_test.go
- bill_invoice.go:898: collapse the if-then-return / return-true pair into a single `return strings.HasPrefix(...)` so staticcheck S1008 stops flagging it - defensive_test.go: add nil / wrong-type / empty-slice tests for the predicate helpers and normalisers whose defensive guards were previously unreached (setPartyRoleDefault, partyHasRole, partyHasInboxWhenRequired, ensureSIRENOnSupplier, isPartyIdentitySTC, the is*Invoice family, statusReasonCodesAllowed, etc.). Coverage: 91.7% -> 94.6% Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- bill_status.go: rename siRENFromSEParty -> sirenFromSEParty (S/N1)
- extensions.go: rewrite fr-ctc-role values + descriptions to match
the French CTC specification of MDT-158 (CDAR RoleCode). Labels
for WK and DFH were generic UNCL 3035 ("Work/Service receiver",
"Delivery From") but CDAR assigns them CDAR-specific meanings:
WK = dematerialisation platform / operator, DFH = Portail Public
de Facturation. Updated all role names (BY Acheteur, DL Affactureur,
AB Agent d'acheteur, SR Agent de vendeur, etc.) and added French
translations.
- bill_status.go: align BR-FR-CDV-08 comment with the corrected WK /
DFH meanings.
- org.go: normalizeIdentity now maps SIREN Type -> iso-scheme-id
0002 and SIRET Type -> 0009 directly, so downstream validators can
rely on the scheme-id ext being present even when eu-en16931 is
not declared (Flow 6 / standalone Flow 10).
- Updated TestPrivateIDNormalization to reflect the new contract.
Copilot comments on the deleted flow10 files (early-return party
normalisation; inverted billing-mode comments) are already resolved
by the consolidation merge.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- tax/addons.go: HasAddon now takes ...cbc.Key. Returns true when the object declares at least one of the listed addons (semantics symmetric with AddonIn). Backwards-compatible with single-key callers. - addons/fr/ctc/bill_invoice.go: drop the local invoiceHasEN16931Addon helper; rule 02 now reads `tax.HasAddon(en16931.V2017)` directly. - addons/fr/ctc: rename helpers_test.go -> ctc_test.go (paired with ctc.go) and dissolve defensive_test.go — its nil / wrong-type / empty-slice tests are redistributed to bill_invoice_test.go, bill_status_test.go, codes_test.go and org_test.go alongside the source they exercise. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aligns naming with the underlying value (G1.24 is a whitelist of VAT percentages, not a tax-rate object). Renames cover the variable, the predicate helpers, is.Func labels, rule messages and tests: - allowedVATRates -> allowedVATPercents - invoiceVATRatesAllowed -> invoiceVATPercentsAllowed - paymentVATRatesAllowed -> paymentVATPercentsAllowed - TestPaymentVATRate* -> TestPaymentVATPercent* - TestInvoiceB2CVATRateNot* -> TestInvoiceB2CVATPercentNot* Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ill schemas - Switch the two example status-system YAMLs (anomaly, shutdown) to the new `other` line key; arbitrary custom keys are no longer accepted now that bill.StatusLine keys are a closed set with an explicit Other entry. - Regenerate the four affected example output snapshots (es status, fr flow10 invoices) to pick up the recent normalization changes (untdid-tax-category on VAT combos, line-key fixes). - Add bill/action, bill/fault, bill/reason, bill/status-line to the schemas golden list in internal/ops/bulk_test.go so the schemas bulk-action test reflects the new bill types. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Picks up the new bill types (Action, Fault, Reason, StatusLine), the closed-set status line key change, the STATUSLINE-02 assertion message fix, and the StatusLineOther entry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Linter (golangci-lint):
- gofmt addons/fr/ctc/flow10/extensions.go and addons/fr/ctc/flow2/org.go
- correct the bill.Fault type doc comment ("Faults" -> "Fault")
- rename the `any`-shadowing locals in rules/is/any_of_test.go
- remove the unused issuerParty/recipientParty test helpers in flow6
Coverage: add direct unit tests for the new guard/predicate helpers
introduced by this PR, which were previously exercised only indirectly:
- bill.PaymentTypeIn / StatusTypeIn / StatusLineKeyIn (bill/guards_test.go)
- org.IdentitiesExtensionIn (org/identity_test.go)
- flow2 predicates: precedingDocCodeValid, notesHaveTXD,
finalInvoiceAdvancesMatch, finalInvoicePayableZero, identitiesNoDupExt
- flow10 predicates: partyHasVATCode, invoiceHasSellerVATIDForExempt,
invoiceHasExemptTaxNote
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add direct unit tests for the flow2/flow6/flow10 normalizers, party helpers and rule predicates that were previously exercised only indirectly (or not at all): - flow2: org normalizers/helpers (normalizeParty, ensureSIRENIdentity, identity & inbox validators, meta/scheme guards) and bill_invoice predicates (billing mode, STC note, attachments, due dates, notes, tax-ext guards). - flow6: org normalizers/validators, extValue, partyRoleKnown, the reason-code->key reverse mapping, and prepareStatusWithLine. - flow10: org scheme/identity helpers and bill VAT-percent / exempt predicates. Also remove dead production helpers in flow6 that were referenced only by their own tests (statusPartiesIdentitySchemesAllowed, partyHasRole, ensureSIRENOnSupplier), and simplify flow2's ensureIdentity to ensureSIRENIdentity since it only ever creates SIREN identities (fixes a golangci-lint unparam finding). Package coverage: flow2 ~98%, flow6 ~97%, flow10 ~99%. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- AddAddons: append, skip-empty, skip-duplicate, in-call dedupe, no-op and nil-receiver branches. - SetAddons: set and wholesale-replace. - ExtractNormalizersForNew: nil object, non-addons object, unseen-key collection with seen-map update, already-seen skipping, idempotent repeat pass, and the incremental meta-addon case where a second pass after AddAddons returns only the newly-introduced addon. All three reach 100% coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| // of the suggested values. | ||
| func IdentitiesExtensionIn(key cbc.Key, value ...cbc.Code) rules.Test { | ||
| return identitiesTest{ | ||
| desc: fmt.Sprintf("has a ext [%s] in [%s]", key, strings.Join(cbc.CodeStrings(value), ", ")), |
Restructures French CTC support and introduces general-purpose
fault-suppression mechanisms motivated by it.
French CTC refactor (
addons/fr/ctc/)The previously-monolithic
fr-ctc-v1is replaced by a meta-addon thatauto-dispatches based on document content, plus three flow-specific
sub-addons that operators can also declare directly:
fr-ctc-flow2-v1— domestic B2B clearance invoicesfr-ctc-flow6-v1—bill.Status/bill.Paymentlifecycle (CDV)fr-ctc-flow10-v1— B2C and cross-border B2B e-reporting (invoices + payment receipts)Shared DGFiP codes now live in the new
catalogues/dgfippackage(owns
dgfip-billing-mode, replacingfr-ctc-billing-mode). Flow 6exposes role / reason / status / condition / action extensions, each
with EN+FR labels and per-document-type allow-lists.
All three flow addons follow the conventions documented in the new
addons/README.md:tax.ExtensionsHasCodes,is.In,is.Present, …) over customis.Funcpredicates,rules.Forbase object (with frozen numbers after release),<context/object(s)> <field> <constraint> (<BR-code>).Validation framework — fault-ignore mechanism
A new way for addons or callers to relax a fault emitted elsewhere
(e.g. when the EXTENDED-CTC-FR profile drops EN16931 rules that GOBL's
addons/eu/en16931enforces):rules.Ignore(codes...)— aDefan active rule set declaresto suppress specific fully-qualified fault codes from the aggregate
result, order-independent.
rules.WithIgnore(codes...)— the same as a call-siterules.Validateoption, useful for one-off converter calls.head.Header.Ignore []rules.Code— a caller-supplied ignorelist that travels with the envelope and is covered by the envelope
signature when sealed. Targets format-conversion cases where a
specific fault is known-acceptable for a given document.
billmodel evolutionsrules.Testhelpersbill.PaymentTypeIn,bill.StatusTypeIn,bill.StatusLineKeyInfor use as guards insiderules.When(replacesad-hoc
is.Exprstring expressions).bill.StatusLinekeys are now a closed set with an explicitStatusLineOtherentry;StatusLine.JSONSchemaExtendenumerates themvia
OneOf.Pre-Review Checklist
And if you are part of the org: