Notes de version
Toutes les évolutions visibles par les utilisateurs de NomaUBL — IHM, API REST, CLI, comportement — sont consignées ici. La version la plus récente apparaît en haut. Cette page reflète la carte À propos de cette version et l'écran Notes de version intégrés à l'application.
2026.05.15 — 2026-05-14
Deux améliorations qui permettent aux opérateurs de câbler des systèmes aval sans code dédié : actions facture personnalisées (boutons toujours visibles dans la modale de détail qui déclenchent une chaîne configurable d'appels connecteur) et synchronisation depuis connecteur pour les listes personnalisées (récupération des entrées d'une liste depuis un endpoint api-connector ou une requête sql-connector, avec paramètres enregistrés pour qu'une même requête alimente plusieurs listes). Plus la syntaxe unifiée {field} / {{field}} qui permet d'utiliser le même picker de variables dans les paramètres d'action.
Actions facture personnalisées
- Nouveau type
CustomInvoiceActiondansservices/invoiceHelpersplusparseCustomActions/customActionsToPropsqui enregistrent et sérialisentcustomAction.N.id,.labelet le même bloc.call.M.*sur le modèle e-invoicing (les surcharges par kco viae-invoicing-{kco}continuent de fonctionner). - La page Actions a une section Actions personnalisées sous la liste des actions vendeur prédéfinies. Chaque ligne porte un
idlibre + unlabel(texte du bouton) + le même éditeur de call-card — connecteur, endpoint / requête, paramètres,stopOnFailureoptionnel. InvoiceDetailModalrend les actions personnalisées dans leur propre groupe (leActionsSectionActions personnalisées) sous les actions vendeur prédéfinies, avec la logique de chaîne existante (variables résolues, chaînage de réponses via{call.N.fieldName}). Le bandeau de résultat est rattaché au groupe dont le bouton a déclenché la chaîne via un champactionResult.source; le résultat est aussi effacé quand la modale se ferme ou passe à une autre facture afin que les bandeaux périmés ne restent pas.InvoiceListetIntegrationListchargent les actions personnalisées en plus des actions réglementaires et les transmettent à la modale.
Syntaxe unifiée des variables dans les paramètres d'action
resolveActionParamsaccepte maintenant{field}(syntaxe insérée par le picker de notifications) et l'ancienne{{field}}. Les jetons inconnus passent inchangés afin qu'une faute de frappe soit visible à l'exécution.- Chaque paramètre d'appel sur la page Actions (paramètres par endpoint ET le fallback paramètres bruts) reçoit un bouton picker
{ }alimenté par le même hookusePlaceholderOptionsque l'éditeur de notifications.
Synchronisation depuis connecteur pour les listes personnalisées
CustomListEditorreçoit un groupe Sync source (optionnel) sous le tableau des lignes. Choisir un api-connector ou un sql-connector, puis un endpoint / une requête, puis mapper les champs de la réponse :Code field— nom de colonne (SQL) ou clé JSON (API) qui sert de code à chaque ligne.Label FR field/Label EN field— libellés FR (requis) et EN (optionnel).List path(API seulement) — chemin pointé vers le tableau dans le corps JSON, supportedata.itemsetitems[0]; vide quand le corps est déjà un tableau.Parameters— valeurs fixes (pas de substitution de variables) envoyées au connecteur. La même requête peut alimenter plusieurs listes en enregistrant des valeurs différentes par liste ; les valeurs par défaut de la définition d'endpoint s'appliquent quand un champ est laissé vide.
- Le bouton
Sync nowappelle le connecteur, parcourt la réponse, construit l'ensemble de lignes et remplace les lignes de l'éditeur avec un message succès/erreur traduit (N ligne(s) synchronisée(s) depuis connector · endpointou l'erreur sous-jacente). - La configuration sync vit dans le même modèle de liste sous
sync.connector / sync.endpoint / sync.codeField / sync.labelFrField / sync.labelEnField / sync.listPath / sync.params.parseRefOptionsfiltre ces clés afin que les consommateurs de liste (renderer de cellule refList, dropdown Filtres avancés) ne les voient jamais comme des entrées. Voir la page Listes personnalisées.
Backend — liaison de paramètres SQL plus tolérante
SqlConnectorClient.executeQueryretire maintenant une paire de guillemets simples ou doubles entourant chaque paramètre chaîne avant lesetStringJDBC. Les opérateurs qui tapent'01'dans une valeur par défaut de requête ou dans le panneau de test — la façon d'écrire un littéral SQL — obtenaient silencieusement 0 ligne car JDBC liait la chaîne de 4 caractères telle quelle. Le strip permet aux deux conventions de fonctionner. Note : comparer à une colonne JDECHAR(n)demande toujoursWHERE TRIM(col) = :pdans la requête — c'est la règle Oracle de comparaison non-blank-padded quand un côté est lié enVARCHAR2, pas un choix du framework. Voir la page Connecteurs SQL.
Correction de race sur le dropdown endpoint dans l'éditeur de liste personnalisée
- Le chargeur d'endpoints attend maintenant que le catalogue
connectorssoit arrivé avant de tirer, et abandonne quand le connecteur choisi n'y est pas encore. Le code précédent basculait le kind par défaut surapiquandconnectorsétait vide, tirait le mauvais endpoint de liste, mettait en cache le résultat vide et court-circuitait les ré-exécutions suivantes — le dropdown restait vide au rechargement de l'éditeur. Corrigé : l'endpoint enregistré se résout correctement au rechargement.
2026.05.14 — 2026-05-14
Les règles de notification peuvent maintenant utiliser n'importe quelle colonne de la facture comme variable, plus seulement les 10 champs canoniques d'origine. Sujet, corps et valeurs de paramètres d'appel d'action ont tous un nouveau bouton { } qui ouvre un picker recherchable — choisir une variable et elle s'insère dans le champ au curseur. Le jeu de variables fusionne les champs canoniques de notification (doc / dct / kco / status / statusLabel / message / reason / reasonLabel / action / actionLabel) avec toutes les colonnes du catalogue de la spec Factures ({customerName}, {contractRef}, {totalHT}, {currency}, {logBusinessUnit}, {logPaUuid}, …) — un appel d'action pour mettre à jour un client ou pousser vers un système aval n'a plus besoin de câblage sur mesure.
Backend — contexte facture complet dans les variables
NotificationDispatcher.readInvoiceContextprojette maintenant toutes les colonnes deColumnCatalogs.invoices()via un seul SELECTF564231 LEFT JOIN F564230et stocke la projection en chaîne consciente du type (montants à 2 décimales, date / datetime ISO depuis JDE Julian, parsingasInt, trim CHAR) dans une nouvelle mapctx.extrasclée par nom de colonne de spec.buildPlaceholdersfusionnectx.extrasd'abord, puis superpose les 10 variables canoniques par-dessus — donc les{doc}/{status}/ etc. existants gardent leur sens familier si une colonne du catalogue partage le même nom.- Un seul aller-retour SQL par envoi (au lieu du SELECT précédent sur 5 colonnes) — même forme, juste plus large.
Frontend — popover PlaceholderPicker
- Nouveau
common/PlaceholderPicker.tsx— popover thémé avec un déclencheur stylé en bouton{ }. Cliquer ouvre une liste recherchable (nom de variable enmono+ libellé orienté opérateur) ; choisir une variable et le snippet{nom}s'insère dans l'input lié au curseur (ou s'ajoute à la fin avec un espace de tête quand l'input n'est pas focalisé). Escape / clic à l'extérieur ferme. - Le hook
usePlaceholderOptionscharge la liste fusionnée une fois par page (10 canoniques + colonnes de/api/list-views/invoices/catalog) et la met en cache en scope module pour que chaque picker partage le même fetch. - L'éditeur de règle câble trois pickers : à côté de l'input Sujet, à côté du textarea Corps et par ligne valeur de paramètre dans chaque appel d'action. L'indice de variable en ligne verbeux est remplacé par un pointeur court vers le bouton
{ }+ quelques exemples représentatifs.
2026.05.13 — 2026-05-14
Filtres refList multi-sélection partout. La ligne de filtre par colonne TanStack et le panneau Filtres avancés permettent maintenant aux opérateurs de choisir un nombre quelconque de codes pour une colonne refList (statuts, statuts e-reporting, listes personnalisées, …), avec un raccourci d'effacement en un clic sur le déclencheur — pas besoin de désélectionner chaque entrée. Le filtrage serveur IN (?,?,?) est activé sur les colonnes catalogue concernées — choisir trois statuts dans Filtres avancés → Exécuter renvoie l'union.
SearchSelectMulti — picker multi-sélection thémé
- Nouveau composant frère dans
common/SearchSelect.tsx. Même apparence et même recherche queSearchSelect, mais chaque ligne bascule dans unevalue: string[], une coche est affichée à côté de chaque entrée active et le déclencheur affiche les codes joints par virgule quand c'est court ouN sélectionné(s)quand la liste déborde. - Un petit bouton ✕ à droite du déclencheur apparaît quand au moins une option est sélectionnée — cliquer dessus réinitialise le tableau en un seul clic sans ouvrir le popover (
stopPropagationpour que le déclencheur ne bascule pas). La ligne de pied Effacer reste comme chemin secondaire.
Ligne de filtre par colonne (TanStack)
- Une colonne de spec avec un
refListrend maintenant le picker multi-sélection dans la ligne de filtre par colonne de DataTableV2. Le renderer de cellule conserve son affichagecode — libellé, donc le picker et la cellule restent alignés. - La fonction de filtre accepte soit une chaîne unique (legacy) soit un
string[](multi) : pour un tableau, la ligne correspond quand sa valeur (trimée, en minuscules) apparaît dans l'ensemble choisi. Un tableau vide retire automatiquement le filtre. - Le flag
FilterMeta.filter.multisur les colonnes de kind enum pilote la sélection du picker ; les colonnes booléennes et les énumérés non-refList restent en mono-sélection.
Panneau Filtres avancés
- Les lignes refList dans
ServerFilterPanelutilisent aussi le picker multi-sélection. La sélection est encodée en chaîne jointe par virgule dansOpFilter.a(par ex.200,210,9907) — le contrat existant deflattenServerFiltersla transmet telle quelle au backend. - Cliquer sur ✕ sur le déclencheur pour réinitialiser ; sinon les choix s'accumulent jusqu'à Exécuter.
Backend — IN (?,?,?) pour les colonnes refList
SpecQueryHelper.appendSpecFilterClausesséparait déjà les valeurs jointes par virgule en clauseINquand la colonne catalogue déclaraitfilterInList; cette version active ce flag sur les deux colonnes catalogue refList restantes :invoiceStatussur la vue Erreurs d'intégrationstatussur la vue E-Reporting
statusCodedes Factures l'avait déjà depuis le travail de deep-link.
Élargissement de colonne pour l'opérateur between
- Choisir
betweensur un filtre par colonne date / nombre / texte élargit maintenant la colonne pour faire entrer les deux champs opérandes (plancherBETWEEN_COL_WIDTH = 340pxdans DataTableV2). L'élargissement est calculé depuis l'étatcolumnFilterset appliqué de façon cohérente au<col>, au min-width de Th et de Td afin quetable-layout: fixedl'honore. Repasser à un opérateur à opérande unique et la colonne reprend sa largeur de spec au rendu suivant.
2026.05.12 — 2026-05-14
Mode hybride client pour les vues de liste pilotées par spécification et un dropdown recherchable refList dans la ligne de filtre par colonne. Chaque Exécuter charge maintenant une seule tranche capée depuis le serveur ; TanStack pilote filter / sort / group / paginate sur cette tranche dans le navigateur — pas d'aller-retour quand on tape dans la ligne de filtre, pas de latence en changement de page, les filtres survivent à la pagination. Identique au modèle Liberty v2 tout en restant sûr sur des tables énormes grâce à un cap maxRows par vue (5000 par défaut).
Flux de données hybride client-side
- Chacune des quatre vues pilotées par spec (Factures, Erreurs d'intégration, Journal de traitement, E-Reporting) émet maintenant une seule requête serveur par Exécuter, dimensionnée à
spec.maxRows ?? 5000lignes. DataTableV2ne reçoit plustotal / page / pageSize / onPageChange / onPageSizeChangesur ces pages — TanStack pagine la tranche chargée en interne avecinitialPageSize = spec.defaultPageSize ?? 50.- La plage de dates / les puces de barre d'outils / Filtres avancés → Exécuter déclenchent toujours un nouveau fetch. Un changement de tri ré-émet aussi le fetch pour que la tranche reflète toujours les
maxRowslignes les plus pertinentes quand le cap est atteint. - Quand le cap est atteint, la barre d'outils affiche un message traduit
X / Y lignesà côté de Exécuter avec une infobulle qui indique d'affiner les Filtres avancés / la plage de dates.
Champ maxRows dans la spec + éditeur
- Nouveau champ optionnel
maxRowssurListViewSpec(5000 par défaut, pas de surcharge par page nécessaire). Le parser le préserve. - Vues de liste → ligne Défauts a un champ Max rows à côté de Taille de page, avec une infobulle qui explique chacun. La propriété persiste par vue via le chemin de surcharge standard
db-nomaubl.view.<nom>.
Dropdown refList dans la ligne de filtre par colonne
- Une colonne de spec avec un
refListrend maintenant un dropdown recherchable de type énuméré dans la ligne de filtre par colonne de DataTableV2 — peuplé depuis la liste de référence chargée avec des entréescode — libellé— au lieu de retomber sur un champ texte. Le renderer de cellule conserve son affichagecode — libellé, donc le picker et la cellule restent alignés. - Une
FilterFnd'égalité tolérante (coerce en chaîne, trim, insensible à la casse) remplace leequalsstrict de TanStack — les codes numériques (par ex. un code statut stocké en nombre) correspondent à la valeur de l'option du picker, et le padding CHAR d'Oracle ne casse pas l'égalité. - Le filtre par colonne reste client-side (filtre uniquement la tranche chargée) — la même nuance que l'opérateur connaît déjà avec le modèle hybride.
Internes de DataTableV2
- L'état de tri est maintenant contrôlable indépendamment du mode de pagination serveur : une page client-side peut toujours fournir les props
sorting + onSortingChangeet TanStack les honore tout en paginant localement. Sans cela, les quatre pages converties perdraient leur tri par défaut au premier rendu.
2026.05.11 — 2026-05-13
Version « cohérence UI ». Toutes les listes déroulantes du front React passent maintenant par le même composant recherchable (SearchSelect) — les filtres, les éditeurs de paramètres, les modaux et les éditeurs XSL / UBL partagent la même apparence, la même navigation clavier et un champ de recherche intégré pour les longues listes (pays, modes de paiement, devises, catégories TVA, statuts, scheme IDs…). Les listes déroulantes des listes de référence sont aussi conscientes du type : le format à 6 champs du modèle statuses (tag|labelFr|labelEn|paCode|collect|groups) est correctement parsé — ce sont les libellés (pas le tag) qui s'affichent dans le picker.
SearchSelect — composant global de liste déroulante
- Nouveau
src/common/SearchSelect.tsxporté et adapté du design Liberty v2 : popover en portail, filtrage à la frappe, colonnemonooptionnelle pour les codes, ligne d'en-tête viaanyLabel, mode comboboxallowCustom, taillessize: 'sm' | 'md', fermeture sur clic extérieur /Échap. - Sites migrés (non exhaustif) : chaque ligne de filtre dans
ServerFilterPanelet le filtre par colonne de DataTableV2, chaque cellule de l'éditeur Vues de liste, la barre d'outils Journal de traitement, les barres d'outils Factures et Erreurs d'intégration, toutes les listes déroulantes du modal Facture (picker fournisseur, pickers pays, modes de paiement, exonération TVA, types de notes, références doc, type d'allowance, codes d'unité, catégories fiscales), les éditeurs des paramètres (Connecteur API, Connecteur SQL, Types de documents, scope E-Invoicing, modèle Document, Fetch Invoices, Block Canvas), la page Fetch Input, Process Document, le modal Set Status, la page Actions, la page Règles de notification, le picker de modèle AI Chat, les onglets UBL Defaults (devise, paiement, type de document, TVA, en-tête, fournisseur, préfixe de note, scheme IDs, profile ID, unités, type de facture, éditeur de règles, éditeur de mappings — ~27 dropdowns), le picker de fichier de l'éditeur XSL, les éditeurs préfixe note et doc-ref, les formulaires Extract BIP / Extract FTP / Extract & Process, la section connecteur de Process API. - Les composants legacy
Select(danscommon/Input.tsx),FieldSelect/MethodSelect(dansSettings/settingsStyled.ts),FileSelect(dansXslEditor/xslEditorStyled.ts) et l'ancienMappingSelect<select>stylé (dansUblDefaults/ublDefaultsStyled.ts) sont retirés —MappingSelectest maintenant un fin wrapper autour deSearchSelectqui conserve l'API legacy avec enfants<option>, donc tous les onglets UBL Defaults récupèrent la nouvelle apparence automatiquement. - Le picker de taille de page dans le
DataTablelegacy et dansDataTableV2utiliseSearchSelectpour la cohérence.
Correction des libellés des listes de référence
parseRefOptionsest maintenant consciente du type : pour les modèlesstatusesetereporting-statuses, elle parse le format à 6 champscode → "tag|labelFr|labelEn|paCode|collect|groups"et affiche les libellés FR / EN (pas le tag) dans les dropdowns. Les autres listes de référence gardent le format standard à 2 champslabelFr|labelEn. Voir la page Statuts.loadRefListstransmettemplate.typeau parser pour que le bon format soit choisi par liste.
2026.05.10 — 2026-05-13
Version « vues de liste pilotées par spécification ». Toutes les pages de liste — Erreurs d'intégration, Journal de traitement, E-Reporting, Factures — passent par DataTableV2 dont la forme des colonnes (libellés, formats, alignement, largeur, filtres côté serveur) est pilotée par une spécification JSON stockée sur db-nomaubl (avec un défaut embarqué dans le JAR). La mise en page V1 historique a été retirée de ces quatre pages — V2 est le seul mode. Un nouveau catalogue de colonnes par vue indique toutes les colonnes que les tables sous-jacentes peuvent projeter ou filtrer, et le nouvel éditeur Vues de liste permet aux opérateurs d'Ajouter une colonne sans écrire de code tant qu'elle vit dans le catalogue. La vue Factures fait maintenant une jointure gauche avec F564230 — 16 colonnes de journal/archive (fichier source, BU, utilisateur/job JDE, échéance, UUID PA…) sont disponibles depuis le picker. Plus la correction du drill-through Erreurs récentes du tableau de bord (les filtres n'étaient pas transmis) et d'un bug d'aller-retour CustomizationID dans la fenêtre Facture.
Vues de liste pilotées par spécification (Phase A + Phase B)
- Nouveau schéma
ListViewSpecstocké sousdb-nomaubl.view.<nom>(par ex.view.invoices), avec un défaut embarqué dansconfig/list-views/view.<nom>.jsonpour chacune des quatre pages migrées. Pilote la visibilité des colonnes, les libellés FR/EN, le type, le format (date/datetime/amount/percent), l'alignement, la largeur et la liste blanchefilter: true. - Nouveau point d'entrée
GET /api/list-views/<nom>qui résout la spécification (propriété stockée prioritaire, défaut embarqué sinon). L'éditeur lit et écrit via le même chemin. - Catalogue de colonnes intégré par vue (
ColumnCatalog+ColumnCatalogs) — indique toutes les colonnes que le handler Java peutSELECT: expression SQL, type (STRING/NUMBER/DATE/JDE_DATE/JDE_DATETIME), comportement de filtre (exact/LIKE/inList/between), flags de projection (cents → /100,asInt → parseInt,trimForFilter). Disponible viaGET /api/list-views/<nom>/catalog. - Câblage Phase B : les handlers Java de
/api/invoices,/api/integration-errors,/api/processing-loget/api/ereportingconstruisent maintenant la projectionSELECTet les clausesWHEREdepuis la spec + le catalogue. Le helper partagéSpecQueryHelperrésout les opérateurs de filtre en un seul endroit. Ajouter une colonne via l'éditeur la fait apparaître dans la grille (et dans le panneau Filtres avancés sifilter: true) sans modification de code. - Nouvel éditeur Vues de liste avec une carte pliable par vue, réorganisation drag-and-drop des colonnes via une poignée
GripVertical, champs de libellé FR/EN, inputs type/format/alignement/largeur, toggleVisible / Filtreet picker+ Ajouter une colonnealimenté depuis le catalogue. Le badgeoverride/defaultpar carte indique si l'opérateur a touché à la spec ou non. Voir la nouvelle page Vues de liste dans la Configuration.
Factures — F564231 LEFT JOIN F564230
- La requête SQL pilotée par spec des factures joint maintenant
F564231(UH) etF564230(FE) sur doc / dct / kco, donc 16 colonnes journal/archive sont accessibles depuis le picker+ Ajouter une colonnede l'éditeur :logSourceFile,logActivityCode,logSubType,logAlphaKey,logAmount,logInvoiceDate,logDueDate,logCreated(UPMJ+UPMT),logUser,logJobn,logPid,logVersion,logBusinessUnit,logRouting,logSendToPaFlag,logPaUuid. La jointure gauche préserve les lignes factures sans entrée de journal.
Panneau de filtres avancés
- Nouveau composant
ServerFilterPanel: panneau pliable Filtres avancés indexé par nom de colonne, avec un sélecteur d'opérateur par colonne (contains,equals,≠,<,≤,>,≥,between,empty,not empty). Le panneau émet un état brouillon ; un bouton Exécuter explicite le valide enappliedFilters— taper dans le panneau ne sature pas le back-end. - Vocabulaire des opérateurs traduit de bout en bout : les libellés de colonne prennent la variante française (
labelFr) quand la locale active commence parfr, avec retour àlabelsinon.
Polish DataTableV2
- Les tables utilisent maintenant
width: 100% + table-layout: fixedet reçoivent les largeurs par colonne via un<colgroup>— les colonnes sans largeur explicite se partagent l'espace restant. Une seule barre de défilement dans le corps du tableau (plus de double-scroll page + table). - La zone de page passe
PageLayout fillpour les pages V2, donc le corps du tableau remplit l'espace vertical restant ; l'en-tête sticky fonctionne correctement à l'intérieur du scroller.
Correction du drill-through tableau de bord
- La carte Erreurs récentes du Tech Dashboard transmet maintenant
{ doc, dct, kco }quand on ouvre une ligne sur Erreurs d'intégration ; la page cible amorce son bag de filtres depuis ces props. Une pastille visible montre le drill actif et propose un×pour le retirer (avant, le filtre était invisible avec la barre slim et le panneau replié). - Les cartes de statut du Business Dashboard (
Déposée,Validation réussie, multi-statut « En vol »…) filtrent maintenant les factures viafilters.statusCodede bout en bout ; le flaginList()du catalogue éclate les buckets séparés par virgule en clauseIN (?,?,?,?,?). - Le drill-through depuis les barres de débit du Tech Dashboard vers le Journal de traitement amorce maintenant le
DateRangeFilterV2 viainitialRangepour que la période cliquée s'applique.
Fenêtre Facture — aller-retour CustomizationID
- Modifier une facture existante ne réinitialise plus son
cbc:CustomizationIDau défaut EN16931. Le formulaire porte maintenantcustomizationId(défauturn:cen.eu:en16931:2017pour les nouvelles factures) ;parseUblXmllit la valeur du UBL source,buildUblXmll'écrit verbatim.
Petits nettoyages
- Débordement des pastilles de statut — sur la page Factures, 5 pastilles inline maximum, le reste se replie dans un menu
+N moreavec un point coloré par code. Les drill-throughs multi-statuts (par ex. En vol = 5 codes) remontent la valeur active dans le groupe inline quand applicable. - UX éditeur Vues de liste — réorganisation drag-and-drop via une poignée
GripVerticalunique (plus de doubles flèches), bouton de suppression par ligne, colonnes de libellé FR/EN dédiées, champ largeur, badge bundled vs override par carte. - Catalogue Vues de liste — le picker
+ Ajouter une colonneliste toutes les entrées du catalogue absentes de la spec courante (nom / libellé anglais / type). L'ajout amorce une nouvelle colonne de spec avec les libellés du catalogue ; l'opérateur peut les ajuster ensuite. - Onglet par défaut du Journal de traitement — restauré à Groupé (mode de lecture quotidien) ; le choix Groupé / Plat de l'opérateur reste persisté en localStorage comme avant.
- Alignement du badge de statut —
statusCodedes factures utilise maintenanttype: "string"donc la pastille est alignée à gauche dans sa cellule (était à droite à cause du typenumberprécédent). - SQL Phase B par l'exemple — la vue Factures exécute une requête jointe de la forme
SELECT <colonnes spec> FROM F564231 UH LEFT JOIN F564230 FE ON FE.FEDOC=UH.UHDOC AND FE.FEDCT=UH.UHDCT AND FE.FEKCO=UH.UHKCO WHERE … ORDER BY <defaultSort spec> OFFSET ? ROWS FETCH NEXT ? ROWS ONLY— ajouter une colonne à la spec via le catalogue la fait remonter dans la grille sans modification de code.
2026.05.9 — 2026-05-12
Version pipeline de validation + webhooks entrants. La pile Schematron s'appuie désormais sur des XSLT précompilés chargés depuis le JAR — le pipeline ISO de compilation au démarrage a disparu, et les règles locales sont précompilées au build. Flux 2 s'exécute sur tous les profils (l'étape 3 de la séquence AFNOR XP Z12-012 était sautée silencieusement sur les factures Extended-CTC-FR). Un nouveau pack de règles maison NomaUBL capture les contrôles côté AIFE absents des packs Schematron publics (première règle : les codes d'avoir 261/381/396/502/503 demandent une référence à une facture antérieure). Côté exploitation, les webhooks entrants deviennent une fonctionnalité de premier plan : des POST signés HMAC vers /api/webhook/{connector}/{event} retrouvent la facture par son UUID PA, appliquent le statut cycle de vie et dédupliquent les ré-essais « at-least-once » — assez générique pour brancher n'importe quelle PA via le modèle api-connecteur. La liste Erreurs d'intégration abandonne sa colonne Message illisible au profit d'une fenêtre de détail dédiée qui sépare le contexte de debug Schematron de l'explication française.
Webhooks entrants (framework générique)
- Nouvelle route
/api/webhook/{connector}/{event}— publique (passe outre l'auth de session), vérifie la requête via HMAC-SHA256 sur un canonicaltimestamp\nMÉTHODE\nchemin\nchecksumBody, déduplique sur l'event id du payload (cache mémoire LRU+TTL, 10 000 entrées × 1 h), puis dispatche vers un handler par événement. Les événements de type statut appliquent laInvoiceStatusCatalog.StatusTransitionrésolue contre la ligneF564230correspondante (recherchée parFEUKIDSZ). - La configuration vit sur le modèle api-connecteur (nouvel onglet Webhooks dans
ApiConnectorEditor) : secret partagé (chiffré au repos via le suffixe*Secret), surcharges de chemins JSON pouridField/statusField/eventIdField, et table de correspondancepaStatus:logical(success/pending/failed) réutilisée depuisImportStatusHandler. L'onglet affiche l'URL en lecture seule à coller dans les réglages webhook de la PA. - Renvoie 2xx sur erreur interne pour stopper les ré-essais ; 401 sur signature invalide (bruyant) et 404 sur connecteur inconnu. Un redémarrage JVM purge le cache de dédup sans risque — rejouer le même événement une seconde fois n'a aucun effet observable.
Pipeline Schematron — précompilation uniquement
- Le runtime ne compile plus les fichiers
.sch.UBLValidatorcharge directement les.xslprécompilés depuis le classpath et échoue immédiatement au démarrage si un fichier attendu manque. Les trois packs AFNOR sont livrés tels que publiés ; les deux règles locales (BR-FR-CPRO-Schematron-UBL+BR-NOMAUBL-rules) sont précompilées au build parbuild.shvia le CLI Saxon +xmlresolver— le même pipeline s'applique partout. - Les XSL squelette ISO (
iso_dsdl_include.xsl,iso_abstract_expand.xsl,iso_svrl_for_xslt2.xsl) et le helpercompileSchematronne tournent plus en runtime. Le démarrage à froid gagne un battement perceptible — trois compilations XSLT × cinq packs ne se rejouent plus à chaque JVM. - Le pied de page du tableau de bord continue d'afficher les versions par pack :
BuildInfolit toujours la source.schpour la version (priorité au patternyyyymmdd_VX.Y.Z, sinon repli sur le commentaire d'en-tête), donc rien ne casse même si la charge runtime est désormais en.xsl. Voir la page UBL Validate.
Correctif profil de validation — Flux 2 systématique
- AFNOR XP Z12-012 V1.3.1 découpe la validation en 4 étapes : l'étape 2 choisit EN 16931 ou Extended-CTC-FR (selon
CustomizationID), l'étape 3 exécute BR-FR-Flux 2 inconditionnellement par-dessus. Le code précédent considérait Extended-CTC-FR comme un sur-ensemble et sautait Flux 2 — manquant les règlesBR-FR-*/EXT-FR-FE-*spécifiques à la réforme que la PA continue d'imposer côté serveur. Le profil Extended exécute désormais les deux étapes.
Règles maison NomaUBL
- Nouveau
BR-NOMAUBL-rules.schpour les règles côté AIFE absentes des packs Schematron publics. Première règle (BR-NOMAUBL-01, fatale) : si BT-3 ∈{261, 381, 396, 502, 503}, au moins unecac:BillingReference/cac:InvoiceDocumentReferencequi portecbc:ID(BT-25) etcbc:IssueDate(BT-26) doit être présente. Les PA rejettent aujourd'hui ces avoirs avec l'erreur de validation modèleprecedingInvoices; faire remonter l'échec localement pour qu'il arrive dansF564236au lieu d'après un aller-retour. - Câblé via
BuildInfo(versionschematron.nomaubldans/api/build-info) et exécuté en dernière couche après CPRO-B2G.
Rendu des messages de validation
- Les règles
BR-FREXT-*du CTC-FR émettent une chaîne unique mélangeant un contexte de debug séparé par virgules (Num Fact : …, Code : S, rate : 20, …) et une explication française préfixée par un autre marqueur[RULE-ID] -. TantInvoiceDetailModal(bouton Validate + erreursF564236enregistrées) que la nouvelleErrorDetailModaldécoupent le bloc sur le dernier marqueur, [RULE-ID] -: l'explication française devient la ligne principale, les champs de debug se rendent dans une petite grille monospace en carte atténuée en dessous. Le pattern d'id de règle accepte les suffixes FNFE-MPEini/rev(correction de flag regex — les variantes warning ressortaient en texte brut). ConfigJson.jsonUnescapecouvre désormais l'ensemble RFC 8259 des séquences d'échappement, dont\uXXXX,\b,\f,\/. Les messages d'erreur PA contenant des caractères français accentués (é→é) et des sauts de ligne ne ressortent plus comme des séquences littérales dans le message de cycle de vie.PAImportStatusClient.parseJsonErrorsl'appelle sur chaque token d'erreur extrait.
Erreurs d'intégration — vue détail lisible
- Colonne Message retirée du tableau — les messages Schematron / XPath sont trop longs pour une cellule de grille. La colonne consommait ~720 px et continuait de tronquer le contexte. Un clic sur la ligne ouvre désormais la vue détail à la place.
- Les lignes appariées (avec une vraie facture dans
F564231) ouvrent toujoursInvoiceDetailModalsur l'onglet Historique. - Les lignes orphelines ouvrent désormais une nouvelle
ErrorDetailModal— badge de niveau, règle + description (viauseRuleCatalog), source, date, doc / dct / kco (avec une mention aucune facture correspondante dans F564231), client, et le message complet rendu via le même helpersplitValidationMessage. Toutes les lignes de la page sont désormais cliquables. - Nouvelle colonne Date : le même contexte temporel que la carte « erreurs récentes » du Tableau de bord IT est visible sans ouvrir une ligne.
Format de date d'entrée par modèle de document
UBLDatabaseHandler.insertDocumentLog/updateDocumentLogétait codé en dur pour parser les dates source enyyyy-MM-dd. Ça marchait pour les flux source UBL (le XSL émet de l'ISO) mais échouait silencieusement sur les documents source XML dont les dates sontdd/MM/yyyyetc. Nouvelle propriétédateInputFormatsur le modèle de document (réglée dans l'Éditeur de documents → onglet Document → section Format de date) qui pilote le parseur, avec ISO en défaut rétro-compatible.CustomUBLla lit depuis la ressource modèle et la transmet au handler de base.
TAG_INVOICE_TYPE_CODE — BT-3 séparé du DCT
TAG_DOCUMENT_TYPEétait commenté à tort comme BT-3 alors qu'il s'agit en réalité du code Type / DCT utilisé dans la concaténationcbc:ID. Nouvelle variable distincteTAG_INVOICE_TYPE_CODE(BT-3, UNTDID 1001 — 380, 381, 384, …) dansubl-template.xsl: quand elle est renseignée et que la source XML porte une valeur, cette valeur l'emporte sur les règles UBLDefault /$invoiceType_default. Émise en ligne viaubl:type-code-qnamepour que le code résolu atteigne réellement le fil au lieu d'être masqué par un second appel àubl:resolve-invoice-typedans le template historique.- Métadonnées de l'éditeur XSL corrigées (
TAG_DOCUMENT_TYPEne revendique plus BT-3) et la nouvelle variable apparaît dans la grille à deux colonnes de la section Header dès que le template la déclare.
api-connecteur — multipart, vérif statut
- Nouvelle propriété
endpoint.N.contentType+ builder de corps multipart pour que les endpoints api-connecteur puissent soumettre dumultipart/form-data(l'import facture IOPOLE attend une partfile=@{{filePath}};contentType=text/xml). UI : sélecteur Content-Type dans le panneau endpoint de la page Connecteurs API. - Arbre de décision relaxé dans
ImportStatusHandler— tout statut nonfailed/ nonpendingest traité comme un succès (couvre le vocabulaire IOPOLEEMITTED/RECEIVEDsans configuration spécifique).
Profilage de debug par étape
- Nouveau commutateur optionnel
debugProfilesur global qui écrit des lignes de chronométrage par étape dansF564237(en-tête, lignes, validation, émission UBL, envoi PA). Visualisé dans le Tableau de bord IT pour repérer l'étape lente d'un lot sans journalisation ad-hoc.
Petits nettoyages
- Le drapeau
UHALRTPSDde revue apparaît dans la liste E-Invoicing (colonne + badge coloré) pour repérer rapidement les lignes à revoir. - La vérification de l'annuaire tourne désormais au moment de la validation (pas seulement à l'envoi) afin qu'un contre-parti inconnu remonte dans
F564236avant même la mise en file du document. Le contrôle de joignabilité est sensible au mapping (recherche LIKE castée via le helper de dialecte pour que le paddingNCHARd'Oracle ne casse pas les correspondances partielles). - Améliorations de pré-transformation dans
isc-normalize.xsl: les templatesclientFacturation/clientConsommationlaissent passer les enfants horsadresse(les balises par ligne commeconsIdentitese résolvent) ; les valeursprixUnitairekWhà zéro sur les lignes d'avoir / remise sont remplacées par la valeurmontantHTdu frère, rendue sans signe (BT-146 doit être ≥ 0 en UBL). - Nouveau dossier
e2e/avec une suite Playwright qui exerce les pages majeures (Tableau de bord, Factures, Erreurs d'intégration, Paramètres → tous les éditeurs, Notifications). Pas encore branché à la CI — à lancer avecnpx playwright testà la demande.
2026.05.8 — 2026-05-09
Version de consolidation côté connecteurs. La configuration PA est désormais homogène entre e-invoicing, e-directory et e-reporting — chaque modèle système référence un api-connecteur réutilisable au lieu de porter ses propres champs d'authentification et endpoints, et la forme inline historique est supprimée (sans repli). L'infrastructure mock (MockPlatformApiClient, MockTokenManager, paUseMock/paMockBehavior) est retirée. Les requêtes de jeton OAuth2 acceptent maintenant un corps form-urlencoded (authTokenContentType / grant_type=client_credentials) ainsi que des en-têtes personnalisés sur la requête de jeton (authTokenHeaders), ce qui rend accessibles les PA qui exigent un en-tête tenant sur l'appel d'authentification lui-même. L'E-Reporting est entièrement désolidarisé de l'e-invoicing : il choisit son propre api-connecteur, son propre endpoint, son propre paMode, et peut soumettre les rapports en SFTP comme en REST. Les trois éditeurs de modèles système ont été réorganisés selon une mise en onglets cohérente.
Soumission PA — E-Reporting indépendant de l'e-invoicing
- Auparavant, la soumission e-reporting partageait le connecteur, le
paModeet les identifiants du modèle e-invoicing. Elle lit désormais ses propresconnector/endpoint.report-import/paModedepuis le modèlee-reporting(et les surcharges par sociétée-reporting-{kco}), ce qui permet de cibler une plateforme différente — ou des identifiants différents sur la même plateforme — pour les rapports. - Nouveau transport SFTP pour la soumission des rapports. Réutilise le
PlatformFtpClientexistant (la classe est agnostique à la ressource — il lui faut juste les propriétéspaFtp*sur la ressource passée en argument), donc aucune nouvelle classe de transport. Le branchement se fait dansEReportingHandler:paMode=APIpasse par l'api-connecteur,paMode=FTPécrit le XML dans un fichier temporaire et l'envoie en SFTP,paModevide ignore la soumission. - L'ancien drapeau
sendToPAY/N sure-reportingest remplacé parpaMode(API / FTP / vide). Mêmes sémantiques, un seul champ, cohérent avec e-invoicing. - La vérification de configuration signale désormais
paMode=APIsansconnectoretpaMode=FTPsanspaFtpHostcomme erreurs, en remplacement de l'ancien contrôlesendToPA=Y/issuerSiren.
Jeton OAuth2 — form-urlencoded + en-têtes personnalisés
ApiConnectorClient.fetchAndCacheOauth2Tokenlit désormaisauthTokenContentType(application/jsonpar défaut,application/x-www-form-urlencodedpour passer en mode formulaire) etauthTokenHeaders(pairesKey:Valueséparées par point-virgule envoyées uniquement sur la requête de jeton — pour les PA qui exigent un en-tête tenant-id sur l'appel d'auth lui-même).- Nouveaux corps par défaut quand le template est vide : le mode formulaire émet
grant_type=client_credentials&client_id={user}&client_secret={pass}(URL-encodé) ; le mode JSON conserve la charge JD Edwards AIS. UnauthTokenFieldvide essaie automatiquementaccess_tokenpuistoken, donc le flux OAuth2 client_credentials standard fonctionne sans configuration supplémentaire. - L'onglet Auth de la page Connecteurs API a gagné le sélecteur Body Content-Type et la zone de texte Token request headers.
Réorganisation des éditeurs de modèles système
- Les trois modèles système suivent désormais le même schéma à plusieurs onglets.
- E-Invoicing (4 onglets) : UBL Validation · PA Connection (connecteur + Timeout / SSL Verify) · FTP/SFTP (Send Mode + serveur SFTP, atténué quand Send Mode ≠ FTP) · Status (Status Retrieval ; les intervalles de polling renvoient l'utilisateur vers global → Scheduling).
- E-Directory (2 onglets) : Directory (Enable Check + INSEE Search) · Connector (api-connecteur + surcharges d'endpoint par tâche). Les anciens groupes inline API Connection + Credentials sont supprimés — ils étaient devenus du code mort depuis que
PaConnectorResolverest devenu strict. - E-Reporting (4 onglets, nouvelle forme) : Identity · Reporting · PA Connection · FTP/SFTP — calqué sur e-invoicing.
- Send Mode quitte l'onglet PA Connection d'e-invoicing pour rejoindre l'onglet FTP/SFTP où il appartient logiquement (par défaut
API; le sélecteur n'est utile que pour configurer FTP). - Le groupe Background Scheduling est retiré d'e-invoicing — il écrivait dans
fetchImportInterval/fetchStatusIntervalsur le modèle e-invoicing alors queBackgroundSchedulerne lit ces propriétés que depuisglobal. Le piège du « champ écrit mais jamais lu » disparaît ; l'utilisateur a une ligne d'aide qui pointe vers le bon endroit.
Infrastructure mock retirée
- Suppression de
MockPlatformApiClient,MockTokenManageret de la plomberiepaUseMock/paMockBehaviordansCustomUBL/UBLInvoiceProcessor/LogCatalog. Le mode mock PA n'avait plus de raison d'être depuis le refactor api-connecteur — pour des tests hors-ligne, il suffit de pointer un api-connecteur vers un mock Postman ou un stub local. - L'éditeur
EInvoicingEditorperd l'onglet Mock / Testing (l'éditeur passe de 5 à 4 onglets). Le Tableau de bord IT n'affiche plus l'indicateur PA mode / mock. Les fichiers de configuration et la charge utile/api/systemne portent plus le drapeau mortpaUseMock.
Petits nettoyages
- La vérification ConfigApi a été réécrite pour parcourir de bout en bout la nouvelle forme par référence de connecteur (référence connector par modèle → résout vers l'api-connecteur → valide baseUrl + champs d'authentification + résolution des noms d'endpoint par tâche).
DirectoryApiClientimpose la forme par référence de connecteur viaPaConnectorResolver(pas de repli vers l'inline). Même schéma strict que e-invoicing et e-reporting.- Commentaires « tombstone » et marqueurs
// retired in 2026.05retirés deCustomUBL,UBLInvoiceProcessor,LogCatalog,IPlatformApiClientetEInvoicingEditor.
2026.05.7 — 2026-05-09
Grosse version côté connecteurs et notifications. Nouveau type de modèle connecteur SQL qui permet de définir des requêtes nommées de la même façon que les api-connecteurs définissent leurs endpoints, avec un éditeur de paramètres et un panneau de test. Les deux types de connecteurs peuvent désormais être câblés depuis les liaisons d'actions et les règles de notification, qui ont elles-mêmes gagné une liste d'appels multiples avec arrêt sur échec et chaînage des réponses (placeholders {call.N.fieldName}). L'éditeur de règles de notification est réorganisé en six onglets, les appels d'action se replient derrière un en-tête de description, et la boîte de réception affiche le journal des actions sous forme de pastilles colorées. Plusieurs anciens bugs du dispatcher et des éditeurs sont aussi corrigés.
Connecteurs SQL (nouveau)
- Nouveau type de modèle
sql-connector— paramètres de connexion (Oracle / PostgreSQL / URL / DBUser / DBPassword / schéma / timeout / maxRows) plus une liste de requêtes nommées. Chaque requête porte un nom, un libellé, une description libre, une spécification de paramètres (name|label|default;…), le SQL avec des placeholders:param, et un drapeauWritable. Voir Connecteurs SQL. - Le binding des paramètres passe par
PreparedStatement— les jetons:namesont réécrits en?positionnels et liés positionnellement, les valeurs ne sont jamais substituées par concaténation. Le parseur respecte les chaînes entre apostrophes, les identifiants entre guillemets, les commentaires de ligne et de bloc, et l'opérateur de cast PostgreSQL::type. - Liste blanche des types d'instructions :
SELECT/INSERT/UPDATE/DELETE/MERGE.DROP/TRUNCATE/ALTER/GRANTetc. sont rejetés avant même l'ouverture de la connexion. Les instructions non-SELECTexigent en plusWritable=Ouisur la requête concernée — une faute de frappe dans une règle de notification ne peut pas accidentellement déclencherDELETE FROM …. - Nouvelle route back-end
/api/sql-connectors(liste + exécution), parallèle à/api/connectors. NouveauSqlConnectorEditordans Paramètres avec trois onglets : Connection / Queries (cartes repliables par requête) / Test (exécute la requête sur la base cible, affiche les colonnes + lignes ou le nombre de lignes affectées). - Bouton + Add SQL dans l'en-tête Settings à côté de + Add API ; les connecteurs SQL ont leur propre groupe latéral avec un badge
sql.
Liaisons d'actions et règles de notification multi-appels
- Les liaisons d'actions (boutons réglementaires du modal facture) et les règles de notification portent désormais une liste d'appels au lieu d'un seul. Les appels partent dans l'ordre de déclaration ; le comportement par défaut est poursuivre en cas d'échec, à l'image du canal e-mail.
- Drapeau Arrêt sur échec par appel — interrompt la chaîne au premier échec, tracé dans le journal sous la forme
STOP · N appel(s) restant(s) ignoré(s). - Champ Description par appel affiché en en-tête de carte repliée, pour qu'une liaison à plusieurs appels se lise comme une liste à cocher en un coup d'œil. Les nouveaux appels s'ouvrent automatiquement ; le chargement d'une règle replie tout.
- Chaînage des réponses : la sortie de chaque appel est versée dans un contexte sous des clés
call.N.*. Les appels suivants y accèdent via{call.N.fieldName}dans leur payload.- Les appels api-connecteur exposent tous les mappings
endpoint.N.response.*que le connecteur définit, plussuccess/statusCode/error. - Les appels sql-connecteur exposent les colonnes de la première ligne par leur nom, plus
success/rowCount/updateCount/statementType/error.
- Les appels api-connecteur exposent tous les mappings
- Compatibilité ascendante : les anciennes règles et liaisons mono-action continuent de fonctionner — les anciennes clés à plat sont lues comme une liste à un élément au chargement et réécrites au format canonique
action.N.call.M.*à la prochaine sauvegarde. - Le helper front-end
executeConnectorActionroute selon le type de modèle (api/sql) et retourne une enveloppe uniforme — le runner d'actions du modal facture n'a donc pas à connaître le type.
Refonte de l'éditeur de règles de notification
- Le formulaire long et unique passe à six onglets : Général · Déclencheur · Canaux · Email · Actions · Test. L'onglet revient à Général au changement de règle.
- Les paramètres de destinataire sont sous Canaux à côté des cases de livraison. Les onglets Email et Actions affichent leur contenu sans condition ; la case « action » a été retirée — les appels partent automatiquement quand la règle a au moins un appel (désactiver la règle pour les supprimer).
- Le menu déroulant des connecteurs liste les api-connecteurs et les sql-connecteurs fusionnés avec les suffixes
· API/· SQL; le menu cible charge les endpoints ou les requêtes selon le type du connecteur choisi.
Trace des actions dans la boîte de réception
- Le dispatcher ajoute désormais un pied d'audit par appel au corps rendu (enregistré dans
NTK74MSG2) — l'enregistrement portail garde une trace permanente de ce qui a été déclenché avec cette alerte. Plafonné à la largeur de colonne moins une marge de sécurité. - La boîte de réception affiche l'audit sous forme de pastilles colorées sous le message —
OKvert,FAILrouge,STOPorange,SKIPgris — au lieu de mélanger les lignes d'audit dans le corps tronqué. - L'aperçu de la cloche retire le pied d'audit et affiche à la place une ligne récapitulative : 2 action(s) exécutée(s) (gris) ou 1 action(s) en échec sur 2 (rouge), pour qu'un coup d'œil suffise à savoir s'il faut ouvrir la boîte de réception.
Corrections du dispatcher de notifications
- Les actions ne partaient jamais depuis les notifications. Trois causes, toutes traitées :
- La boucle de dispatch exigeait l'ancienne case « action » dans les canaux ; le verrou est retiré — une liste d'actions non vide suffit.
- Le dispatcher s'arrêtait prématurément quand
recipients.isEmpty(), supprimant les règles purement actionnelles et celles dont la résolution de destinataire échouait ; l'arrêt prématuré est retiré (les boucles portail/email no-op naturellement sur une liste vide). - Surtout,
EmailDispatcher.send()pouvait bloquer surtransport.close()face à des serveurs SMTP capricieux (leQUITde Gmail). Le thread worker restait bloqué, supprimant silencieusement chaque étape suivante. Corrigé en (a) exécutant les actions avant l'email pour qu'un teardown SMTP bloqué ne puisse jamais les empêcher, et (b) bornanttransport.close()sur un thread daemon avec un budget de 5 secondes — le message a déjà été livré parsendMessage, abandonner la fermeture est sans risque.
- Diagnostics : lignes
INFOstructurées par dispatch et par appel sur stdout (dispatch rule=X status=Y channels=… actions=N,dispatching N action call(s),call #N → connector/endpoint,api-action … HTTP 200/sql-action … ok (N row(s))), avecWARNsur l'arrêt sur échec et la fermeture SMTP lente, et lignesERRORqui portent le motif d'échec.
Corrections d'éditeur
ConfigApi.updateTemplateremplace désormais entièrement les propriétés de la ressource au lieu de fusionner la nouvelle map par-dessus l'ancienne. Sans cela, les éditeurs qui renumérotent des listes indexées (appels d'action, endpoints, requêtes, codes de statut) laissaient traîner d'anciennes entrées — un appel #2 supprimé ressuscitait au chargement suivant caraction.2.*n'était jamais retiré. Le correctif s'applique à tous les éditeurs qui font un aller-retour sur une map de propriétés structurée.- Le bouton Add mapping d'api-connecteur fonctionne — l'effet d'état local de
ResponseMappingsEditorutilise maintenant une dépendance JSON-stringifiée pour que les lignes vides survivent au re-render parent. Auparavant la nouvelle ligne disparaissait dès le clic parce que leRecordvide du parent était une nouvelle référence d'objet à chaque rendu. - Nouveaux helpers
Resource.removeProperty(name)etResource.clearProperties()utilisés par le chemin de sauvegarde en remplacement complet.
Flux des traitements en cours (Tableau de bord IT)
/api/dashboard/log-tailreconstruit autour deF564237(journal d'exécution) au lieu deF564236(erreurs de validation). Le widget du Tableau de bord IT affiche maintenant les jobs lancés par le planificateur qui démarrent et se terminent en direct, avec des badges de méthode (STARTvert,ENDbleu, erreurs en rouge).- Requête bornée à la journée (
FEUPMJ = today AND FEUPMT > since) avec un repli en cas de passage de minuit qui supprime le plancher horaire si le widget était en pause au moment du changement de date — le prédicat reste sur l'index, peu importe la profondeur d'historique.
Widget Système de fichiers — regroupement par partition
File.getFreeSpace()renvoie des chiffres au niveau de la partition : tous les chemins du même point de montage affichaient donc la même barre d'usage disque. Le back-end émet désormais unfsIdpar chemin ; le widget regroupe les chemins parfsIdet affiche l'usage disque une fois par système de fichiers, avec les lignes de chemin en dessous.
2026.05.6 — 2026-05-09
Nouveau Tableau de bord IT dédié aux équipes techniques avec 14 widgets couvrant JVM / BD / disque / débit / erreurs / planificateur — page distincte du tableau de bord métier existant pour que chaque public dispose d'une vue dimensionnée à ses besoins. Tableau de bord métier réaligné, vérification de configuration réécrite contre le schéma actuel orienté connecteur, et nouveau suivi d'IP en mémoire qui alimente la carte Sessions actives quand l'authentification est désactivée.
Tableau de bord IT (nouvelle page)
- Nouvelle entrée Documentation → Tableau de bord IT qui regroupe tout ce dont un opérateur IT a besoin en un coup d'œil : Santé système (heap JVM / GC / threads / uptime), ping BD, informations de build, widget Système de fichiers (espace libre / total + nombre de fichiers pour
appHome/processHome/dirInput/singleOutput/burstOutput/dirArchive/dirError), graphique de débit, courbe d'erreurs, taux de relance, temps de traitement par modèle, sessions actives, traitements en cours en direct (paires START / END des jobs, erreurs en rouge), vérification de configuration, tables de base, erreurs récentes, planificateur. Voir Tableau de bord IT. - Nouveaux endpoints back-end
/api/system,/api/dashboard/tech,/api/dashboard/log-tail,/api/dashboard/config-check— payloads groupés pour que la page se mette à jour en un seul aller-retour. - Le widget Système de fichiers parcourt chaque chemin de façon récursive (plafonné à 5000 fichiers pour rester rapide) et gère les jokers d'exécution (
%TEMPLATE%,%FILE_NAME%) en tronquant au premier rencontré pour rapporter sur le répertoire existant le plus profond au-dessus.dirOutputretiré de la liste — déjà couvert parprocessHome. - Le widget Temps de traitement par modèle charge les événements START/END de
F564237à plat et les apparie côté Java sur(FEWDS1|FEUPMJ)avec un helperhhmmssToSeconds()pour un calcul de durée correct — remplace une auto-jointure SQL cassée (FETMPLambigu et arithmétiquee.FEUPMT - s.FEUPMTincorrecte).
Tableau de bord métier — réalignement
- Widget Planificateur retiré (présent désormais sur le tableau de bord IT — le public métier n'en a pas besoin).
- Dernière rangée réorganisée de
(Par société 6 | E-Reporting 6)+(Round-trip 6 | Planificateur 6)à une seule rangéePar société 4 | E-Reporting 4 | Round-trip 4pour que trois widgets courts se partagent une rangée équilibrée plutôt que de laisser une demi-cellule vide. - Grille passée en
align-items: stretch, les panneaux remplissent leur Span viaflex: 1— Activité récente atteint maintenant le même bord bas que la colonne empilée Points d'attention + Règles d'erreur les plus fréquentes à côté. Même correction pour la nouvelle rangée du bas.
Sessions actives sans authentification
- Nouveau
ActivityTrackeren mémoire (map IP →lastSeen) mis à jour à chaque requête depuisWebServer.handle(). QuandauthEnabled=N, il n'y a aucune ligneF564252à compter — la carte Sessions actives du tableau bascule donc sur Clients actifs · 15 min alimentée par ce tracker. L'équipe IT voit enfin qui utilise l'application et depuis où, sans avoir à activer l'authentification.
Vérification de configuration — réécriture
/api/dashboard/config-checkvalidait des propriétés obsolètes (paApiBaseUrl/paApiLoginEndpoint/paApiImportEndpoint/paApiUsername/paApiPassword/paApiDirectoryEndpoint/paApiEReportingEndpoint/ublXsdPath/ublSchematronPath) — aucune n'existe dans le schéma actuel orienté connecteur. La carte remontait 8 fausses erreurs sur une configuration parfaitement valide.- Valide désormais :
baseUrl,authType, identifiants selon le type d'authentification (OAUTH2 / BASIC / BEARER) et la présence d'un endpoint nomméimport(avertissement siimport-statusmanque). E-directory contrôlebaseUrl+ endpointdirectory-checkquandcheckDirectory=Y. E-reporting contrôleissuerSiren/frequency/fluxquandsendToPA=Y. Vérifications obsolètes des chemins XSD / Schematron retirées — les ressources de validation sont embarquées dans le JAR.
Divers
- Le groupe Documentation de la barre latérale contient désormais l'entrée Tableau de bord IT.
- Vue groupée de ProcessingLog :
FEUKIDutilisé comme départage pour que deux événements partageant le mêmeUPMJ+UPMTgardent un ordre stable d'un rafraîchissement à l'autre.
2026.05.5 — 2026-05-08
Passe d'architecture pilotée par le refactoring des noms de colonnes : chaque requête SQL du backend passe désormais par UBLColumnConfig (plus de littéraux UHKCO / FETXFT codés en dur) et par UBLTableConfig (les tables d'auth et de notifications rejoignent les autres comme tables configurables). Les droits de rôles deviennent des lignes (F564254) au lieu de listes CSV, permettant d'ajouter une dimension de permission sans changer le DDL. Groupes de codes de statut, journal d'exécution et BLOB d'e-reporting sont reformatés pour être conformes JDE et indépendants du dialecte. Deux bugs Oracle historiques (espaces de remplissage NCHAR, commentaires SQL avec guillemets) sont corrigés.
Refactoring configuration colonnes / tables
- Tous les sous-handlers Java (
InvoiceApi,EReportingApi,IntegrationApi,DashboardApi,AiAssistant,WebApiHandler,UBLDatabaseHandler,RuntimeLogHandler,UBLInvoiceProcessor, …) résolvent désormais les noms de colonnes exclusivement viacols.<accesseur>. Le templatedb-nomaubl-columnsles écrase tous de manière cohérente — fini la dérive silencieuse quand un client renomme une colonne. - Les tables d'auth (
F564250users,F564251roles,F564252sessions, nouvelleF564254permissions) et la table de notifications (F564253) sont maintenant des entrées à part entière dansUBLTableConfiget l'onglet Settings → db-nomaubl → Tables, au même niveau que les tables factures / e-reporting. Elles participent à la substitution DDL si renommées. WebServer.javane contient plus de JDBC :resolveKeysByUblNumber,readTemplateName, le middleware d'auth-validation et la lecture du blob UBL ont migré vers les sous-handlersapi/*;WebServerne fait plus que router.- Nouvelle page Références croisées (Documentation → Références croisées) générée à la compilation. Pour chaque accesseur
tables.<X>/cols.<X>, elle liste tous les sites d'appel Java qui le lisent, avec une case « afficher accesseurs inutilisés » pour repérer le code mort. Régénérée parXrefScannerà chaquebash build.sh, sans maintenance manuelle.
Permissions par rôle — droits ligne par ligne (F564254)
- Nouvelle table
F564254(PMROLE,PMCRAPPID,PMCRAPPVAL,PMENABL) qui remplace les quatre colonnes CSVRLPAGES/RLCOMPANIES/RLSETTINGS/RLREADONLYdeF564251. Chaque droit est une ligne typée (page/company/feature) ; ajouter une nouvelle dimension de permission est désormais un INSERT, pas un changement de DDL. - Réinitialisation sûre : supprimer
F564254puis rejouer Init Database réinjecte les droits admin/viewer sans toucher aux lignes de rôles existantes. Sur une base déjà peuplée, l'opération ne fait rien. Le log indique combien de droits ont été insérés. - Éditeur Rôles (Settings → users-roles → Roles) refondu : liste de cartes avec actions copier / supprimer, panneau d'édition avec case à cocher par fonctionnalité + texte d'aide, sociétés en table avec bouton Add row (plus de séparateurs virgule), section Allowed Pages avec libellés lisibles (clés i18n
nav.*réutilisées de la barre latérale) + l'identifiant de page en gris monospace à côté. La colonne Tag est en lecture seule — référencée par les méthodes factory Java, la renommer casserait silencieusement les appels. F564252(sessions) renommée selon les conventions JDE :SSLSID(token UUID) /SSUSER/SSSTDTIM(début) /SSETDTIM(fin).F564251/F564254reçoivent les champs d'audit JDE classiques (USER/PID/JOBN/UPMJ/TDAY).
Groupes de codes de statut + nettoyage tableau de bord
- Le template statuses gagne un 6ᵉ champ pipe pour les groupes : niveau supérieur (
inflight/errorTech/errorBusiness/terminal) et étapes du funnel (created/sent/pending/transmission/approved/rejected). Nouvel endpoint/api/status-codes/groups. - Les compteurs SQL de
DashboardApiet les cartes du dashboard (PipelineFunnel,EReportingCoverage,StaleInvoices,RecentActivity,invoiceHelpers.statusColors) lisent depuis cette source unique au lieu d'intégrer leurs propres listesIN ('9904','9905',…). Ajouter un nouveau code de statut PA est une ligne dansconfig-template-lists.json. - Le store React
statusGroupsStoreest chargé une fois au démarrage de l'application et déclenche un re-render global ponctuel à l'hydratation du cache ; les couleurs de statut s'affichent correctement dès le premier rendu après connexion (plus besoin de « naviguer ailleurs et revenir »). - Éditeur Statuses : chaque ligne s'étend désormais en formulaire 4 colonnes avec sélecteur de groupes par puces + dropdown et recherche sur code / tag / libellés / code PA / libellés de groupes. Tag en lecture seule.
Journal d'exécution (F564237)
- Ajout de la PK
FEUKID(séquence calculée à l'insert viaCOALESCE(MAX(FEUKID),0)+1, indépendante du dialecte). - Renommage des colonnes selon les conventions JDE :
FEMODE→FERMK,FEMETHOD→FERMK2,FEMESSAGE→FEK74MSG1(1024). Largeur deFETMPLramenée à 40. - Les troncatures à l'insertion correspondent aux nouvelles largeurs. La réponse REST du processing-log inclut maintenant
id, utilisé comme clé React stable et comme 3ᵉ critère de départage pour que deux événements partageantUPMJ+UPMTne s'inversent plus entre deux rechargements de page. - Vue groupée par job : le même critère de départage
FEUKIDcorrige le bug d'ordreSTART/ENDqui faisait apparaître les deux comme orphelins alors qu'ils étaient appariés. Les erreurs FATAL affichent maintenant un badge compactFATAL ERROR/ERROR/FAILED+ le chemin complet dans la colonne message (qui débordait avant).
XML binaire e-reporting (F564260.RGTXFT)
- Type changé de
TEXT/CLOBversBYTEA/BLOB. Le backend écrit le XML en octets UTF-8 viadialect.writeBlob/ lit viadialect.readBlob(utilisaitwriteText/readText, incompatibles avec le nouveau type binaire). - À noter : les tables e-reporting sont renumérotées —
F564240/F564241/F564242deviennentF564260/F564261/F564262. Les colonnes FK des tables filles passent deRGUKIDàRHUKID(cycle de vie) etRIUKID(mapping). Voir Tables de base de données.
TRIM piloté par le dialecte (NCHAR Oracle)
- Nouveau helper
DatabaseDialect.trimChar(col)— enveloppe avecTRIM(col)côté Oracle (gère le remplissage par espaces desNCHARJDE qui faisait silencieusement échouer les comparaisons d'égalité), retourne la colonne brute côté PostgreSQLVARCHAR(pas de remplissage, pas d'appel de fonction inutile → les index restent utilisables). - Correction du compteur de notifications resté vide chez un client : avec un
*stocké enNCHAR(10)(donc*+ 9 espaces) et un bind JDBC string, la clause WHERE comparait'* 'à'*'sans jamais correspondre. Même cause racine derrière la sémantique de diffusion du dispatcher — les deux corrigées. - Passe sur 9 fichiers / 47 occurrences :
InvoiceApi,DashboardApi,IntegrationApi,EReportingApi,EReportingFetcher,AiAssistant,JDEBipExtractor,InvoiceStatusesHandler,ApiCommons.categoryFilter. Tout passe pardialect.trimChar.
DDL runner
- Le découpage des instructions respecte maintenant les guillemets et les commentaires de ligne. Avant, tout
;à l'intérieur d'un littéral'…'(par exemple dans unCOMMENT ON COLUMN IS '…; …') coupait l'instruction en deux, produisant des erreursUnterminated string literalà l'initialisation.
Interface / paramètres
- Settings → db-nomaubl → Tables donne accès à Auth · Users / Roles / Sessions / Permissions et à la table Notifications, au même titre que les tables factures et e-reporting.
- Le panneau Validation Errors du modal détail de facture affiche maintenant chaque ligne sur deux niveaux (niveau + règle + date en haut, message en dessous) pour que les longs textes de règles localisées ne se battent plus avec le code de règle.
- L'onglet Initialize de db-nomaubl voit sa zone de log s'étendre à toute la hauteur disponible au lieu de plafonner à 200 px avec du vide au-dessous.
2026.05.4 — 2026-05-07
Tableau de bord refondu en grille 12 colonnes + page Erreurs d'intégration transformée en véritable outil d'analyse, avec des descriptions de règles extraites des fichiers Schematron embarqués pour ne plus laisser l'utilisateur déchiffrer un code à la main. Le mode clair devient le mode par défaut. Deux bugs de dialecte Oracle qui vidaient silencieusement des panneaux du tableau de bord sur les installations clientes sont corrigés.
Tableau de bord
- Grille 12 colonnes en remplacement de la disposition empilée. La rangée hero (Total / En cours / Rejetée — IT / Rejetée — Business) s'appuie sur les compteurs par statut existants ; en dessous, un funnel pipeline, un graphique de volume, le couple Activité récente / Bloquées + Règles en échec, Par société / Couverture e-Reporting, puis Aller-retour PA / Santé du planificateur.
- La rangée Activité récente / Règles en échec est désormais en 6/6 pour s'aligner avec les rangées du dessous — le précédent 8/4 rendait la carte Activité visuellement plus large que sa voisine.
- Le widget Règles en échec gagne un sélecteur
TOUT / UBL / INTEGdans son en-tête et remplace les barres proportionnelles par des lignes classées de largeur égale (badge de rang + code de règle + ligne de description secondaire + compteur). Les anciennes barres proportionnelles rendaient des comptes de 160 vs 10 visuellement quasiment identiques. - Les cartes hero ouvrent désormais la liste des factures avec un filtre multi-statuts (
/api/invoices?status=A,B,C) pour que les cartes En cours / Rejetée — IT / Rejetée — Business aboutissent sur une liste correctement filtrée et non sur la liste complète.
Page Erreurs d'intégration
- Bascule de vue : par évènement (table à plat existante) et par règle (cartes regroupées par règle + source, chaque carte affichant le nombre de factures et des chips par sévérité). Les cartes conservent une largeur égale grâce à
auto-fill— une dernière rangée courte n'étire plus une carte isolée sur toute la largeur. - Nouvelle case
Sans correspondance— l'ancien comportement (erreurs sans facture jointe) reste à un clic, tout en affichant par défaut toutes les erreurs. - Filtre catégorie (
Validation UBL/Intégration / cycle de vie) sur les deux vues, mappé côté backend sur une listeUVSRCL IN (...)pour que les règles Schematron / XSD soient analysables séparément des erreurs d'exécution / dispatcher (PDF, PA, BDD, …). - Cliquer sur une ligne de la vue par évènement ouvre la modale facture sur l'onglet Historique (alignement avec Notifications).
- Liens profonds depuis le widget Règles en échec — Voir toutes les erreurs ouvre l'onglet par règle, et un clic sur une règle donnée bascule sur la vue par évènement avec la règle déjà appliquée en chip de filtre.
Catalogue de descriptions de règles
- Nouveau
ValidationRuleCatalog(Java) qui parse les.schembarqués au premier appel et extrait un dictionnaire{id de règle → description humaine}en cherchant les lignes[<id>]<séparateur><description>dans chaque bloc<assert>. Le séparateur est permissif (-ou:, espaces optionnels) pour couvrir les trois formats des quatre Schematrons embarqués :- EN 16931 :
[BR-CL-23]-Description(sans espace) - FREXT-IC :
[BR-FREXT-IC-08] - Description(avec espaces) - CIUS-FR :
[BR-FR-23/BT-49] : Description(deux-points, plus la convention FNFE-MPE où l'id de l'assert utilise_et le code entre crochets/— la recherche retente automatiquement avec_→/).
- EN 16931 :
- Le matcher du tag d'ouverture capture les attributs en un seul bloc, ce qui lui permet de retrouver
id="…"quel que soit l'ordre des attributs — la version précédente exigeaitiden premier et ignorait silencieusement toutes les règles CIUS-FR. - Douze règles de cycle de vie / intégration issues de
ErrorCatalog(UBL_CREATION,DB_INSERT,PA_SEND, …) sont amorcées avec une description FR dans le même dictionnaire. - Nouvel endpoint
GET /api/integration-errors/catalogqui retourne le catalogue fusionné. Le frontend le met en cache pour la page via un petit hookuseRuleCatalog. - Là où apparaît un code de règle (widget Règles en échec, cartes par règle, colonne Règle de la vue par évènement) la description s'affiche en infobulle et comme ligne secondaire sous le code.
- Limitation connue : les 34 asserts du Schematron
BR-FR-CPROn'ont pas d'attributid, le validateur enregistre donc un code de règle vide — ces lignes restent sans libellé.
Correctifs de dialecte Oracle
loadByCompanyetloadRoundTripStatsutilisaient tous deuxcolonne <> ''pour filtrer les lignes vides. Sur Oracle, la chaîne vide est stockée commeNULLetNULL <> ''vautNULL(traité comme faux), si bien que la clause WHERE s'effondrait et que les deux requêtes renvoyaient zéro ligne sur les installations Oracle des clients tout en fonctionnant parfaitement en Postgres local. Remplacé parLENGTH(TRIM(colonne)) > 0(loadByCompany) et purement supprimé dansloadRoundTripStatsoù la clause IN filtre déjà les NULL des deux côtés.
Thème
- Le mode clair devient le mode par défaut pour une première visite. La bascule continue de mémoriser le choix de l'utilisateur dans
localStorage; les utilisateurs qui avaient précédemment opté pour le mode sombre le conservent.
2026.05.3 — 2026-05-06
Système de notifications — les changements de statut d'une facture atteignent désormais les utilisateurs via une boîte de réception dans le portail, par e-mail (avec le PDF de la facture joint par défaut) et par appels d'API externes, le tout piloté par des règles définies par l'utilisateur.
Stockage et orchestrateur
- Nouvelle table
F564253(DDL Oracle + Postgres, plus ajout dansAuthManager.initTablespour qu'une installation neuve la crée automatiquement). Une ligne par notification délivrée, cléNTUKIDseule, avec(NTDOC, NTDCT, NTKCO)référençant la facture. Index composites sur(NTUSER, NTEV01, NTUPMJ DESC)pour la pastille de la cloche et l'inbox, et sur(NTDOC, NTDCT, NTKCO)pour l'historique au niveau facture. - Nouveau package
custom.ubl.notify:NotificationDispatcher(singleton avec un pool de 2 threads pour l'envoi asynchrone),NotificationDatabaseHandler(CRUD surF564253, avec troncature à l'insertion alignée sur les largeurs de colonnes pour qu'une valeur source inhabituellement longue ne fasse pas échouer l'envoi),EmailDispatcheret le POJONotificationRule. - Les règles sont enregistrées comme ressources
notification-ruledans un fichier dédiéconfig-notifications.jsonà côté de la configuration principale ;ConfigJsonrépartit les ressources vers ce fichier en fonction de leur type. - Purge quotidienne dans
BackgroundSchedulerpilotée parglobal.notificationsRetentionDays(défaut 90 jours,0désactive). - À la première initialisation, le dispatcher enregistre un crochet d'arrêt JVM ; les exécutions CLI qui se terminent juste après une mise à jour de statut peuvent ainsi vider le pool de threads (sursis de 2 secondes) avant l'arrêt du processus.
Points d'intégration sur les changements de statut
- Branchement dans
InvoiceStatusCatalog.StatusTransition.apply()après les écritures en base : les règles sont évaluées et déclenchées à chaque transition. Toutes les exceptions sont capturées — un échec de notification n'annule jamais la mise à jour de statut sous-jacente. - Les valeurs de statut, motif et action qui viennent d'être appliquées sont passées directement à
NotificationDispatcher.fire(...). Le dispatcher n'a donc plus à relireF564231depuis une connexion JDBC séparée — cette lecture renvoyait un instantané périmé tant que la transaction appelante (par exempleImportStatusHandler) n'avait pas encore été validée, ce qui faisait apparaître l'ancien libellé dans le corps de la notification. - Le
SetStatusModalcôté UI (cible base de données) déclenche désormais aussi les notifications — ce chemin contournaitStatusTransition.applyet restait silencieux auparavant. - Les modes CLI (
-process,-fetch-import,-fetch-status,-fetch-single,-fetch-all, l'ancien-run) appellent un utilitaire communinitRuntimeCatalogsqui initialise à la foisInvoiceStatusCatalogetNotificationDispatcher. Sans cela, les traitements en lot mettaient à jour les statuts mais ignoraient les notifications, le singleton du dispatcher n'étant jamais initialisé.
Canal e-mail
- Une seule transaction SMTP par envoi : toutes les adresses (l'e-mail résolu de la cible portail plus chaque entrée d'
emailRecipients) sont placées dans l'en-têteTo:d'un seul message, en un appel àTransport.sendMessage. La boucle adresse-par-adresse précédente se bloquait dès qu'un serveur SMTP gérait mal la fermeture de connexion en milieu de boucle, ce qui faisait disparaître silencieusement tous les envois après le premier. - Séquence explicite
Transport.connect/sendMessage/closedans untry/finallyavec délais d'expiration stricts sur la socket (connectiontimeout,timeout,writetimeout, tous à 20 s). Les erreurs au moment duclosesont absorbées, pour qu'un nettoyage bloqué ne contamine pas l'envoi suivant. - PDF de la facture rendu et joint par défaut, contrôlé par le drapeau
attachPdfde la règle (valeur par défautY). Le PDF est généré une seule fois par envoi et réutilisé pour chaque destinataire ; un échec de rendu est tracé mais ne fait pas échouer l'e-mail. - Sujet et corps par défaut quand la règle laisse
emailSubjectouemailBodyvides :Invoice {doc} {dct} {kco} — {statusLabel}pour le sujet de l'e-mail et un corps avec les lignesStatus / Reason / Action. LeNTMSGPcôté portail garde uniquement le libellé du statut, la boîte de réception affichant déjàNTDOC · NTDCT · NTKCOà côté.
Modèle de destinataire
- La cible portail (utilisateur / rôle) et
emailRecipientssont des champs indépendants : possibilité de renseigner l'un, l'autre ou les deux. La cible portail reçoit aussi automatiquement le canal e-mail si son compte F564250 a unUSEMAILrenseigné. emailRecipientsaccepte les séparateurs,et;.- Compatibilité ascendante : les règles existantes avec
recipientType=emailsont migrées au chargement — l'adresse passe dansemailRecipientset le type est vidé. - Résolution des destinataires plus tolérante : si la lecture de F564250 échoue (connecteur
db-nomaublabsent, table manquante, incident transitoire), un destinataire portail est tout de même émis avec le nom d'utilisateur littéral, au lieu d'abandonner la règle silencieusement avec un message No recipients resolved.
Installations sans authentification
- Lorsque
global.authEnabled != "Y", le dispatcher écrit les lignes portail sous une valeur sentinelle de diffusion (NTUSER='*') ; les routes inbox et cloche interrogent cette même sentinelle quand aucun utilisateur n'est connecté. Les notifications fonctionnent sans qu'aucune ligne F564250 ne soit nécessaire. - La cloche reste visible dans la barre d'utilitaires quel que soit l'état d'authentification (auparavant cachée à l'intérieur de la branche réservée aux utilisateurs connectés).
- L'éditeur de destinataire adapte ses libellés : quand l'authentification est désactivée, l'option vide affiche Diffusion — tous les utilisateurs au lieu de Aucune — emails uniquement.
Frontend
- Nouvelle page Notifications (promue de Gestion vers Application en 2026.05.4) — boîte de réception avec onglets Toutes / Non lues, action tout marquer comme lu, suppression par ligne, badge de statut coloré selon le catalogue, bande d'accent pour les lignes non lues, et une ligne méta
doc · dct · kco · motif · action · règle. Cliquer sur une ligne ouvre la facture liée dansInvoiceDetailModal. Voir Notifications. - Nouvel éditeur Règles de notification — liste latérale et formulaire à sections : déclencheur, canaux, destinataire, contenu e-mail, appel d'action, et un panneau de Test synchrone qui exécute réellement la règle. Les codes de déclenchement utilisent des multi-sélections à puces alimentées par les ressources
statusesetrejection-reason-codes— la règle ne peut donc plus diverger des codes assignables à une facture. La section action reprend la structure de Process API : connecteur en liste déroulante, endpoint en liste déroulante alimentée parapi.connectors.listEndpoints(...), et lignes de paramètres pré-remplies à partir de la définition de l'endpoint. Voir Règles de notification. - Nouveau composant NotificationBell dans la barre d'utilitaires — interroge
/api/notifications/unread-counttoutes les 30 s, affiche une pastille rouge avec le compteur et un menu déroulant des 6 dernières notifications. Cliquer sur une notification la marque comme lue puis ouvre directement la modale de la facture via un événementnomaubl:open-notificationsurwindow(cela fonctionne même quand l'utilisateur se trouve déjà sur la page de la boîte de réception et que le composant n'est donc pas remonté). - Permissions de rôle pour les deux nouvelles pages, plus une nouvelle icône
belldans le jeu d'icônes central.
2026.05.2 — 2026-05-06
Soumission B2B française à la PA — pièces jointes PDF qualifiées (LISIBLE + documents associés) et plusieurs corrections d'intégrité de l'aller-retour qui ont émergé pendant la mise en œuvre.
Pièce jointe LISIBLE + pièces jointes additionnelles qualifiées
- Nouveau drapeau
lisibleY/N sur les modèles de document. QuandY, un PDF est rendu à partir de l'UBL fraîchement généré via lepdf-templaterésolu, puis réinjecté en tant que pièce jointe « facture lisible » (cbc:ID = "LISIBLE"). Indépendant du sélecteurattachmentexistant — les deux peuvent s'activer sur la même facture. - Nouvelle propriété JSON
additionalAttachments— liste d'entrées{code, path}intégrées comme blocscac:AdditionalDocumentReference. Éditeur UI dans l'onglet Document avec un sélecteur de code (RIB,BON_LIVRAISON,BON_COMMANDE,PJA,BORDEREAU_SUIVI,BORDEREAU_SUIVI_VALIDATION,DOCUMENT_ANNEXE,ETAT_ACOMPTE,FACTURE_PAIEMENT_DIRECT,RECAPITULATIF_COTRAITANCE,FEUILLE_DE_STYLE) et un champ chemin. Les chemins acceptent les placeholders%APP_HOME%,%ENV%,%DOCNAME%,%KCO%,%DOC%,%DCT%. Les fichiers manquants sont tracés et ignorés — ils ne font pas échouer le traitement. Tranform.embedPdfInUBLreçoit une nouvelle surcharge à code String. Le qualifieur devient lecbc:IDducac:AdditionalDocumentReferenceinséré.cbc:DocumentTypeCoden'est pas émis (UBL-SR-43 le réserve aux objets facturés 130 / 50) etcbc:DocumentDescriptionn'est pas émis non plus (la PA retournait HTTP 400 quand il était présent en plus de la pièce jointe). La signature 3-args reste identique : les appelants qui utilisent la forme historiquePDF_Invoicene sont pas impactés.PdfTemplateEngine.renderetInvoicePdfGenerator.generategagnent un booléenmergeAttachment. Le flux LISIBLE passefalsepour que le PDF rendu n'hérite pas d'une pièce jointe déjà intégrée par le flux historiquecreate/attach— sinon LISIBLE dupliquerait visiblement le PDF original à l'intérieur de lui-même.
Corrections de format XML pour acceptation PA
Le parser de la Plateforme Agréée s'est avéré sensible à des octets précis que le code historique ne respectait pas :
embedPdfInUBLrepassait l'UBL par le transformer Xalan du JDK, qui émet<?xml version = '1.0' encoding = 'UTF-8'?>(espaces autour de=, apostrophes). Passage à Saxon (déjà utilisé parconvertToUBL) pour que la sortie corresponde octet pour octet à<?xml version="1.0" encoding="UTF-8" standalone="no"?>. PropriétéSTANDALONE = "no"explicite ; attributfilenameémis avantmimeCodepour respecter l'ordre historique.convertToUBLforce aussistandalone="no", pour que les flux qui contournentembedPdfInUBL(exécutions sans pièce jointe) produisent la même déclaration XML acceptée par la PA.- Le nouveau
AdditionalDocumentReferenceest inséré sur sa propre ligne — l'indentation est recopiée depuis le nœud blanc existant, avec une indentation supplémentaire en tête quand l'élément précédent est lui aussi un nœud Element (les pièces jointes consécutives et le<cac:AccountingSupplierParty>qui suit conservent chacun leur séparateur\n).
Garde-fou de ré-indentation ConfigJson
tryReIndentJson désérialisait toute chaîne commençant par { ou [ comme du JSON imbriqué — y compris les variables de gabarit comme "{content}", "{statusAt}", "{reportName}" utilisées par d'autres modèles. La désérialisation « réussissait » parce que les crochets s'équilibraient, produisant un objet aux clés non quotées qui rendait config.json impossible à relire au rechargement suivant. Nouvelle heuristique looksLikeJson() qui exige soit un conteneur vide, soit un vrai démarreur de valeur JSON (clé entre guillemets après {, etc.) avant de récurser. Les modèles existants contenant des chaînes {placeholder} font désormais l'aller-retour correctement.
Divers
parseUblXmllitcbc:LineExtensionAmount(BT-131) directement etInvoiceDetailModall'affiche tel quel comme montant de ligne au lieu de recalculerqty × prix ± remises— le recalcul comptait deux fois quand le prix unitaire était déjà net (une ligne 45 × 12,75 avec une remise ligne de 489,15 affichait 84,60 au lieu de 573,75 dans le modal alors que le PDF était correct).ubl-template.xsl: nouveau slotTAG_CUSTOMER_SIRET(BT-46) à côté du SIREN acheteur existant.
2026.05.1 — 2026-05-05
Moteur de modèles PDF — Phase 2 : les modèles PDF deviennent des ressources partageables de premier ordre, gagnent une section générique block pilotée par XPath, et un éditeur visuel à part entière.
Modèles PDF en ressources de premier ordre (Phase 2a)
- Nouveau type de ressource
pdf-template, persisté dansconfig-pdf.json(renommé depuisconfig-pdf-templates.jsonpour la concision). - Nouvelle page Modèles PDF (entrée du menu sous Gestion) pour créer, copier, importer, exporter et éditer des mises en page indépendamment de tout modèle de document. Voir Modèles PDF pour la référence complète.
- Les documents référencent une mise en page via la propriété
pdfTemplateportée par la ressource doc-template. Plusieurs documents peuvent partager un même modèle PDF — édition unique, propagation à l'ensemble. - Chaîne de résolution :
pdfTemplatedu doc-template →defaultPdfTemplatesurglobal→ modèle interne livré. Le nom réservébuilt-inest en lecture seule et toujours disponible comme filet de sécurité. - JSON formaté lisiblement sur disque : les objets
template/configimbriqués sont écrits comme de vrais objets JSON indentés (et non comme des chaînes échappées), pour rester lisibles dans n'importe quel éditeur. Aller-retour assuré parConfigJson.readPropertyValue, partagé pour que les loaders restent agnostiques de la forme sur disque.
Section générique block (Phase 2b)
- Nouveau type de section
block— primitives de mise en page pilotées par XPath qui se composent en n'importe quel contenu, sans classe dédiée :text(littéral),field(valeur XPath, avec libellé inline optionnel et formatagedate/currency/number/percent) ;image,spacer,hr;- conteneurs
row/column(alignement + écart) ; repeat(XPath → liste, rend sonchildpar occurrence) ;if(XPath → booléen, rendchildsi vrai) ;table— grillelignes × colonnesavec bordures de cellules optionnelles et ligne d'en-tête stylée. Définirxpathla fait itérer (une ligne par occurrence), les enfants servant de gabarit par ligne.
- Les XPath des cellules à l'intérieur d'une table itérante sont automatiquement rendus relatifs : un chemin absolu commençant par le XPath de l'itérateur est tronqué au moment du rendu pour que chaque ligne s'évalue dans son propre contexte itéré.
align: end | centersur unrowréduit la ligne à ~50 % de largeur et aligne la table entière de ce côté, au lieu d'étirer des cellules à parts égales sur toute la page (les paires « libellé + valeur » restent groupées à droite).
Éditeur visuel (Phase 2c)
- Nouveau
BlockCanvasEditormonté dans le tiroir de toute sectionblock: trois panneaux empilés (arbre, barre d'outils, inspecteur) plus une issue de secours JSON. - Inspecteur : formulaires d'attributs par type avec sous-panneau de style ; le sélecteur Type en haut transforme le nœud sélectionné sur place (column → repeat sans suppression / recréation) via le helper
transmuteKindqui reporte les champs compatibles. - Le chargeur d'XML d'exemple est remonté à l'en-tête du modèle — chargement unique, tous les blocks réutilisent les entrées pour l'autocomplétion XPath.
- Le sélecteur XPath préserve les préfixes de namespace
cbc:/cac:(requis par le moteur namespace-aware côté backend) et émet/*/<chemin-complet>pour que les sélections soient sans ambiguïté et indépendantes de la racine (Invoice ou CreditNote indifféremment). À l'intérieur d'un ancêtre itérant, le sélecteur supprime en plus le préfixe de l'itérateur pour que les cellules démarrent en chemin relatif (cbc:TaxAmountau lieu de/*/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount). - L'aperçu en direct est remonté en haut du formulaire et s'ouvre dans une modale 960 × 85vh — fini la valse scroll-down / scroll-up pendant l'itération sur une mise en page.
- Le sélecteur de section est remonté en haut et converti en chips : un clic ajoute une section en haut de la liste, automatiquement ouverte pour rendre l'inspecteur immédiatement visible.
blockpeut être ajouté plusieurs fois par modèle ; chaque block porte unnameutilisateur affiché à côté de la ligne de section.
Refonte du tiroir des sections prédéfinies
- Les bascules utilisent le composant
Checkboxpartagé (style rond-bleu cohérent au lieu des cases natives en mode sombre). - Les bascules sont parsées par préfixe
Catégorie · Nomet regroupées en colonnes côte à côte qui reflètent la mise en page PDF réelle — Header se lit comme METAS | SUPPLIERS, Line Table comme Group headers | Columns | Sub-details au lieu d'une longue liste plate. - Bordure du tiroir adoucie : trait fin avec un accent bleu de 2 px à gauche.
Corrections critiques
- Scanner JSON top-level : le parser maison utilisait un naïf
indexOfpour localiser"<clé>", qui faisait silencieusement correspondre la première occurrence imbriquée. Une table avecchildrenlisté avantxpathse retrouvait avec sonxpathrésolu vers celui du premier enfant, l'itérateur retournait 0 nœud, et la table entière disparaissait du PDF rendu. Remplacé parfindTopLevelValueStartqui respecte la profondeur de crochets et l'état de chaîne, et n'identifie que les clés au niveau 1. ConcernereadString,readFloat,readBool,readStringArrayet les recherchestree/children/child/styledansparseNode. - Boucle d'écho de l'éditeur :
parseConfigperdait le champnamedu block etuseEffect [value]dePdfTemplateFormre-parsait à chaque écho — combinés, chaque frappe déclenchaitsetSelectedPath([])et démontait l'inspecteur, volant le focus et (sur émissions répétées) figeant la page. Les deux fonctions préservent désormaisname, et les deux effets de seed sautent quand la valeur entrante correspond à la dernière émise (lastEmittedRef). - Tables itérantes : un NodeList vide retourne désormais
nullproprement pour qu'OpenPDF n'étouffe pas sur une table à 0 ligne, et chaque cellule est rendue dans son propre try/catch — une cellule en erreur devient un placeholder[ERROR]inline au lieu de casser la mise en page complète de la ligne.
Backend / helpers partagés
PdfContextporte désormais leDocumentparsé namespace-aware pour que les sectionsblockexécutent du XPath sans re-parser le XML UBL.ConfigJsonexposereadPropertyValue,findStringEnd,findMatchingBracket,jsonUnescape,compactJsonettryReIndentJsonpour que d'autres types de ressources puissent opter pour le stockage JSON imbriqué formaté lisiblement.
2026.05.0 — 2026-05-05
Refonte importante du pipeline de traitement de documents, du générateur PDF et de la surface REST des factures.
Traitement piloté par le modèle de document (XML ou UBL)
- Nouvelle propriété
source(XML|UBL) sur chaque modèle de document. Choisie dans l'onglet Document de Gestion → Documents. XMLconserve le comportement actuel (XSL → UBL → BDD → envoi PA).UBLcible les fichiers déjà au format UBL 2.1. La clé primaire(doc, dct, kco)est extraite ducbc:IDde la facture via une regex à groupes nommés (idPattern+ valeurs par défautdocDefault/dctDefault/kcoDefault). Exemples :F202600025→^(?<dct>[A-Z]+)(?<doc>\d+)$(kcoDefault = 00001)38706889RI00001→^(?<doc>\d+)(?<dct>[A-Z]+)(?<kco>\d+)$
- L'onglet Document inclut un assistant Exemple cbc:ID + Suggérer + Tester qui dispense d'écrire la regex à la main : coller un ID réel, Suggérer remplit la regex en segmentant sur les transitions lettres / chiffres, Tester applique le motif et les valeurs par défaut et affiche en direct le
(doc, dct, kco)extrait. - La convention
DOC_DCT_KCO_ubl.xmln'est plus exigée — le traitement UBL extrait toujours les clés depuiscbc:ID. Le nom de fichier peut être quelconque.
Point d'entrée unique pour le traitement
- Les pages Process XML et Process UBL disparaissent. Une seule page Process Document les remplace ; le formulaire bascule entre contrôles XML et UBL selon le
sourcedu modèle choisi. - Une seule route backend :
POST /api/process(remplace/api/runet/api/process-ubl). - Une seule commande CLI :
-process <config> <modèle> <fichierOuDossier> [type] [drapeaux](remplace-xmlet-ubl).nomaubl.sh process …. -fetch-singleet-fetch-allperdent l'argumentprocessType— inféré à partir du modèle. Fetch Input et Paramètres → Planification perdent également le sélecteur Type de traitement.
Nouvelle page Documents
- Sidebar → Gestion → Documents ouvre une page dédiée aux modèles de documents (les entrées de
config-documents.jsonréférencées parF564231.UHTMPL). Elle dispose de ses propres boutons Ajouter / Importer / Copier / Supprimer et d'un champ Description. Les Paramètres conservent Ajouter Connecteur / Copier / Supprimer pour les modèles système et les connecteurs uniquement.
F564231.UHTMPL — lien facture → modèle
- Nouvelle colonne
UHTMPL VARCHAR2(40)sur la table d'en-tête. Stockée au moment du traitement (chemins XML et UBL) pour permettre au générateur PDF de retrouver lepdfTemplateJSON spécifique au document lors du rendu. - DDL ajouté à
sql/oracle/ddl.sqletsql/postgres/ddl.sql.
Surface REST factures — clé primaire propre
- Toutes les routes
/api/invoices/{…}utilisent désormais(doc, dct, kco)directement (/api/invoices/{doc}/{dct}/{kco}/lines,/lifecycle,/errors,/vat,/notes,/xml,/resend,/validate,/status, ainsi quePUT/DELETE). L'identifiant composite, le helpercastToVarchar(UHDOC)et le||UHDCT||UHKCOdans les WHERE disparaissent pour toute recherche par clé. Plus rapide (utilise les index) et propre côté Postgres. - Nouveau helper
bindDoc()qui lie le paramètre numériqueUHDOCviasetInt; Postgres ne rejette plussetStringsur une colonneINTEGER.
/invoice/view (PDF) — recherche à double forme
GET /invoice/view?id=<numéro de facture UBL>(comparé àUHK74FLEN) ou?doc=&dct=&kco=. La page peut être liée depuis n'importe où — y compris collée dans le navigateur — sans nécessiter d'identifiant composite.
Refonte du générateur PDF
InvoicePdfGeneratoréclaté (1 027 lignes monolithiques) en un packagecustom.ubl.pdf:PdfTheme,UblXmlHelpers,InvoiceData,UblParser,PdfDrawing,PdfContext,PdfTemplate/PdfTemplateEngine/PdfTemplateLoader/DefaultPdfTemplate, registrePdfSection, et une classe par section souscustom.ubl.pdf.sections/(Header, Parties, Agent, LineTable, DocAllowances, VatBreakdown, TotalsBox, Payment, NoteBlock).- Nouveau moteur de template JSON — les sections sont listées et réordonnées dans le modèle, chacune avec sa configuration
config(visibilité des colonnes, bascules de sous-détails, comportement d'en-tête de groupe, saut de page par livraison, …). Édité dans Documents → 🖼 PDF Template : réordonnancement par glisser-déposer, drawer de configuration par section et iframe d'aperçu en direct (POST /api/pdf-templates/preview). - L'override par document est stocké dans la propriété
pdfTemplateJSON du modèle (lien viaF564231.UHTMPL). Si vide, la mise en page par défaut est utilisée.
Améliorations frontend
- Sidebar — nouvelle entrée Documents sous Gestion ; entrée Process Document remplaçant Process XML / Process UBL ; barre de défilement fine adaptée au thème pour atteindre les groupes en débordement (clair et sombre).
- Les placeholders de chemin (
%APP_HOME%,%ENV%,%PROCESS_HOME%) dans la page Process Document sont résolus côté serveur avant le branchement absolu / basename, pour que les fichiers choisis via Browse fonctionnent même lorsquedirInputcontient un placeholder. - XML — sortie spool JDE renommé en Spool XML partout — le pipeline XSL est générique, seul BIP est spécifique à JDE.
- Diverses petites corrections : binding de la description sur la liste Documents, nettoyage des modales Settings, statut / send-status / email migrés vers
(doc, dct, kco), suppression deaugmentPromptWithSitemapdans AiAssistant.
Rôles / Permissions
- Nouvelle clé de page
documentsdans l'éditeur de rôles (sous Gestion) afin que les installations avec rôles restreints puissent autoriser ou refuser la nouvelle page.
2026.04.10 — 2026-05-04
Paramètres e-invoicing — configuration hybride envoi FTP / statut API
- L'onglet PA Connection masquait précédemment la configuration API (Base URL, Authentification, Récupération de statut, Planification en arrière-plan) lorsque Send Mode = FTP, rendant impossible une configuration hybride où les factures partent en SFTP mais où la relève des imports, la récupération des statuts et les actions vendeur passent toujours par l'API. Toutes les sections sont désormais toujours visibles ; le sélecteur de mode est renommé Send Mode avec un texte d'aide précisant qu'il ne pilote que le transport sortant. Chaque section non active reçoit une mention grise (utilisé pour la récupération de statut / l'import / les actions vendeur ou utilisé lorsque Send Mode = FTP) qui rend visible d'un coup d'œil le rapport entre champs et opérations.
XSL — BT-46 (SIRET acheteur)
- Correction de
XTSE0680: Parameter siren is not declared in the called templatedansubl-common.xsl: l'appel àubl:party-siretpassait<xsl:with-param name="siren">au lieu dename="siret"(copier-coller depuis le bloc adjacentubl:company-siren). - Correction de la validation XSD
cvc-complex-type.2.4.alors de l'émission de BT-46 :<cac:PartyIdentification>est un enfant de<cac:Party>, pas de<cac:PartyLegalEntity>. L'émission du SIRET sort deubl:party-legal-entity(l'appel d'aide intégré était structurellement invalide) et figure désormais directement dans le bloccac:Partydu XSL document, avantcac:PartyTaxScheme/cac:PostalAddress. Les XSL document qui ont besoin de BT-46 doivent suivre le même schéma. TAG_CUSTOMER_SIRET(BT-46) ajouté au catalogue de l'éditeur XSL et promu dans la liste principale de la section acheteur, à côté deTAG_CUSTOMER_SIRENdans Variables.
2026.04.9 — 2026-04-30
Paramètres — correction de l'état d'éditeur obsolète au changement de liste
- Le passage d'un modèle à un autre ouvrait parfois l'éditeur de droite avec les lignes de la liste précédemment consultée. Deux causes : les éditeurs qui amorcent leur état interne depuis les props au montage (les 14 éditeurs de listes, StatusesEditor, DocumentTypesEditor, …) gardaient les lignes du modèle précédent car leur initialiseur
useStatene s'exécute qu'une fois ; etselectTemplate()basculaitselectedimmédiatement maispropsn'était mis à jour qu'au retour du fetch, si bien que des clics rapides pouvaient acheminer un fetch obsolète vers le mauvais modèle. - Correction : le rendu de l'éditeur est désormais enveloppé dans un
<div key={selected}>keyé avecdisplay: contents, ce qui force React à démonter l'éditeur précédent et à monter une instance fraîche à chaque sélection.selectTemplate()purge de manière synchroneeditData / props / rawPropset tient un compteur de séquence de fetch, abandonnant toute réponse rendue obsolète par un clic ultérieur.
Détail facture — bouton Télécharger UBL
- Nouveau bouton Télécharger UBL dans l'onglet History de la modale de détail facture, à côté de Validate UBL. Enregistre le XML UBL brut stocké dans
F564231.UHTXFTdans un fichier local nommé{doc}-{dct}-{kco}.xml. Réutilise l'endpointGET /api/invoices/{id}/xmlet leublRawXmldéjà chargé dans l'état de la modale, sans appel supplémentaire. Le bouton est désactivé avec une infobulle tant que le XML n'est pas chargé.
Assistant IA — message d'accueil automatique à la première ouverture
- L'ouverture du panneau de chat sans historique envoie automatiquement un message d'accueil localisé (Bonjour / Hello selon la langue de l'IHM), pour que l'assistant se présente et liste ses principales capacités sans que l'utilisateur n'ait à saisir une première requête. À usage unique par chargement de page : la fermeture / réouverture du panneau en cours de session ne répète pas le message d'accueil, et les conversations existantes sont préservées.
2026.04.8 — 2026-04-29
Assistant IA — outil d'historique de cycle de vie + délégation REST
- Nouvel outil local
lifecycle_history: retourne toutes les transitions de statut d'une facture issues de F564235 (séquence, code statut + libellé, message, date / heure, motif de rejet PA + libellé, action attendue + libellé, note de statut) — même charge utile que celle rendue par l'onglet History de la modale de détail facture. Permet à l'IA de répondre à « pourquoi la facture X a-t-elle été rejetée / qu'a dit la PA » sans recourir à « je n'ai pas accès à cet historique ». validation_errorsetlifecycle_historydélèguent désormais aux gestionnaires REST existantsWebApiHandler.handleInvoiceErrors/handleInvoiceLifecycle(l'onglet History de l'IHM React appelle les mêmes endpoints). Le SQL dupliqué dans les outils IA a été supprimé, ce qui fait bénéficier l'IA des noms de tables configurablesUBLTableConfig, des requêtes adaptées au dialecte (Oracle vs Postgres) et de la résolution de libellés de statut maintenue côté REST. Une seule source de vérité.- Les catalogues complets de statuts factures + e-reporting sont désormais ajoutés au prompt système au moment de la conversation (lus dans
InvoiceStatusCatalogetEReportingStatusCatalog, ce qui propage les personnalisations utilisateur). Le modèle devinait des codes à partir d'expressions comme litige (49 au lieu du vrai 207) — il dispose désormais de la table en contexte et utilise le code exact aveclist_invoices/list_ereports. AIChatPanel: la zone de saisie reprend le focus dès que l'assistant a fini de diffuser sa réponse, supprimant la nécessité de cliquer à nouveau dans le champ pour poser la question suivante.
2026.04.7 — 2026-04-29
Assistant IA — correction de url_not_allowed sur web_fetch
- Le
web_fetchd'Anthropic ne télécharge que les URL apparues précédemment dans des messages utilisateur ou des résultats d'outils antérieurs. L'injection sitemap de 2026.04.6 plaçait les URL dans le prompt système où elles ne comptent pas, si bien que chaque fetch retournaiturl_not_allowed. Une première tentative d'exposer le catalogue via un outil personnalisélist_docs_pagesretournant du JSON a aussi échoué — l'extracteur d'URL d'Anthropic scanne le contenu detool_resulten texte brut et ne reconnaît pas les URL encadrées par des guillemets JSON. - Correction finale :
list_docs_pagesretourne désormais le sitemap en texte brut, une URL par ligne. L'extracteur Anthropic les capture, et l'appelweb_fetchqui suit aboutit. Claude suit un parcours en deux étapes propre :list_docs_pages→web_fetch→ réponse. - Les appels d'outils serveur + leurs résultats sont désormais affichés dans le chat sous forme de pastilles en ligne (📖
web_fetch · <url>, 📥web_fetch_result · ✓ <url>ou ❌<error_code>), rendant visibles les modes d'échec auparavant absorbés silencieusement — ce qui a précisément permis de déboguer le problème JSON-vs-texte.
2026.04.6 — 2026-04-29
Assistant IA — recherche documentaire pilotée par le sitemap
- Le modèle savait qu'il pouvait récupérer
docs.nomana-it.frmais ignorait quelles URL existaient ; il devinait et ratait, ou abandonnait et répondait depuis ses connaissances antérieures. Le backend récupère désormaissitemap.xmlune fois au démarrage, filtre les entrées au préfixe documentaire (par défauthttps://docs.nomana-it.fr/nomaubl), et injecte la liste de pages obtenue dans le prompt système — ce qui amène le modèle à choisir une URL réelle plutôt qu'à deviner. - Le sitemap est mis en cache pendant 6 heures et plafonné à 200 pages. Les échecs sont silencieux (le snapshot précédent reste en service) et ne bloquent jamais l'appel chat.
- Deux nouvelles propriétés
globaloptionnelles :aiDocsSitemapUrl(par défauthttps://docs.nomana-it.fr/sitemap.xml, vide pour désactiver l'injection sitemap) etaiDocsPathPrefix(par défauthttps://docs.nomana-it.fr/nomaubl).
2026.04.5 — 2026-04-29
Assistant IA — correction de compatibilité ascendante pour web_fetch
- Les configurations existantes antérieures à 2026.04.4 ne disposent pas de la nouvelle propriété
aiDocsDomainsdans leur modèleglobal, si bien que l'assistant démarrait sans outilweb_fetchet indiquait (à raison) qu'il n'avait pas accès à la documentation. - Nouvelle sémantique pour
aiDocsDomainsdansAiAssistant: propriété absente → valeur par défautdocs.nomana-it.fr(compatibilité ascendante — aucune édition manuelle requise) ; chaîne vide → désactivation explicite ;"a,b,c"→ utilisation de cette liste. Aucun changement de BDD ni d'API ; uniquement une valeur par défaut côté serveur.
2026.04.4 — 2026-04-29
Assistant IA — utilisation d'outils (recherche documentaire + outils de données en lecture seule)
- Le panneau de chat permet désormais au modèle d'appeler des outils en cours de conversation au lieu de répondre uniquement depuis ses connaissances antérieures. Deux couches : recherche documentaire via l'outil serveur
web_fetch_20250910d'Anthropic, avecallowed_domainsverrouillé sur la listeglobal.aiDocsDomains(par défautdocs.nomana-it.fr) ; et outils opérationnels en lecture seule exécutés localement contre la même base que l'IHM (list_invoices,explain_status_code,validation_errors,list_ereports). Activable viaglobal.aiToolsEnabled(par défaut Y). - Nouveau
global.anthropicSystemPromptqui surcharge le prompt système intégré. Vide = utiliser le défaut intégré qui décrit le produit, indique l'URL documentaire au modèle et liste les plages de codes statut (1373 / 99xx / 9950 – 9957). - Backend récrit dans
AiAssistant.java: boucle d'appels d'outils (jusqu'à 5 tours), diffuse les deltas de texte sous forme{type:"token"}et expose les invocations d'outils sous forme{type:"tool_call",name,summary}afin que l'IHM affiche une pastille en ligne (📖 web_fetch, 🔍 outil local) au-dessus de la bulle assistant pendant que l'appel est en cours. - Paramètres → System → Global → onglet AI : trois nouveaux champs (System Prompt textarea, Allowed Doc Domains liste séparée par virgules, Custom Tools Y/N).
- Les réponses de l'assistant sont désormais rendues en Markdown via
react-markdown+remark-gfm: titres, gras, listes, tableaux GFM, blocs de code, code en ligne et liens s'affichent correctement. Les liens externes s'ouvrent dans un nouvel onglet.
Voir Capacités IA pour la référence utilisateur complète.
2026.04.3 — 2026-04-29
XML E-Reporting — conformité à la spécification Flux 10
EReportingXmlBuilderréécrit pour respecter la nomenclature officielle FNFE-MPE Flux 10 (TT-1..TT-99, TG-8..TG-39). Les anciens noms personnalisés (<Identifier>,<DocumentType>,<Flux>,<Period>,<Customer>,<Totals>,<TaxBreakdown>) sont remplacés par ceux de la spec :<Id>,<IssueDateTime><DateTimeString>,<TypeCode>,<Sender><Id schemeId>+<Name>+<RoleCode>,<Issuer><Id schemeId>+<Name>+<RoleCode>,<TransactionsReport><ReportPeriod><StartDate>+<EndDate>. Les dates sont émises au formatyyyymmdd(période) etyyyymmddhhmmss(date d'émission), sans séparateur.- Application stricte de la règle G6.28 de routage B2C / B2BINT : les transactions B2C n'émettent jamais de bloc
<Invoice>individuel — seuls des blocs<Transactions>agrégés sont produits (un par CategoryCode + devise, avec des<TaxSubtotal>imbriqués portant TaxPercent / TaxableAmount / TaxTotal). Le B2BINT continue d'émettre un<Invoice>par facture avec ID, IssueDate, TypeCode, CurrencyCode, Seller (déclarant), Buyer (contrepartie), MonetaryTotal, et<TaxSubTotal>par taux. - Conformément à G6.23, tout
TaxAmount/TaxTotalest désormais exprimé en EUR (l'attributcurrencyIdest verrouillé surEUR) quelle que soit la devise de la facture source. Les montants taxables conservent la devise d'origine. <Transactions><CategoryCode>(TT-81) restreint au sous-ensemble de la spec :TLB1(livraisons de biens taxables),TPS1(prestations de services taxables),TNT1(non taxable),TMA1(régime de la marge) ; bascule automatiquement surTLB1/TNT1selon le taux quand la ligne source contient une valeur hors-liste.- Nouvelles propriétés optionnelles du template
e-reporting:senderName,senderRoleCode(par défautWK),issuerName,issuerSchemeId(par défaut0002, avec0223/0227/0228/0229pour les cas internationaux),issuerRoleCode(SE/BY),businessProcessIdetbusinessProcessTypeId(TT-28 / TT-29 émis sur le<BusinessProcess>par facture en B2BINT uniquement), etflowName(TT-2). L'éditeur Settings → Système → E-Reporting expose ces champs en trois sections groupées : Sender (PA), Issuer (Déclarant), Business Process. <ReportDocument><Id>est désormais initialisé par défaut à{siren}-{flux}-{début}-{fin}quand aucun identifiant de transmission n'est fourni — une valeur stable par période contre laquelle la PA peut dédupliquer.- Catalogue de statuts dédié à l'e-reporting (codes 9950 – 9957), indépendant de la plage invoice 99xx. Le nouveau
EReportingStatusCatalogcharge le nouveau template systèmeereporting-statuses(libellés FR / EN éditables dans Settings → Système → ereporting-statuses, en parallèle du templatestatusesexistant). Codes :9950 EREPORT_CREATED,9951 EREPORT_SUBMIT_SKIPPED,9952 EREPORT_SENT_TO_PA,9953 EREPORT_PENDING,9954 EREPORT_ERROR_SENT,9955 EREPORT_DEPOSITED,9956 EREPORT_FAILED_IMPORT,9957 EREPORT_REJECTED. Le catalogue se réamorce automatiquement avec des valeurs par défaut intégrées si le template est absent, donc les installations existantes continuent de fonctionner sans migration manuelle.EReportingHandlerréécrit pour utiliser ces codes (auparavant il réutilisait ceux des factures) ; le cas « envoi PA désactivé » pose désormais son propre code au lieu de réutiliserSTATUS_CREATED. EReportingFetcherlit désormais les sous-totaux de TVA principalement depuis le XML UBL stocké dansF564231.UHTXFT(parse les nœudscac:TaxTotal/cac:TaxSubtotalau niveau document — les sous-totaux par ligne sont ignorés pour éviter le double comptage). Le comportement précédent (lecture deF564234) est conservé en repli, pour que les déploiements qui ne matérialisent pas la table de récapitulatif TVA puissent malgré tout produire des reports. Corrige le symptôme « bloc<Transactions>vide » sur les reports B2C quandF564234n'était pas remplie alors que les factures et leur XML UBL étaient bien stockés.
Settings → éditeurs de listes (perte de focus à la saisie)
- Correctif appliqué à 15 éditeurs de listes (Statuses, Countries, ActionCodes, CurrencyCodes, CustomizationIds, InvoiceTypes, PaymentMeans, NoteTypes, DocumentReferenceCodes, RejectionReasonCodes, SchemeIds, UnitCodes, ProfileIds, VatexCodes, VatCategories) : la saisie dans n'importe quelle ligne perdait le focus après chaque caractère — et toute nouvelle ligne ne pouvait pas être remplie.
- Cause : chaque éditeur disposait d'un
useEffect(() => setRowsState(...), [props])qui reconstruisait l'état local des lignes à partir des props du parent à chaque render. Comme l'éditeur lui-même renvoie les lignes au parent à chaque frappe (et le parent re-render), un aller-retour était créé qui recomposait le tableau de lignes → React démontait / remontait les inputs → le curseur était éjecté. Pire,*RowsToPropsfiltre les lignes dont la clé / code est vide : toute nouvelle ligne disparaissait des props du parent dès la première frappe hors de la colonne clé. - Correctif : suppression de la synchronisation props → rows. Chaque éditeur ensemence ses lignes à partir des props une seule fois au montage et reste l'unique écrivain ensuite. Les clés React restent liées à l'index du tableau, ce qui préserve l'identité des inputs des lignes existantes entre les renders.
- Pour
StatusesEditorspécifiquement, les champstypeetdescriptiondu template sont désormais préservés lors de l'écho vers le parent (ils étaient silencieusement supprimés, ce qui corrompait le templatestatusesà la sauvegarde).
Refonte du schéma E-Reporting
- Renommage des colonnes des tables F564240 / F564241 / F564242 selon la structure JDE fournie :
- F564240 :
RGDOC → RGUKID(PK = RGUKID seul, sans composante flux / kco ; déclarée enNUMBER(15)sur Oracle /BIGINTsur Postgres dans le DDL statique et dansAuthManager.initTables),RGFLUX → RGY56BAR,RGTYPCD → RGDCT,RGPSTART → RGEFTJ,RGPEND → RGEFDJ,RGISSUID → RGY56EPID,RGINVCNT → RGNINV. Suppression deRGSENDID(l'émetteur reste dans la config + l'XML, non persisté) etRGUKIDSZ(l'UUID PA n'est plus stocké — la submission est tracée via le statut + le cycle de vie uniquement). - F564241 : la colonne FK vers F564240 conserve le préfixe parent (
RGUKID) ;RHFLUX → RHY56BAR; suppression deRHKCO(la KCO se récupère via la table parente). PK =(RGUKID, RHSEQN). - F564242 : la FK est
RGUKID;RIFLUX → RIY56BAR; suppression de la colonne report-RIKCO. Le triplet facture perd l'infixINV:RIINVDOC / RIINVDCT / RIINVKCO → RIDOC / RIDCT / RIKCO. PK =(RGUKID, RIDOC, RIDCT, RIKCO).
- F564240 :
- Mêmes changements dans le DDL Oracle, le DDL Postgres et
AuthManager.initTables(le bouton Initialize Database crée donc la nouvelle structure). EReportingDatabaseHandler: renommage du champrgdoc → rgukid;kcon'est plus porté par le handler (seul F564240 le contient, fixé au moment de l'insertReport).nextSequence()fait désormaisMAX(RGUKID) + 1(globalement unique). SignatureinsertReport(typeCode, kco, …): paramètresenderIdsupprimé.updatePATransactionId()supprimé (colonne disparue). Tous les INSERT enfants mis à jour avec les nouveaux noms de colonnes.- La sous-requête NOT EXISTS de
EReportingFetcherréécrite avec les nouvelles colonnesRIDOC / RIDCT / RIKCO / RIY56BAR. - API REST simplifiée :
/api/ereporting/{flux}/{kco}/{rgdoc}→/api/ereporting/{rgukid}./api/ereporting/{flux}/{kco}/{rgdoc}/resend→/api/ereporting/{rgukid}/resend. JSON renvoyé :rgdoc→rgukid; champssenderetpaUuidsupprimés. - Types frontend, client API, page liste, modale de détail, colonnes et i18n mis à jour en conséquence (le resend renvoie une fois l'UUID PA dans sa réponse, conservé pour l'afficher dans le bandeau de succès).
- Modale de détail → onglet Factures : suppression de la colonne Numéro. Le triplet DOC / DCT / KCO est l'identifiant canonique ; le numéro UBL n'était qu'une copie d'affichage de la même donnée, retirée avec sa clé i18n, le champ
invoiceNumberdeEReportInvoiceLinket la jointureUHK74FLENcôté backend.
Dashboard / Carte « À propos »
- Le schematron EXTENDED-CTC-FR est désormais listé dans la carte À propos de cette version (clé
frExtendedCtc, libellé EXTENDED-CTC-FR) — il était livré dans le JAR mais absent de/api/build-info. BuildInfoextrait désormais en priorité l'estampille FNFE-MPE (Schematron yyyymmdd_NAME_VX.Y.Z …) avant le motif génériqueSchematron version X.Y.Z; Flux 2 et Extended-CTC-FR intègrent tous deux la version source EN 16931 (1.3.15) dans leurs commentaires, ce qui induisait précédemment le parseur en erreur.- Restriction de la date EN 16931 à un format ISO
yyyy-mm-ddstrict, supprimant le--parasite hérité du-->de fermeture du commentaire.
2026.04.2 — 2026-04-29
Validation
- Correctif : la re-validation d'une facture existante depuis InvoiceDetailModal → Historique (ainsi que le chemin
validateUblDirect) échouait aveccvc-elt.1.a: Cannot find the declaration of element 'Invoice'. LaDocumentBuilderFactoryutilisée pour parser l'UBL n'était pas namespace-aware par défaut, et le validateur XSD ne pouvait donc pas associer<Invoice>/<CreditNote>au schéma UBL 2.1.setNamespaceAware(true)est désormais positionné sur les deux instances de parser.
2026.04.1 — 2026-04-29
Journal des traitements
- Le traitement UBL écrit désormais une paire
START/ENDdansF564237afin que le Journal des traitements couvre ProcessUBL (/api/process-ubl), fetch-invoices en mode UBL et le CLI-ubl— comme le faisait déjà-xml.FEMODE = PROCESSpour ces lignes ;FETMPLreste vide (aucun template de document ne s'applique au traitement UBL).
Page Validation UBL
- Correctif : l'upload d'un fichier UBL ne tombe plus dans
<input>/_ubl/(substitution littérale de la sentinelle_ubl). L'upload utilise désormais le dossier conventionnel<input>/ubl/, en cohérence avec les endpoints fetch / list-files. - Correctif : la validation d'un fichier UBL uploadé n'échoue plus avec
No such file or directory. Le nom de base présent dans le formulaire est résolu vers<dirInput>/ubl/avant parsing ; les chemins absolus issus du navigateur de fichiers continuent de fonctionner.
Validation
- Nouveau schematron EXTENDED-CTC-FR (FNFE-MPE
EXTENDED-CTC-FR-UBL-V1.3.0) embarqué et câblé dansUBLValidator. - Le schematron français appliqué est désormais piloté par
cbc:CustomizationID(BT-24). Lorsque l'URN contientEXTENDED/extension, la règle EXTENDED-CTC-FR est exécutée à la place de EN 16931 + CIUS-FR (sur-ensemble dérivé qui assouplit volontairement certaines règles EN 16931 —UBL-CR-550est par exemple commentée pour autoriserInvoiceLine/Delivery). Pour toutes les autres valeurs, le comportement précédent est conservé : base EN 16931 + surcouche CIUS-FR (BR-FR Flux 2). CPRO-B2G continue de s'auto-déclencher surcbc:Note#ADN#B2Gquel que soit le profil.
Configuration / UBL Defaults
- Nouvelle liste système
customization-ids(BT-24) pré-remplie avec les URN françaises standard (base EN 16931, FNFE-MPE Basic / Extended CTC, Factur-X Minimum / Basic / Basic WL / Extended, Peppol BIS Billing 3) — pleinement éditable depuis Settings → Customization IDs. - UBL Defaults → Header : BT-24 est désormais une liste déroulante alimentée par la liste
customization-ids(la saisie libre reste accessible en repli si la liste est vide ou si la valeur n'est pas enregistrée).
Mode replace
- Le retraitement en mode replace purge désormais
F564235(cycle de vie) etF564236(erreurs de validation) en plus deF564231/F564233/F564234. Auparavant ces deux tables append-only continuaient à croître à chaque rejeu, mêlant un historique de cycle de vie périmé et des erreurs de validation obsolètes aux données du dernier run. - Nouvelle méthode
UBLDatabaseHandler.purgeForReplace()qui efface en une seule fois les cinq tables UBL pour un(doc, dct, kco)donné. Appelée parUBLInvoiceProcessor.process(chemin UBL) etCustomUBL(chemin XML) dès quereplaceMode=true, de sorte que les deux chemins ont désormais une sémantique replace identique, quelle que soit la présence de la ligne F564230 préexistante.
2026.04.0 — 2026-04-29
E-Reporting (Flux 10.1 / 10.3)
- Nouvelle page E-Reporting au premier niveau : liste, modale de détail, dialogue de génération.
- Nouvelles tables
F564240,F564241,F564242(configurables dans le paramétragedb-nomaubl; créées par Initialize Database). - Nouveau template système
e-reporting+ surcharges par sociétée-reporting-{kco}; la soumission réutilise le token PA dee-invoicing[-{kco}]via le nouvel endpointreport-import. - CLI :
-ereporting <config> [start=AAAAMMJJ] [end=AAAAMMJJ] [kco=...] [flux=10.1,10.3] [type=IN]. - Ordonnanceur d'arrière-plan : nouvelle tâche
ereportingIntervaldansglobal. - Modale de détail : l'onglet Factures utilise un
DataTableavec export CSV / Excel. - Modale de détail : bouton de téléchargement du XML généré (remplace l'onglet XML inline).
Journal des traitements
- Nouvelle entrée Processing Log sous le menu Management, basée sur
F564237. - Vue groupée (par défaut) : chaque traitement est replié sur une seule ligne
START → ENDavec badge de statut, durée et liste dépliable des étapes intermédiaires ; la vue à plat est conservée pour les utilisateurs avancés. - Barre d'outils : listes déroulantes pour Mode et Modèle, sélecteur de période (défaut : 7 derniers jours), recherche par nom de fichier.
Dashboard
- Nouvelle carte À propos de cette version ancrée en bas du dashboard avec le numéro de version, la date de build, la version du profil AFNOR et les versions de chaque module Schematron (EN 16931, BR-FR Flux 2, BR-FR CPRO).
Documentation
- Nouvelle page Notes de version (menu Documentation) qui affiche ce fichier.
- Maintenue en deux langues —
RELEASE.md(anglais) etRELEASE.fr.md(français) embarqués dans le JAR ; la page sélectionne la bonne en fonction de la langue active de l'IHM. - Sommaire en haut de page avec une vignette par version cliquable.
- Rendu Markdown maison avec prise en charge de la continuation paresseuse des listes (les puces réparties sur plusieurs lignes sont rendues comme un seul élément).
Settings
- L'éditeur
db-nomaublexpose les trois nouveaux noms de tables e-reporting (tableEReporting,tableEReportingHist,tableEReportingMap), avec les valeurs par défautF564240/F564241/F564242. - L'action Initialize Database crée désormais les trois tables e-reporting en plus des tables UBL / auth existantes.
- Le sélecteur de pages dans l'écran Rôles expose les nouvelles pages
processinglogetreleasenotesafin de pouvoir y donner accès aux rôles existants.
Backend
- Défauts
DatabaseDialect.writeText/readText— le XML est stocké enCLOB(Oracle) /TEXT(PostgreSQL) viasetString/getStringportables (évite le piège pgjdbcgetClob → OID). nodeToBytesdansUBLDatabaseHandlerforce désormaisOutputKeys.INDENT="no"afin que le XML écrit dansF564230.FETXFTne soit pas pretty-printé par Saxon en mode fat-jar (même correctif que celui déjà appliqué à l'UBL)./api/build-info(public) retourne les métadonnées de version + les fichiersRELEASE.md/RELEASE.fr.mdembarqués.
1.0.0 — Version initiale
NomaUBL est une plateforme e-invoicing Java 17 + React qui transforme les sorties ERP (JD Edwards, SAP, NetSuite, ERP personnalisé) en documents UBL 2.1 conformes, les valide, les soumet à une Plateforme Agréée (PA) française et trace l'intégralité du cycle de vie des factures.
Pipeline principal (ERP source → UBL → PA)
- Extraction du XML JDE depuis la file d'attente BIP (
F95630/F95631/F9563110), l'archive JDE, en SFTP ou depuis le système de fichiers local ; routage par template de type de document (invoices,credit_notes, …). - Transformation XSLT 2.0 via Saxon-HE — produit des factures et avoirs UBL 2.1 à partir d'un framework XSL configurable (
ubl-common.xsl+ubl-template.xsl). - Validation : XSD (UBL 2.1) + Schematron — EN 16931, BR-FR Flux 2 (CIUS-FR / FNFE-MPE) et BR-FR CPRO (Chorus Pro pour le B2G), avec gestion des sévérités (
fatal,error,warning,info). - Soumission PA en HTTP (Java 11
HttpClient), token OAuth2 mis en cache et auto-rafraîchi sur 401, plus un canal SFTP de secours. - Surcharges PA par société via les templates
e-invoicing-{kco}— credentials, endpoints et tokens indépendants par société émettrice. - Pré-vérification annuaire PPF (non bloquante) via le template
e-directory— recherche le client avant envoi et signale en avertissement les destinataires injoignables. - Génération PDF via Oracle BI Publisher (
oracle.xdo) avec post-traitement Ghostscript optionnel, et embarquement iText du PDF encac:AdditionalDocumentReferencedans l'UBL. - PA factice (
paUseMock=Y) avec scénarios succès / échec / token expiré pour les tests bout-en-bout sans plateforme réelle.
Stockage des documents, statuts et cycle de vie
Schéma Oracle / PostgreSQL (configurable dans db-nomaubl) :
| Table | Rôle |
|---|---|
F564230 | Archive source — XML JDE original, drapeaux de traitement |
F564231 | Entête UBL — champs BT-* EN 16931, XML UBL généré, statut courant |
F564233 | Lignes UBL |
F564234 | Synthèse TVA par catégorie / taux |
F564235 | Événements de cycle de vie (historique) |
F564236 | Erreurs de validation XSD / Schematron |
F564237 | Journal de traitement runtime (un événement START / END / erreur par ligne) |
F564250 / F564251 / F564252 | Utilisateurs / Rôles / Sessions |
- DDL adaptée au dialecte via
DatabaseDialect— Oracle (BLOB,NUMBER,VARCHAR2) et PostgreSQL (BYTEA,INTEGER,VARCHAR). - L'action Initialize Database dans Settings crée tout le schéma et provisionne les rôles
admin/viewerpar défaut. - Dates JDE Julian stockées en entiers (
CYYDDD - 1900000) et converties à la volée pour l'IHM.
Catalogue de statuts factures
- 30+ codes couvrant le cycle de vie complet AFNOR XP Z12-014 V1.3 :
STATUS_CREATED → STATUS_VALIDATED → STATUS_SENT_TO_PA → STATUS_PENDING → STATUS_DEPOSITED → …plus les états litige, factoring et erreurs de routage. - Codes workflow internes (
9900–9907) et codes UNTDID 1373 mappés à la PA (1,8,10,37,43,45–51). - Tous les codes / libellés / mappings PA sont pilotés par les données depuis le template système
statuses— éditables dans Settings. StatusTransition.apply()met à jourF564231et insère un événementF564235en un seul appel.
CLI
Modes interactifs et batch — tous pilotés par un unique config.json :
| Mode | Rôle |
|---|---|
-config | Ouvre l'IHM Swing (FlatLaf dark) |
-xml | Traite des fichiers XML JDE : SINGLE / BURST / UBL / AUTO |
-ubl | Valide + charge en base des fichiers UBL existants |
-fetch-single, -fetch-all | Récupère depuis BIP / archive / répertoire + traitement |
-fetch-import | Interroge la PA sur le statut des factures en attente (9906) |
-fetch-status | Récupère les événements de cycle de vie depuis la PA et met à jour la base |
-extract | Extrait les fichiers d'entrée / sortie d'un job BIP JDE |
-serve | Serveur HTTP embarqué + ordonnanceur d'arrière-plan |
-install | Provisionne l'arborescence d'un environnement |
-password | Encode un mot de passe pour stockage |
-updUser | Met à jour l'utilisateur JDE sur les jobs soumis |
IHM Web (React 19 + Vite)
- Dashboard avec compteurs de statuts, tuile d'erreurs d'intégration, actions rapides et infos licence / version.
- Factures — liste paginée + filtrable, modale de détail (Résumé, Parties, Lignes, TVA, Notes, Historique, PDF), création / édition / copie / renvoi en place, set-statut (PA ou DB seul), envoi e-mail avec PDF en pièce jointe.
- Erreurs d'intégration — toutes les lignes de validation
F564236sans facture associée (soumissions cassées). - Extract & Process — récupération unitaire et batch depuis BIP, FTP, archive ou fichiers locaux.
- Process UBL — chargement et validation d'UBL XML existants.
- Validate — testeur XSD + Schematron pour des fichiers UBL ad hoc.
- XSL Editor — éditeur Monaco avec navigateur XML, sélecteur de variables conscient du template et installeur de framework par template.
- XML Viewer — visualiseur / formatteur Monaco avec chargement local + serveur et sauvegarde.
- UBL Defaults — valeurs par défaut par société (devise, moyens de paiement, catégories TVA, etc.).
- Référentiel des statuts — référence complète AFNOR XP Z12-014 V1.3.
- Codes motifs — référence complète AFNOR XP Z12-012 Annexe A.
- Référentiel UBL — glossaire BT-*.
- Versions fichiers — historique des versions adossé à SQLite pour les fichiers XSL / XSD / Schematron / RTF / config éditables, avec upload / restauration / téléchargement.
Settings (gestionnaire de configuration)
- Édition à chaud de
config.jsondepuis le navigateur. Templates système :global,e-invoicing,e-directory,statuses,db-nomaubl,db-jde,ftp-jde,fetch-invoices. - Listes de codes :
invoice-types,vat-categories,vatex-codes,payment-means,scheme-ids,unit-codes,countries,note-types,currency-codes,rejection-reason-codes,action-codes,document-reference-codes,profile-ids. - Templates de type de document : par document RTF / XSL / clé de burst / routage / type de traitement.
- Templates de connecteurs API avec substitution de placeholders (
{{username}},{{token}},{{content}}, …) et auth pluggable (NONE,BASIC,BEARER,API_KEY,OAUTH2). - Surcharges par société
e-invoicing-{kco}.
Authentification & RBAC
- Tables intégrées utilisateur / rôle / session (
F564250–F564252). - Hashs PBKDF2-HMAC-SHA256, changement de mot de passe forcé à la première connexion, liste blanche de pages par rôle et filtre par société par rôle.
- Activable via
authEnableddansglobal(off → pas de login). - Rôles
admin(complet) etviewer(lecture seule restreinte) provisionnés par défaut au Initialize Database.
Ordonnanceur d'arrière-plan
Piloté depuis global.fetch*Interval (minutes — 0 désactive) :
fetchImportInterval— polling périodique du statut import PA.fetchStatusInterval— récupération périodique du cycle de vie PA.fetchAll.N.{interval,label,params}— plusieurs jobs batch de traitement de documents.
API HTTP embarquée
Un serveur REST + statique minimal (com.sun.net.httpserver) sert le bundle React sur / et expose /api/* pour les factures, templates, fetch / extract, validation, système de fichiers, licence, packaging, authentification, et la documentation OpenAPI sur /api/docs.
E-mail & i18n
- Envoi SMTP (TLS / SSL) avec PDF en pièce jointe par facture.
- Traductions français / anglais complètes dans toute l'IHM.
Licence
- Licences JWT signées RS256 vérifiées au runtime via une clé publique PEM embarquée — modes
full(toutes fonctionnalités) ourestricted(vues lecture seule).