---
suivi: 1939
date: 2026-10-16
sujet: Diagnostic verrou comptabilisation facture électronique
chantier: factures-electroniques
type: diagnostic
statut: poussé
hash: 1dc67fb03
fichiers:
  - docs/suivi/SUIVI_1939_diag_verrou_compta_facture_electronique.md
---

# SUIVI #1939 — PHASE 1 diagnostic (aucun correctif)

Diagnostic uniquement. Aucun code métier modifié. Aucune migration. Aucun build.

## Fiches lues

- #1845 LEÇON : comptabilisation électronique bloquée « jusqu’au lot suivant » ; `MESSAGE_COMPTABILISATION` posé ; Sage lecture seule à l’import.
- #1853 LEÇON : vraie compta = `ExtBillUpdate` sur le brouillon existant ; interrupteur `FACTURES_ELECTRONIQUES_COMPTA_OUVERTE` ; admin seul si interrupteur fermé.
- #1847 LEÇON : création fournisseur Hectarion ≠ code Sage ; compta encore bloquée à l’époque.
- #1888 LEÇON : rattachement fournisseur sans inventer un code Sage.

Lecture #1853 : l’ouverture ne couvre que `executerComptabilisationApbill` (`autoriserCompta: true`) + `FactureElectroniqueComptaAcces`. Les autres appels à `reponseSiFactureElectroniqueBloquee` et le hard-abort de `validerEtComptabiliser` n’ont pas été reliés à l’interrupteur.

## PROMPT ENVOYÉ

PHASE 1 — diagnostic. Toast « Échec » avec `MESSAGE_COMPTABILISATION` alors que `config('erp.factures_electroniques_compta_ouverte') === true` en prod. Utilisatrice Sabrina hors `GS_ADMIN_ERP`. Vérifier usages du message, chemin du clic, interrupteur vs rôle, points d’entrée oubliés, git `#1853` / `-S MESSAGE_COMPTABILISATION`.

## 1. Usages de `MESSAGE_COMPTABILISATION`

