---
suivi: 1945
date: 2026-10-16
sujet: Diag Comptabilisation FE — compte bancaire, établissement, prépayé
chantier: factures-electroniques / comptabilisation
type: diagnostic
statut: poussé
hash: 1ff693594
fichiers:
  - resources/js/Pages/DepotFactures/DepotFactureSaisieForm.vue
  - resources/js/Components/DepotFactures/DepotFactureSaisieActionBar.vue
  - resources/js/Pages/Factures/Comptabilisation/Index.vue
  - app/Http/Controllers/ComptabilisationController.php
  - app/Http/Controllers/DepotFactureController.php
  - app/Support/ComptabilisationBankCompteOptions.php
  - app/Support/ProgrammeSaisieSelectPresenter.php
  - app/Support/LigneComptableEtablissementResolver.php
---

# SUIVI #1945 — diagnostic Comptabilisation FE (compte bancaire / établissement / prépayé)

## Fiches lues

- #1853 LEÇON : ExtBillUpdate complète le brouillon, jamais de second bill, jamais de paiement à la compta.
- #1942 / #1941 LEÇON : « Valider et Comptabiliser » = mise en file seulement ; envoi Sage = bouton Comptabiliser page Comptabilisation.
- #1940 LEÇON : FE ne paie jamais à la compta ; `deja_reglee` neutralisé.
- #1759 LEÇON : paramètres bancaires programme = `financial_entity_id` / intacct_id affiché.
- #1847 : prépayé / reste à payer lus du XML et affichés ; `deja_reglee` non coché à l’import.

Aucune de ces fiches ne traite l’obligation établissement « hors programme » ni le préremplissage bloqué par options Select.

## PROMPT ENVOYÉ

PHASE 1 diagnostic uniquement. FE BECM F4050, E-04 HECTARE, programme HEC31-003, 58,26 € prépayés (reste 0). Constats : compte bancaire vide, établissement obligatoire, bouton Comptabiliser grisé, Net à payer 58,26 €. Règles Robin : compte programme prérempli ; établissement non obligatoire si programme. Comparer classique vs FE ; bouton front/back ; source liste comptes ; 512433 ; prépayé vs envoi Sage. Proposition PHASE 2 sans coder.

## SYNTHÈSE

Même écran pour classique et FE : `Comptabilisation/Index.vue` charge `DepotFactureSaisieForm` en `comptabilisationMode`. Le préremplissage bancaire et l’obligation d’établissement sont 100 % dans ce formulaire + les mêmes contrôles back. La FE n’a pas de chemin UI distinct sur ces deux champs ; la différence vient de l’import (pas de compte / établissement / programme en saisie initiale) et du gating interrupteur #1853.

### 1. Facture CLASSIQUE rattachée à un programme

| Sujet | Comportement | Fichier:ligne |
| --- | --- | --- |
| Préremplissage compte | Oui, côté front seulement, quand `programme_id` est posé et que le compte du programme figure dans les options du Select | `DepotFactureSaisieForm.vue:3524-3533` watch ; `:3346-3390` `appliquerSuggestionCompteBancaireDepuisProgramme` |
| Source compte programme | Cascade : `financial_entity_intacct_id` → `compte_bancaire_intacct_id` (legacy) → `accountno_gl_512` → heuristique | Presenter `ProgrammeSaisieSelectPresenter.php:53-57` ; colonne active `programmes.financial_entity_id` |
| Repli société | E-04→512900 / E-13→512901 **seulement s’il n’y a pas de programme** | `DepotFactureSaisieForm.vue:3392-3411` (sortie si `programme_id` renseigné) |
| Établissement obligatoire | Critère = société HECTARE (`E-04`), **pas** « avec / sans programme » | Front `:1200-1224` ; back `ComptabilisationController.php:448-463` + `LigneComptableEtablissementResolver` |

Donc une classique programme HECTARE a le compte prérempli **si** le paramétrage programme + référentiel + jointure GL permettent de trouver une option ; l’établissement reste obligatoire (HECTARE), contrairement à la règle Robin « non obligatoire pour un programme ».

