/** * Offline Schematron-like Validation * * Runs a small set of pure TypeScript pre-flight checks. Some reproduce a * Peppol BIS 3.0 business rule; others are explicitly GETPEPPR-local * diagnostics. This is NOT a full XSD/XSLT Schematron processor — it catches * common problems before the invoice reaches the network. * * ⛔ The registered checks counted by `coverage.rulesChecked` are exactly * those in `SDK_SCHEMATRON_RULE_IDS` (below), and that registry is the only * place the count lives. `validateSchematron()` can additionally emit the * legacy provider-routability diagnostic `unsupported_vat_category`, outside * that count. The separate VAT-only UBL-builder preflight can emit `SDK-INPUT`; * it does not return Schematron coverage. This header once said "~25" while the registry held a different * number — prose counts drift from one the code measures, and only the code can * be right. * `ubl-validation/__tests__/sdk-non-contradiction.test.ts` pins the length, so * adding or removing a rule without updating the registry reds. * * Rules are grouped by category: * - BR-xx — Required field rules (EN 16931) * - BR-CO-xx — Calculation / cross-field consistency rules * - BR-S-xx — Tax category rules * - PEPPOL-xx — Peppol BIS 3.0 specific rules * - GETPEPPR-xx — SDK-local diagnostics with no exact network-rule equivalent * * Design: each rule is a pure function (InvoiceInput) => SchematronViolation[]. * No side effects, no XML, no network. */ import type { InvoiceInput } from "../types/invoice.js"; export interface SchematronViolation { /** Network-rule or product-local diagnostic identifier. */ ruleId: string; /** Severity: "error" blocks sending, "warning" is advisory */ severity: "error" | "warning"; /** Human-readable description of the violation */ message: string; /** Relevant field path (e.g., "lines[0].vatRate") */ field?: string; } export interface SchematronResult { /** * ⚠️ « Aucun problème parmi les contrôles effectués » — PAS « conforme Peppol ». * Le nombre exact de contrôles enregistrés vit dans `SDK_SCHEMATRON_RULE_IDS`. * Le diagnostic de capacité historique `unsupported_vat_category` peut * apparaître en plus, hors de ce compteur. * Le verdict qui engage est rendu à l'envoi. */ valid: boolean; /** Ce qui a réellement été vérifié — pour que l'appelant sache ce que `valid` couvre. */ coverage: { rulesChecked: number; ofNetworkFatalRules: "partial"; }; /** Blocking violations — invoice would be rejected */ errors: SchematronViolation[]; /** Advisory notices — invoice may be accepted but is suboptimal */ warnings: SchematronViolation[]; } /** * The ten VAT category codes EN 16931 allows, verbatim from `BR-CL-17`'s test: * `' AE L M E S Z G O K B '`. * * ⚠️ This set used to hold NINE — `B` (Italian split payment) was missing, so * the validator reported "invalid" for a code the network accepts. Being * stricter than the network is the worse of the two errors (GPR-904): a false * refusal closes a corridor, a malformed document costs one document. */ export declare const VALID_VAT_CATEGORIES: ReadonlySet; /** * The categories the gateway can actually put on the wire. * * `L` (IGIC) and `M` (IPSI) were translated to `canary_islands` / * `ceuta_melilla` — values absent from every Storecove artefact — and `B` has no * provider equivalent at all (GPR-1012). They are valid EN 16931 codes that we * cannot route, which is a different finding from "not a category", and saying * so is the whole point: the previous message conflated the two. * * Drift-locked against the gateway's own table by * `console/src/lib/api/__tests__/vat-category-sdk-alignment.test.ts`. */ export declare const SENDABLE_VAT_CATEGORIES: readonly ["S", "Z", "E", "AE", "K", "G", "O"]; /** * The VAT-only preflight used by `Peppol.toXml()`. * It intentionally excludes provider-routability checks: local UBL generation * may validly use categories such as L/M that the getpeppr gateway cannot send. */ export declare function validateUblBuilderVat(input: InvoiceInput): SchematronViolation[]; /** * Validate an InvoiceInput with offline Peppol pre-flight checks. * * Runs the controls listed in `SDK_SCHEMATRON_RULE_IDS` as pure TypeScript * checks. Official IDs identify exact network-rule equivalents; `GETPEPPR-*` * IDs identify local diagnostics. No XML generation, no network calls. The * count is read from the registry, never written here; * `result.coverage.rulesChecked` reports it at runtime. * * ⚠️ A pass means "nothing wrong among the checks performed", NOT "Peppol * conformant" — the verdict that commits is the one returned at send time. * * @param input - The invoice to validate * @returns Validation result with errors (blocking) and warnings (advisory) * * @example * ```ts * const result = validateSchematron({ * number: "INV-001", * to: { name: "Acme", peppolId: "0208:0685660237", country: "BE" }, * lines: [{ description: "Widget", quantity: 1, unitPrice: 100, vatRate: 21 }], * }); * * if (!result.valid) { * console.error("Validation failed:", result.errors); * } * ``` */ export declare function validateSchematron(input: InvoiceInput): SchematronResult; /** * GPR-1069/GPR-1084 — les contrôles enregistrés que ce validateur exécute. * * ⚠️ 40 contrôles enregistrés, dont 10 diagnostics explicitement locaux, * face aux 333+ règles que le réseau applique. Le diagnostic historique de * capacité `unsupported_vat_category` peut être émis en plus par * `validateSchematron`, sans être compté dans `coverage.rulesChecked`. * `SDK-INPUT` appartient au pré-contrôle distinct du builder UBL et n'entre * pas dans un `SchematronResult`. * Ce module est un PRÉ-CONTRÔLE local : * il attrape les erreurs les plus fréquentes sans appel réseau. Le verdict qui * engage est celui rendu à l'envoi. * * ⛔ Ces identifiants sont ceux que CE FICHIER émet (`violation("BR-xx", ...)`). * Les 23 règles de catégorie de TVA ont été confrontées au rulebook gravé : * quatre ont d'abord été corrigées par GPR-1069, puis GPR-1068 a ajouté les * familles ligne/adjustment/motif manquantes. GPR-1084 a ensuite confronté ses * sept contrôles ciblés et quatre collisions adjacentes trouvées par la même * preuve : seul `BR-08` était une correspondance exacte, vers `BR-16`; les dix * autres portent désormais un ID `GETPEPPR-*` qui annonce leur portée locale. * * ⭐ Un identifiant faux ne se voit pas à l'existence : les quatre corrigés * existaient tous dans le rulebook. Seule la comparaison des COMPORTEMENTS les * a trouvés — `ubl-validation/__tests__/sdk-non-contradiction.test.ts`, côté * console, qui fait tourner ce module et le moteur officiel sur le même * document et rougit si leurs verdicts s'opposent. */ export declare const SDK_SCHEMATRON_RULE_IDS: readonly ["BR-02", "GETPEPPR-ISSUE-DATE-DEFAULTED", "GETPEPPR-FROM-VAT-RECOMMENDED", "BR-07", "BR-16", "GETPEPPR-PAYMENT-TIMING-RECOMMENDED", "GETPEPPR-BUYER-OR-ORDER-REFERENCE-RECOMMENDED", "BR-CL-17", "GETPEPPR-LINE-NET-SANITY", "GETPEPPR-COMPUTED-VAT-SANITY", "GETPEPPR-TAX-INCLUSIVE-SANITY", "GETPEPPR-PAYABLE-SANITY", "BR-S-05", "BR-Z-05", "BR-E-05", "BR-AE-05", "BR-G-05", "BR-IC-05", "BR-S-06", "BR-S-07", "BR-Z-06", "BR-Z-07", "BR-E-06", "BR-E-07", "BR-AE-06", "BR-AE-07", "BR-G-06", "BR-G-07", "BR-IC-06", "BR-IC-07", "BR-E-10", "BR-AE-10", "BR-G-10", "BR-O-10", "BR-IC-10", "GETPEPPR-BUYER-PEPPOL-ID-REQUIRED", "PEPPOL-EN16931-P0100", "PEPPOL-EN16931-P0101", "PEPPOL-EN16931-P0112", "GETPEPPR-UNIT-CODE-RECOGNISED"]; //# sourceMappingURL=schematron.d.ts.map