Constante : `FactureElectroniqueImport.php:24` — texte « Comptabilisation des factures électroniques : disponible au prochain lot » (#1845, `2fa049b61`).

| Fichier:ligne | Condition | Lot |
|---|---|---|
| `FactureElectroniqueImport.php:24` | définition constante | #1845 |
| `ComptabilisationController.php:145-152` | `reponseSiFactureElectroniqueBloquee` : dépôt `facture_electronique` **et** `$autoriserCompta === false` (défaut) | #1845 ; param `$autoriserCompta` ajouté #1853 |
| `ComptabilisationController.php:671-672` | `envoyerIntacct` → bloquée sans `autoriserCompta` | #1845 |
| `ComptabilisationController.php:710-711` | `envoyerAvoirIntacct` → idem | #1845 |
| `ComptabilisationController.php:733-734` | `comptabiliser` (clôture locale sans Sage) → idem | #1845 |
| `ComptabilisationController.php:830-831` | `confirmerPaiementApresCompta` → idem (voulu #1853 : pas de paiement sur ce flux) | #1845 conservé |
| `DepotFactureController.php:2869-2870` | `validerEtComptabiliser` : `if ($depot->facture_electronique) abort(422, MESSAGE_COMPTABILISATION)` — **aucun** test interrupteur ni `GS_ADMIN_ERP` | #1845, **non touché par #1853** |
| `FactureElectroniqueImport1845Test.php:285` | assertion sur `POST …/envoyer-intacct` | #1845 |

Front : **aucune** occurrence du texte « disponible au prochain lot ». Texte voisin distinct : `DepotFactureSaisieActionBar.vue:181` — « … en cours de mise en route » (= `MESSAGE_MISE_EN_ROUTE` #1853), affiché si `factureElectronique && !peutComptabiliserFactureElectronique`.

## 2. Chemin réel du clic « Comptabiliser » (écran Comptabilisation)

1. `DepotFactureSaisieActionBar.vue` variant `compta` → emit `comptabiliser-seul` (bouton :label `comptaLabel`, désactivé si FE et `!peutComptabiliserFactureElectronique`).
2. `DepotFactureSaisieForm.vue:9048` `comptabiliserSeul()` → `POST /factures/comptabilisation/{uuid}/envoyer-intacct-compta`.
3. Route `factures.comptabilisation.envoyer-intacct-compta` → `ComptabilisationController::envoyerIntacctCompta` → `executerComptabilisationApbill(..., inclureApercuPaiement: false)`.
4. Dans ce flux (#1853) :
   - `reponseSiFactureElectroniqueBloquee($uuid, autoriserCompta: true)` → **ne renvoie pas** `MESSAGE_COMPTABILISATION` pour une FE ;
   - puis `FactureElectroniqueComptaAcces::autorise($user)` ; si refus → `MESSAGE_MISE_EN_ROUTE` (pas `MESSAGE_COMPTABILISATION`) ;
   - puis `envoyerDepotApbillEtPaiementIntacct` → `completerBrouillonElectronique` → `FactureElectroniqueComptabilisation` / `ExtBillUpdate`.

Toast de ce chemin en erreur : summary **« Comptabilisation »** (`DepotFactureSaisieForm.vue:9084-9088`), pas « Échec ».

## 3. Interrupteur et rôle `GS_ADMIN_ERP`

Lu via `FactureElectroniqueComptaAcces` (`FactureElectroniqueComptaAcces.php:14-34`) :

- `ouverte()` ← `config('erp.factures_electroniques_compta_ouverte')` ← env `FACTURES_ELECTRONIQUES_COMPTA_OUVERTE` (`config/erp.php:87`).
- `autoriseGroupes` : si ouverte → `true` pour tous ; sinon → uniquement `in_array('GS_ADMIN_ERP', $groupes, true)` (groupes bruts `m365GroupNames()`).

Branché sur : `ComptabilisationController::index` (prop Inertia `peutComptabiliserFactureElectronique`), `apercuEnvoiSage`, garde dans `executerComptabilisationApbill`, verrou cache dans `completerBrouillonElectronique` si interrupteur fermé.

**Le verrou #1845 (`MESSAGE_COMPTABILISATION`) ne lit ni l’interrupteur ni `GS_ADMIN_ERP`.** C’est un refus inconditionnel dès `facture_electronique`.

Front : pas de test `GS_ADMIN_ERP` en dur pour ce bouton. Il suit la prop `peutComptabiliserFactureElectronique` (= `FactureElectroniqueComptaAcces::autorise` côté index Comptabilisation). Si interrupteur true → prop true pour Sabrina (GS_COMPTABILITE) comme pour un admin.

Comportement attendu même chemin `#1853` (`envoyer-intacct-compta`) :

| Utilisateur | Interrupteur | Résultat |
|---|---|---|
| Sabrina (hors ADMIN_ERP) | true | autorisée |
| Sabrina | false | refus `MESSAGE_MISE_EN_ROUTE` + bouton désactivé |
| GS_ADMIN_ERP | false | autorisé (bypass) |
| GS_ADMIN_ERP | true | autorisé |

## 4. Points d’entrée — oubliés par #1853

| Entrée | Passe par ExtBillUpdate #1853 ? | Verrou |
|---|---|---|
| Bouton Comptabiliser (écran Comptabilisation) | oui | interrupteur / admin via `FactureElectroniqueComptaAcces` |
| Aperçu envoi Sage | aperçu seulement | idem |
| Comptabiliser et payer | `executerComptabilisationApbill` puis refus explicite paiement FE | — |
| `validerEtComptabiliser` (saisie dépôt, déjà réglée) | **non** | hard `MESSAGE_COMPTABILISATION`, ignore interrupteur **et** admin |
| `envoyerIntacct`, `comptabiliser` (legacy) | non | `MESSAGE_COMPTABILISATION` |
| `envoyerAvoirIntacct` | non | `MESSAGE_COMPTABILISATION` |
| `confirmerPaiementApresCompta` | non (paiement) | `MESSAGE_COMPTABILISATION` (conservé volontairement) |

Toast observé summary **« Échec »** + détail = `MESSAGE_COMPTABILISATION` : correspond à `DepotFactureSaisieForm.vue:4447-4449` (catch de `valider-et-comptabiliser`), **pas** au bouton Comptabiliser de l’écran Comptabilisation. Le bouton « Valider et Comptabiliser » n’est **pas** masqué pour une FE (`showValiderEtComptabiliser` ignore `facture_electronique`).

Si le toast venait vraiment du bouton Comptabiliser malgré le summary, ce chemin **ne peut plus** émettre `MESSAGE_COMPTABILISATION` dans le code actuel : à confirmer en PHASE 2 via l’URL réseau (`…/envoyer-intacct-compta` vs `…/valider-et-comptabiliser`).

## 5. Git

- `#1853` feat `54abbf8ae` + docs `e3d221d11` : bien ancêtres de `origin/main`.
- `git log -S "MESSAGE_COMPTABILISATION"` : seulement `2fa049b61` (#1845, introduction) et `54abbf8ae` (#1853, assouplit `reponseSiFactureElectroniqueBloquee` pour `autoriserCompta`). Aucun lot postérieur n’a réintroduit le verrou ; `DepotFactureController::validerEtComptabiliser` n’a jamais été assoupli.

## Cause racine

Deux mécanismes coexistent :

1. **Accès #1853** (`FactureElectroniqueComptaAcces`) : respecte l’interrupteur ; si ouvert, Sabrina doit passer sur `envoyer-intacct-compta`.
2. **Verrou #1845** (`MESSAGE_COMPTABILISATION`) : encore actif sur des entrées non migrées, surtout `validerEtComptabiliser`, **sans** tenir compte de l’interrupteur ni du rôle. Ce n’est pas un test `GS_ADMIN_ERP` manquant sur ce verrou : c’est un refus absolu. Un admin ERP échoue aussi sur ce raccourci.

Le symptôme (texte exact `MESSAGE_COMPTABILISATION` + toast « Échec », interrupteur true, non-admin) s’explique par le hard-abort #1845 encore vivant, pas par un faux négatif de l’interrupteur sur le flux ExtBillUpdate.

## Correctif proposé (PHASE 2) — ne pas faire ici

Fichiers touchés (prévision) :

- `DepotFactureController.php` — `validerEtComptabiliser` : ne plus renvoyer `MESSAGE_COMPTABILISATION` inconditionnel ; soit refuser avec message orientant vers l’écran Comptabilisation + ExtBillUpdate, soit (si métier OK) ne faire que la promotion workflow **sans** créer de bill, puis laisser l’envoi Sage au flux #1853.
- `DepotFactureSaisieForm.vue` / `DepotFactureSaisieActionBar.vue` — masquer / désactiver « Valider et Comptabiliser » si `facture_electronique`.
- `ComptabilisationController.php` — remplacer `MESSAGE_COMPTABILISATION` sur les entrées legacy encore utiles par des messages métier explicites (avoir / paiement) ; ne pas rouvrir un second bill.
- Tests #1845 / #1853 : ajuster l’assertion `envoyer-intacct` et couvrir `valider-et-comptabiliser` FE + interrupteur ouvert / fermé / admin.

Ne change pas : règles ExtBillUpdate, contrôle centime TTC XML ↔ TOTALENTERED, refus fournisseur sans code Sage, sens de `montant_ht`, verrou CIE, création fournisseur Sage.

## Risques compta et tests manuels prod (PHASE 2)

Risques : rouvrir un raccourci qui créerait un second bill ; laisser un admin croire que le raccourci « Valider et Comptabiliser » soumet Sage.

Tests : petite FE (interrupteur true) en tant que GS_COMPTABILITE — bouton Comptabiliser + aperçu Sage ; vérifier un seul RECORDNO (pas de second bill) ; même scénario GS_ADMIN_ERP ; tenter « Valider et Comptabiliser » sur FE et confirmer le comportement choisi ; FE sans code Sage → refus explicite.

## DÉPLOIEMENT-TEST

Aucun déploiement applicatif (fiche seule). OVH : rien.

## LEÇON

`MESSAGE_COMPTABILISATION` (#1845) et `MESSAGE_MISE_EN_ROUTE` / `FactureElectroniqueComptaAcces` (#1853) sont deux portes distinctes. Ouvrir l’interrupteur ne désarme pas les `abort` / `reponseSiFactureElectroniqueBloquee` restés sans `autoriserCompta`. Le toast summary « Échec » pointe le raccourci `valider-et-comptabiliser`, pas le POST `envoyer-intacct-compta`. Un non-admin avec interrupteur true doit passer le flux ExtBillUpdate ; un admin échoue quand même sur le hard-abort #1845 du raccourci.