### 2. Facture ÉLECTRONIQUE (chemin #1853)

| Sujet | Différence vs classique | Cause |
| --- | --- | --- |
| Chargement page | Même `GET …/comptabilisation/{uuid}/data` → même formulaire | `Comptabilisation/Index.vue` + `ComptabilisationController::data` |
| Saisie initiale FE | Import sans `compte_bancaire_id` / `etablissement_id` / souvent sans programme en saisie ; `deja_reglee` forcé false | Import #1845/#1847 ; rattaché programme ensuite à l’écran |
| Préremplissage | Même fonction que le classique dès que `programme_id` est posé | Identique `:3346-3390` |
| Bouton | En plus : grisé si FE et `!peutComptabiliserFactureElectronique` (interrupteur) | `DepotFactureSaisieActionBar.vue:223` |
| Envoi Sage | `ExtBillUpdate` / `completerBrouillonElectronique` ; `'payment' => null` | `ComptabilisationController.php:1590`, `:2200`, `:2297` |

Pas de logique FE spécifique qui vide le compte ou force l’établissement : si le compte est vide, c’est le même échec de cascade / options que pour une classique.

### 3. Bouton « Comptabiliser » — conditions exactes

**Front — désactivation** (`DepotFactureSaisieActionBar.vue:223`) :

`disabled` si l’un de : `acompteSageIndisponible` | `!comptaSecondaryActionsEnabled` | `comptaBusyDisabled` | (FE && !peutComptabiliserFactureElectronique).

`comptaSecondaryActionsEnabled` exige `comptaChampsPretPourActions` (`DepotFactureSaisieForm.vue:4232-4267`) :

1. `entite_id` renseigné
2. Si HECTARE : `form.etablissement_id` global renseigné (**pas** l’établissement par ligne — écart avec le toast/back)
3. `analytics_id`
4. Si `deja_reglee` (classique) : date + mode direct
5. `mode_reglement`
6. `compte_bancaire_id`
7. Aucune ligne sans compte
8. Multi-fournisseur : ventilation HT équilibrée

**Back — refus** (`ComptabilisationController::reponseSiComptaNonPretPourAction`, `:382-496`) : équilibre débit/crédit ; société ; Analytics ; mode règlement ; **compte bancaire** ; établissement HECTARE **par ligne** ; ventilation multi-fournisseur ; historique ; déjà réglée (date/mode). Puis contrôles FE propres (brouillon, fournisseur Sage, centime TTC).

Pour le cas BECM : bouton grisé très probablement par (2) établissement global vide et/ou (6) compte bancaire vide, éventuellement interrupteur FE.

### 4. Liste « Compte bancaire » et 512433

Source des options (pas la liste Sage brute) :

1. `intacct_financial_entities` type `bank_account` status actif (`PaiementReferentielOptions`)
2. Filtre société via `location_id` / établissements (`PaiementFinancialEntitySocieteFilter`)
3. Jointure obligatoire `comptes_comptables` actifs avec `accountno = BANKACCOUNTID` (`ComptabilisationBankCompteOptions.php:31-45`) — **sans ligne GL, l’option disparaît sans erreur**

Le préremplissage ne pose une valeur que si elle est trouvée **dans** `comptesPaiementOptions` (sauf heuristique finale, qui peut être invalidée ensuite par le watch société `:3559-3566`).

Programme HEC31-003 : compte attendu = `programmes.financial_entity_id` → `intacct_financial_entities.intacct_id`. Non vérifiable ici (pas de MySQL prod). Requêtes lecture seule ci-dessous.

### 5. FE prépayée — compte / mode / Net à payer

