---
suivi: 1350
date: 2026-08-14
sujet: synthese_financiere_programme
chantier: suivi_chantier
type: feat
statut: poussé
hash: a4837163
fichiers:
  - app/Services/MarcheSyntheseFinanciereService.php
  - app/Http/Controllers/ProgrammeSyntheseFinanciereController.php
  - app/Http/Controllers/SuiviChantierController.php
  - routes/web.php
  - resources/js/Components/Programmes/ProgrammeSyntheseFinanciere.vue
  - resources/js/Pages/SuiviChantier/Index.vue
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - public/build/
  - docs/suivi/SUIVI_1350_synthese_financiere_programme.md
---

## PROMPT ENVOYÉ

SUIVI #1350 — même écran que la synthèse marché, agrégé au programme.
Onglet Synthèse à droite de NF HABITAT. Sélection par marché (défaut
tous). Composition totaux + détail dépliable. Factures par marché
dépliables. Réutiliser pourMarche, pas de seconde formule. #1344
sur main. Clause 300 factures. Perf : mesurer ; si > 2 s proposer
SQL sans coder.

## FICHES LUES

- `SUIVI_1284` LEÇON : ne pas nommer le plafond « à comptabiliser » ;
  CIE soft-delete ops+répartitions. Conservé via pourMarche.
- `SUIVI_1287` LEÇON : ne pas recalculer en parallèle les cumuls
  retenues. Cartouches = sommes des totaux pourMarche.
- `SUIVI_1293` / `#1300` / `#1295` : définitions des 6 cartouches
  reprises telles quelles (somme, pas de 2e formule).
- `SUIVI_1343` / `SUIVI_1344` : MSFS::pourMarche lit désormais la
  reprise HT. #1344 est sur origin/main (2216a040) — héritage OK.
  Colonnes reprise déjà HT : pas de reconversion.
- `SUIVI_1342` / `#1347` / `#1349` : tableau marchés non touché.
- `SUIVI_1340` / `#1341` : non touchés. #1351 (refonte barre) : ici
  seulement AJOUT d’un onglet.

## SYNTHÈSE

### #1344

Déjà sur `origin/main`. `pourProgramme` appelle `pourMarche` → facture
et payé repris inclus. Sans ce lot l’écran serait faux à l’import SIWI ;
ce n’est plus le cas.

### Mapping sélecteur

| Libellé affiché | Valeur (état local) | Colonne DB | Libellé back |
|---|---|---|---|
| Réf. + fournisseur | `marche_id` coché | `marches.id` | id |
| Compteur N/M | `selectedIds.length` / `nb_marches` | — | — |
| Tout sélectionner | tous les ids | — | — |
| Tout désélectionner | `[]` | — | — |

Sélection non persistée, défaut = tous. Recalcul front = Σ des champs
déjà produits par `pourMarche`.

### Cartouches (mêmes clés que le marché)

| En-tête | Champ sommé | Sommée |
|---|---|---|
| Total facturé HT | `totaux.total_facture_ht` | O |
| Total payé HT | `totaux.total_paye_ht` | O |
| Factures en circuit | `totaux.total_en_circuit_ht` | O |
| Reste à payer | `totaux.reste_a_payer_ht` | O |
| Reste à payer + RG | `totaux.reste_a_payer_plus_rg_ht` | O |
| Reste à facturer | `totaux.reste_a_facturer_ht` | O |

Composition repliée : Σ `marche_initial_ht` · Σ `total_avenants_ht`
(une ligne) · Σ `montant_actualise_ht`. Pas de liste d’avenants.

### Route nouvelle

`GET /programmes/{programme}/synthese-financiere`
(`programmes.synthese-financiere.show`) — JSON, chargé à l’ouverture
de l’onglet (les autres onglets Chantier ne paient pas 36× pourMarche).

`GET .../synthese-financiere/marches/{marche}` si > 300 factures.

`route:clear` nécessaire au déploiement.

### Clause 300

Comptage `whereMarcheEffectifIn` hors archive. Si > 300 : totaux
toujours via pourMarche, historique omis du JSON, chargé au dépliage.

### Perf

Compteurs `perf.queries` / `perf.duration_ms` dans le JSON.
MySQL local 127.0.0.1:3306 refusé ; :3307 stub. Mesure réelle = à
coller depuis le pied de page en prod (programme 5).

Si > 2 s (proposition, non codée) : batch SQL unique pour dépôts /
CIE / reprise / libérations RG, puis réinjecter dans les mêmes
accumulateurs que pourMarche — jamais une 2e formule de reste.

### Hors périmètre respecté

Synthèse marché, `recalculer`, `getBilan`, `BilanFinancierService`,
4 KPI Marches/Index, AppShell, useFormatters, ObjectSubNavBar,
tableau marchés, documentPdf, siwi_import, commune : non touchés.

## DÉPLOIEMENT-TEST

```bash
git pull origin main
php artisan optimize:clear && php artisan view:clear
php artisan route:clear
php artisan journal:sync
```

Pas de migrate.

`/programmes/5/marches#synthese` (HERMIONE) :

1. Onglet Synthèse à droite de NF HABITAT.
2. Défaut 36/36. Noter les 6 cartouches, Σ initial / avenants /
   actualisé, ligne Totaux factures, perf (ms + requêtes).
3. Un seul marché MCH-2026-029 : chiffres = synthèse individuelle
   (actualisé 1 156 900,00 · RG 57 845,00 · réel 1 099 055,00 ·
   facturé 1 066 321,37 · payé 1 066 321,37 · reste 32 733,63 ·
   reste+RG 90 578,63 · reste à facturer 32 733,63). Tout écart =
   défaut d’agrégation.
4. Si accessible : marché 109 / MCH-2026-106 (ACP CLOISON).
5. Tout désélectionner → 0 €, pas NaN.
6. MCH-2026-042 à 0 € : pas de ligne fantôme / NaN.
7. Noter les écarts cartouches vs 4 KPI haut (onglet Marchés),
   sans corriger.

## LEÇON

Pour agréger un écran validé, sommer les payloads de la méthode
existante (pourMarche) plutôt que réécrire les formules. La sélection
client-side impose d’envoyer le détail par marché. Ne pas coller
ce calcul sur l’index Chantier (déjà lourd) : endpoint JSON lazy.
Les 4 KPI haut ne sont pas cette synthèse — afficher l’écart, ne
pas aligner.
