---
suivi: 1836
date: 2026-10-09
sujet: Inspection lecture seule des factures Sage
chantier: factures-electroniques
type: outil
statut: poussé
hash: 3766ca9a9
fichiers:
  - app/Http/Controllers/Admin/IntacctInspectionBillsController.php
  - app/Services/Intacct/ApbillInspectionService.php
  - app/Services/Intacct/ApbillChampFacturationElectronique.php
  - app/Services/Intacct/FactureElectroniqueXmlLecteur.php
  - app/Services/Intacct/IntacctLectureSeule.php
  - app/Services/IntacctService.php
  - routes/web.php
  - resources/js/Pages/Admin/Intacct/InspectionBills.vue
  - resources/js/Pages/Admin/Index.vue
  - resources/js/titresOnglet.js
  - tests/Feature/Admin/IntacctInspectionBillsAccessTest.php
  - tests/Unit/Intacct/ApbillProbeRecordNos1836Test.php
  - tests/Unit/Intacct/FactureElectroniqueXmlLecteurTest.php
  - tests/Unit/Intacct/IntacctLectureSeuleTest.php
  - tests/fixtures/facture-electronique/factur-x.xml
  - tests/fixtures/facture-electronique/ubl.xml
  - tests/fixtures/facture-electronique/cii.xml
  - public/build/manifest.json
  - public/build/assets/InspectionBills-BQ46YKzG.js
  - docs/suivi/SUIVI_1836_inspection_bills_fe.md
---

# SUIVI #1836 — inspection lecture seule des factures Sage

## PROMPT ENVOYÉ

Outil DSI de lecture seule pour inspecter des bills Sage (en-tête complet, lignes, pièces jointes, définition APBILL) et corriger la sonde `probe-apbill-states` afin qu'elle traite tous les RECORDNO. Exemples : E-04 / 2660507, 2660206, 2659930.

## Fiches lues

Aucune fiche `docs/suivi` ne décrit les champs API de la facturation électronique ni le diagnostic #1833 (fichier absent). #1570 et #1613 décrivent le patron de sonde web et `lireXmlSeule`. Elles n'ont pas changé le périmètre : pas d'écriture Sage, pas de circuit de dépôt, de comptabilisation ou de paiement.

## SYNTHÈSE

L'écran `/admin/intacct/inspection-bills` est réservé à `GS_DSI` lu par `m365GroupNames()` brut. Le middleware laisse passer `GS_ADMIN_ERP` ; le contrôleur renvoie 403. Un lien apparaît dans Administration, onglet Comptabilité, seulement si le groupe brut contient `GS_DSI`.

La lecture passe par `lireXmlSeule` (refus de create, update, delete, reverse). Le délai d'un appel d'inspection est de 30 secondes. Une facture en erreur n'empêche pas les suivantes. Les brouillons (`STATE = Draft`) sont au plus 50, triés par date de création décroissante quand Sage l'accepte.

Pour chaque facture : tous les champs d'en-tête, les lignes, le `SUPDOCID` et les fichiers (nom, type, taille). Le téléchargement relit Sage et renvoie le fichier au navigateur, sans écriture disque. Un XML est classé Factur-X, UBL ou CII, avec le numéro (BT-1), la date (BT-2), le HT (BT-109), la TVA (BT-110), le TTC (BT-112) et le SIRET vendeur (schéma 0009). Le bouton « Copier en JSON » reprend le résultat, sans le contenu des fichiers. Le journal technique note les identifiants, les noms et les tailles, pas les octets.

La définition APBILL (lookup et inspect) liste le type, les valeurs possibles, les champs personnalisés et ceux de la facturation électronique. Les champs dont le libellé, le nom ou les valeurs possibles évoquent le type « Facture électronique » ou le statut (mise à disposition, litigieux, refusé) sont en tête.

### Sonde — cause

`probeApBillsByRecordNos` ne gardait que la première ligne (`pickFirstApBillRowFromQueryResponse`). Une erreur Sage sur l'appel suivant (`throwIfIntacctError` dans `sendComptabilisationRequest`) sortait de la boucle, et `probeApbillStates` répondait 500 sans les factures déjà lues. Chaque RECORDNO est maintenant un `<read><keys>` distinct. Si la réponse contient plusieurs factures, on retient celle dont le RECORDNO est celui demandé. L'erreur d'un numéro reste sur ce numéro.

### Mapping

| Libellé | Valeur postée | Usage | Lecture |
|---|---|---|---|
| Entité | `location_id` | session Sage | `lireXmlSeule(..., locationId)` |
| RECORDNO | `recordnos` | un ou plusieurs numéros | `<read><keys>` APBILL |
| Lister les brouillons | `brouillons=1` | `STATE = Draft`, 50 max | `<query>` trié, sinon `readByQuery` |

### Journal

Pas d'entrée. L'écran est un outil DSI. Le journal métier ne décrit pas ces écrans.

## DÉPLOIEMENT-TEST

`git pull origin main` puis `php artisan optimize:clear`, `view:clear`, `route:clear`. Pas de migration.

1. Compte sans `GS_DSI`, y compris un administrateur : `/admin/intacct/inspection-bills` répond 403.
2. Compte `GS_DSI` : entité E-04, RECORDNO `2660507`, `2660206`, `2659930`. Le type et le statut de facturation électronique montrent leur nom technique et leurs valeurs possibles.
3. `probe-apbill-states?entity=E-04&recordno=2660507,2660506` renvoie deux entrées.
4. Télécharger une pièce ne laisse pas de fichier sous `storage`.

## LEÇON

Ne pas regrouper plusieurs RECORDNO dans un seul `<keys>`, et ne pas garder seulement la première ligne. Une erreur Sage sur une facture ne doit pas répondre 500 en jetant les autres. `lireXmlSeule` refuse les écritures ; `<query>` et `<readMore>` sont des lectures. Aucun octet de pièce jointe dans le JSON ni dans le journal. Le droit DSI se lit sur `m365GroupNames()`, pas via `isAdminERP()`.