| Élément | Nécessaire à l’envoi Sage ? | Remarque |
| --- | --- | --- |
| Compte bancaire | Exigé front + back **mais non envoyé** à Sage à la compta | Spec APBILL / ExtBillUpdate : `payment => null`. Conservé en `ocr_raw.saisie` pour le volet Paiement ultérieur |
| Mode de règlement | Idem (obligatoire saisie ; défaut Virement pour FE) | Pas dans le payload ExtBillUpdate de paiement |
| Bandeau prépayé | Affichage seul (`montant_prepaye` / `montant_payable` XML) | `DepotFactureSaisieForm.vue:393-403`, `:9397` |
| « Net à payer fournisseur » | Affichage depuis lignes 401 / TTC − retenues | `:4210-4215` — **ignore** prépayé / reste 0 → 58,26 € affiché alors que reste à payer = 0 ; **non envoyé** comme champ paiement Sage |

Cohérence : contradiction d’affichage seulement à ce stade ; l’envoi #1853 ne paie pas. Risque ultérieur : mise en paiement qui ne relirait pas `montant_payable` (hors périmètre strict de ce diag, à traiter en PHASE 2 si confirmé).

## Causes probables (ordre)

1. Compte programme absent ou inactif / sans jointure `comptes_comptables` (ex. 512433) → options sans ce compte → pas de préremplissage + champ vide + bouton grisé.
2. Établissement obligatoire car E-04 HECTARE (code en dur), indépendamment du programme — écart règle Robin.
3. Net 58,26 € = synthèse écritures, pas le reste XML.

## Requêtes de contrôle prod (lecture seule)

A — Compte du programme HEC31-003 :

    SELECT p.id, p.code_envol, p.libelle, e.intacct_id AS societe,
           p.financial_entity_id, fe.intacct_id AS bank_id, fe.name, fe.type, fe.status, fe.location_id,
           p.compte_bancaire_intacct_id, cc.accountno AS legacy_gl
    FROM programmes p
    LEFT JOIN entites e ON e.id = p.entite_id
    LEFT JOIN intacct_financial_entities fe ON fe.id = p.financial_entity_id
    LEFT JOIN comptes_comptables cc ON cc.id = p.compte_bancaire_intacct_id
    WHERE p.code_envol = 'HEC31-003';

B — 512433 dans le référentiel financial entities :

    SELECT id, type, intacct_id, name, status, location_id, gl_account_no, bank_account_no
    FROM intacct_financial_entities
    WHERE TRIM(intacct_id) = '512433'
       OR TRIM(COALESCE(gl_account_no,'')) = '512433'
       OR TRIM(COALESCE(bank_account_no,'')) = '512433';

C — 512433 dans comptes_comptables (jointure du Select) :

    SELECT id, accountno, titre, type_compte, statut
    FROM comptes_comptables
    WHERE UPPER(TRIM(accountno)) = '512433';

D — Options Select simulées pour E-04 (compte visible ?) :

    SELECT fe.intacct_id, fe.name, fe.location_id, cc.id AS compte_comptable_id
    FROM intacct_financial_entities fe
    LEFT JOIN etablissements et ON et.location_id = fe.location_id AND et.statut = 'active'
    LEFT JOIN comptes_comptables cc ON UPPER(TRIM(cc.accountno)) = UPPER(TRIM(fe.intacct_id)) AND cc.statut = 'active'
    WHERE fe.type = 'bank_account' AND LOWER(COALESCE(fe.status,'')) = 'active'
      AND (UPPER(fe.location_id) = 'E-04' OR UPPER(et.parent_id) = 'E-04')
    ORDER BY fe.intacct_id;

E — Dépôt F4050 / prépayé / saisie :

    SELECT d.id, d.uuid, d.numero_facture, d.facture_electronique, d.statut,
           d.montant_ttc, d.montant_prepaye, d.montant_payable, d.deja_reglee,
           JSON_UNQUOTE(JSON_EXTRACT(d.ocr_raw,'$.saisie.compte_bancaire_id')) AS saisie_compte,
           JSON_UNQUOTE(JSON_EXTRACT(d.ocr_raw,'$.saisie.etablissement_id')) AS saisie_etab,
           JSON_UNQUOTE(JSON_EXTRACT(d.ocr_raw,'$.saisie.programme_id')) AS saisie_prog
    FROM depot_factures d
    WHERE d.numero_facture LIKE '%F4050%' OR d.numero_facture LIKE '%BECM%'
    ORDER BY d.id DESC LIMIT 10;

## Proposition PHASE 2 (à décrire, pas coder)

Périmètre : **toutes les factures de programme** (classique + FE) pour préremplissage et établissement ; règles prépayé surtout FE (XML).

| # | Correctif | Fichiers | Risque | Tests |
| --- | --- | --- | --- | --- |
| P2-1 | Établissement **facultatif** si destination/programme renseigné (alignement règle Robin), tout en gardant le contrôle de cohérence société ↔ LOCATIONID ligne si un établissement est saisi | `DepotFactureSaisieForm.vue` (`etablissementRequisComptabilisation`, `comptaChampsPretPourActions`, validate) ; `ComptabilisationController::reponseSiComptaNonPretPourAction` ; `LigneComptableEtablissementResolver` ; PATCH Enregistrer | LOCATIONID manquant côté Sage si le métier en a encore besoin sur certaines lignes HECTARE | Classique programme HECTARE sans établissement → Comptabiliser OK ; hors programme HECTARE → toujours requis ; FE programme idem |
| P2-2 | Garantir préremplissage compte depuis `programmes.financial_entity_id` : si FE absente des options, signaler (compte inactif / sans GL) plutôt que champ vide silencieux ; éventuellement assouplir la jointure GL ou sync `erp:sync-comptes-banques-comptables` | `ComptabilisationBankCompteOptions.php` ; évent. sync ; Form suggestion | Option orpheline / id hors Select | HEC31-003 avec FE paramétré → Select prérempli ; 512433 sans `comptes_comptables` → message explicite |
| P2-3 | FE prépayée (`montant_payable = 0` ou prépayé > 0) : **ne plus exiger** compte bancaire ni mode pour activer Comptabiliser / back `reponseSiComptaNonPretPourAction` (ils ne partent pas à Sage). Conserver saisie optionnelle pour le volet Paiement | Form `:4232+` ; `ComptabilisationController.php:435-446` | Régression si une FE « prépayée » doit quand même être payée partiellement plus tard | FE reste 0 → bouton actif sans compte ; FE non prépayée → inchangé ; classique deja_reglee inchangé |
| P2-4 | Affichage Retenues : Net à payer = reste XML si FE prépayée (ou libellé distinct « Reste à payer ») | `DepotFactureSaisieForm.vue` `netAPayerTtcAffiche` / bandeau | Confusion si retenues CIE + prépayé | F4050 → Net 0,00 € (ou libellé clair) ; non prépayée → comportement actuel |
| P2-5 | Aligner bouton (établissement global) et validate/back (établissement par ligne) | Form `:4239` vs `:1265` | Bouton grisé à tort | Établissement ligne seule → bouton actif |

**Garde-fous PHASE 2** : jamais second bill ; contrôle centime TTC XML = TOTALENTERED ; `montant_ht` inchangé ; payé confirmé ne recule pas ; paiement FE uniquement volet Paiement ; verrou CIE / `cie_effacement_confirme` intact dans le bundle.

**Hors PHASE 2 immédiat** : logique métier du volet Paiement pour `montant_payable` (à ouvrir en lot suivant si les requêtes E confirment un risque de proposé à tort).

## DÉPLOIEMENT-TEST

Diagnostic seul : `git pull origin main`. Pas de migrate, pas de build, pas de `journal:sync`.

Contrôles : exécuter les SELECT A–E en prod ; croiser avec F4050 à l’écran (compte vide, * établissement, Net 58,26).

## LEÇON

L’obligation d’établissement est branchée sur la société HECTARE (`E-04` en dur), pas sur « facture de programme ». Le préremplissage bancaire dépend d’une jointure silencieuse `intacct_financial_entities` × `comptes_comptables` : un compte Sage connu (512433) mais sans ligne GL active n’apparaît ni dans le Select ni dans la suggestion. Le prépayé XML n’alimente que le bandeau ; le Net à payer et les contrôles compte/mode restent ceux d’une facture « à payer ».
