---
suivi: 1643
date: 2026-09-22
sujet: Étude financière du scénario en un seul tableau continu
chantier: Foncier / Faisabilité
type: refonte-affichage
statut: poussé
hash: 15c55ff1
fichiers:
  - resources/js/Pages/Foncier/Scenarios/Show.vue
  - tests/Unit/ScenarioEtudeFiTableauContinu1643SourceTest.php
  - tests/Unit/ScenarioBarreKpiEtUnites1640SourceTest.php
  - tests/Unit/FaisabiliteSaisieTableur1636SourceTest.php
  - tests/Unit/ScenarioHautDePageCompact1641SourceTest.php
  - tests/Unit/ScenarioGrilleTableur1642SourceTest.php
  - tests/Unit/Foncier/FoncierScenarioEtudeFi1139SourceTest.php
  - database/data/journal_mises_a_jour_post_2026_06_12.php
---

# PROMPT ENVOYÉ

Troisième et dernier lot de refonte de `/foncier/scenarios/{id}`. Ne traite QUE la
section ÉTUDE FINANCIÈRE : un seul tableau continu (plus aucun dépliage), six colonnes
fixes (# / Poste / Unité / Saisie / Nombre / Formule / Montant HT), bande de KPI de
30 px, aides dans des « ? ». Aucun calcul modifié. Les quatre totaux de contrôle
doivent rester identiques au centime. Inventaire des 26 codes repris tel quel du #1640.

# SYNTHÈSE

Lot d’affichage. Le moteur, `ScenarioEtudeFiService`, `EtudeFiSaisies` et les routes
sont intouchés. Aucune valeur nouvelle n’a été ajoutée au payload : pastilles, formules
et taux résolus du #1640 sont réutilisés (`uniteSaisiePoste`, `formuleSaisiePoste`,
`REGLES_CALCULEES`, `etude_financiere.regles`).

## Structure du tableau

Un seul `<table>` (`border-collapse`, `table-fixed`, `w-full`). Chaque section du
payload devient une ligne de séparation bleutée de 26 px (nom en capitales à gauche,
sous-total moteur à droite). Les postes suivent immédiatement, hauteur 27 px, bordures
1 px jointives, gouttière de numéros à gauche (numérotation continue, distincte de
toute saisie). Plus de `etudeOuvertes` / bouton de dépliage.

Colonnes : `#` | Poste | Unité de saisie | Saisie | Nombre | Formule appliquée | Montant HT.

- Unité : pastille #1640, ou badge gris « calculé » si le moteur n’en expose pas.
- Saisie : `InputNumber` sans bordure propre (`CELL_INPUT_NUM` du #1642). Fond gris
  et lecture seule pour les postes calculés et pour un scénario gelé.
- Nombre : `poste.quantite` grisé (lots TOTAL ou HECTARE selon le moteur) ; seule
  case éditable = `vrd_compteurs_nombre`.
- Formule : valeurs réelles du scénario (`poste.unitaire`, `poste.quantite`, taux
  résolus). Le montant n’y figure plus — il est dans la dernière colonne.
- Montant HT : `poste.montant` tel que reçu (`resultatPoste`), ou `fmtPct` pour les
  codes `pct_`.

## Bande de KPI et aides

Les quatre tuiles deviennent une bande de 30 px (Total recettes, Prix de revient,
Bénéfice brut teinté `#EFF6FF`, Résultat consolidé teinté `emerald-50`). L’alerte
« Écart contrôle prix de revient » ne s’affiche que si ≠ 0. Le paragraphe d’intro
et la note frais bancaires passent dans des `HelpHint`. L’import Excel est inchangé.

## Hauteurs mesurées (même scénario, 54 postes + 8 sections)

Calculées sur le CSS réel, pas au pixel près d’un navigateur.

| État | Avant | Après |
|---|---|---|
| Tout ouvert (l’état « imbuvable » décrit par Robin) | **~ 3 500 px** (tuiles + 8 en-têtes de carte + lignes 40–68 px avec libellé d’unité en petites capitales) | **~ 1 780 px** (bande 30 + thead 27 + 8 × 26 + 54 × 27 + légende) |
| Défaut d’ouverture (3 premières sections) | **~ 1 200 px** mais Travaux VRD masqué | **~ 1 780 px**, tout visible d’emblée |

Gain à contenu égal (tout visible) : environ **1 720 px** rendus, soit près de la moitié.

## PHP

Aucun fichier PHP modifié. `ScenarioEtudeFiService` n’a reçu aucun champ nouveau.

## Fiches lues

- #1640 LEÇON + inventaire : pastilles et `regles` déjà dans le payload ; ne pas
  réinventer `impots_fonciers` (laissé sans pastille, badge « calculé »).
- #1642 LEÇON : `outline` négatif, `CELL_INPUT` / `CELL_*`, tests sans commentaires.
- #1641 LEÇON : filtre `Faisabilite|Scenario` ; ancre `scenario-section-etude` conservée.
- #1636 LEÇON : natures déjà étiquetées par le moteur ; navigation bornée à la table.

# TABLEAU DE MAPPING

Inventaire #1640 + colonne « pastille dans le nouveau tableau ». `moteur` =
`FaisabiliteLotissementMoteur.php`.

## Recettes (moteur:350-362) — toutes CALCULÉES

| Libellé | Code | Saisi / calculé | Pastille tableau | Multiplicateur | Source |
|---|---|---|---|---|---|
| Nombre de lots Hectare | `nb_lots_hectare` | calculé | calculé (gris) | — | moteur:354 |
| Nombre de lots ODF | `nb_lots_odf` | calculé | calculé (gris) | — | moteur:355 |
| Nombre de lots total | `nb_lots_total` | calculé | calculé (gris) | — | moteur:356 / 189 |
| Recettes lots Hectare TTC | `recettes_lots_hectare_ttc` | calculé | calculé (gris) | — | moteur:357 / 193 |
| Recettes ODF HT | `recettes_odf_ht` | calculé | calculé (gris) | — | moteur:358 / 194 |

## Achat (moteur:363-375)

| Libellé | Code | Saisi / calculé | Pastille tableau | Multiplicateur | Source |
|---|---|---|---|---|---|
| Coût d’achat foncier HT | `cout_achat_foncier_ht` | calculé | calculé (gris) | — | moteur:367 |
| Coût viabilité ODF TTC | `cout_viabilite_odf_ttc` | calculé | calculé (gris) | — | moteur:368 |
| Frais de notaire | `frais_notaire` | calculé | calculé (gris) | — | moteur:369 |
| Commission apporteur HT | `commission_apporteur_ht` | saisi | € HT (montant total) | aucun | moteur:370 / 198 |
| Honoraires de montage HT | `honoraires_montage_ht` | calculé | calculé (gris) | — | moteur:371 |

## Taxes (moteur:376-385)

| Libellé | Code | Saisi / calculé | Pastille tableau | Multiplicateur | Source |
|---|---|---|---|---|---|
| Taxes ZAC / PUP / PAE HT | `taxes_zac_pup_pae_ht` | saisi | € HT (montant total) | aucun | moteur:380 / 208 |
| Taxes diverses HT | `taxes_diverses_ht` | saisi | € HT (montant total) | aucun | moteur:381 / 208 |

## Travaux VRD (moteur:386-411)

| Libellé | Code | Saisi / calculé | Pastille tableau | Multiplicateur | Source |
|---|---|---|---|---|---|
| LOT 1 Terrassement | `vrd_terrassement_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:390 / 211 |
| LOT 2 Réseaux Humides | `vrd_reseaux_humides_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:391 / 212 |
| LOT 3 Réseaux Secs | `vrd_reseaux_secs_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:392 / 213 |
| LOT 4 Espaces Verts | `vrd_espaces_verts_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:393 / 214 |
| Compteurs supplémentaires | `vrd_compteurs_montant_unitaire` × `vrd_compteurs_nombre` | saisi × saisi | € / unité × nombre | nombre saisi | moteur:394-400 / 215 |
| Imprévus travaux | `vrd_imprevus_travaux` | calculé | X % des LOTS 1 à 4 (taux résolu) | paramètre scénario | moteur:401 / 216-218 |
| Travaux divers | `vrd_travaux_divers` | saisi | € HT (montant total) | aucun | moteur:402 |
| Fouilles archéologiques | `vrd_fouilles_archeologiques` | saisi | € HT (montant total) | aucun | moteur:403 |
| Démolition | `vrd_demolition` | saisi | € HT (montant total) | aucun | moteur:404 |
| ERDF | `vrd_erdf` | saisi | € HT (montant total) | aucun | moteur:405 |
| Divers 1 | `vrd_divers_1` | saisi | € HT (montant total) | aucun | moteur:406 |
| Divers 2 | `vrd_divers_2` | saisi | € HT (montant total) | aucun | moteur:407 |

## Honoraires externes (moteur:412-430)

| Libellé | Code | Saisi / calculé | Pastille tableau | Multiplicateur | Source |
|---|---|---|---|---|---|
| Géomètre | `ext_geometre_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:416 / 235 |
| Architecte | `ext_architecte_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:417 / 236 |
| Urbaniste | `ext_urbaniste_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:418 / 237 |
| BE VRD | `ext_be_vrd_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:419 / 238 |
| BE hydraulique | `ext_be_hydraulique_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:420 / 239 |
| BE environnemental | `ext_be_environnemental_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:421 / 240 |
| Géotechnicien et études de sol | `ext_geotechnicien_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:422 / 241 |
| Paysagiste | `ext_paysagiste_par_lot` | saisi × N | € / lot | `nb_lots_total` | moteur:423 / 242 |
| Avocat | `ext_avocat_forfait` | saisi | € forfait | aucun | moteur:424 / 243+253 |
| SPS | `ext_sps_forfait` | saisi | € forfait | aucun | moteur:425 / 254 |
| Huissier | `ext_huissier_forfait` | saisi | € forfait | aucun | moteur:426 / 255 |

## Honoraires internes (moteur:431-453)

| Libellé | Code | Saisi / calculé | Pastille tableau | Multiplicateur | Source |
|---|---|---|---|---|---|
| Honoraires de gestion HT | `honoraires_gestion_ht` | calculé | calculé (gris) | — | moteur:435 |
| Honoraires de commercialisation | `honoraires_commercialisation` | calculé | € / lot (unitaire calculé) | `nb_lots_hectare` | moteur:436-442 / 259 |
| Communication groupe | `communication_groupe` | calculé | € / lot (unitaire calculé) | `nb_lots_hectare` | moteur:443-449 / 260 |

## Frais bancaires et impôts (moteur:454-463)

| Libellé | Code | Saisi / calculé | Pastille tableau | Multiplicateur | Source |
|---|---|---|---|---|---|
| Frais bancaires | `frais_bancaires` | calculé | X % des recettes lots Hectare TTC | taux résolu × recettes H TTC | moteur:458 / 264-265 |
| Impôts fonciers | `impots_fonciers` | calculé | calculé (gris) — pas de pastille #1640 (paramètre, pas une case) | `nb_lots_hectare` | moteur:459 / 266 |

## Prix de revient et résultat (moteur:464-486)

14 lignes toutes calculées, pastille « calculé » : `total_prix_revient`,
`total_prix_revient_postes`, `ecart_prix_revient`, `marge_fonciere`,
`tva_sur_marge`, `tva_totale`, `benefice_brut`, `benefice_pct_ca_ht`,
`benefice_pct_prix_revient`, `benefice_par_lot`,
`honoraires_internes_indicateur`, `resultat_consolide`,
`consolide_pct_ca_ht`, `consolide_pct_prix_revient`, `consolide_par_lot`.

# DÉPLOIEMENT-TEST

Sur OVH : `git pull origin main` puis `php artisan optimize:clear`, `view:clear`,
`journal:sync`. Ni migration, ni `route:clear`.

1. Noter sur un scénario existant les QUATRE totaux (Total recettes, Prix de
   revient, Bénéfice brut, Résultat consolidé) AVANT déploiement, les recomparer
   APRÈS. Identiques au centime.
2. Plus aucun chevron ni section repliée : Travaux VRD visible sans clic.
3. LOT 1 Terrassement, 6 lots : saisir 1 000 → formule « 1 000,00 € / lot × 6 lot(s) »
   et 6 000,00 en Montant HT (après enregistrement — le moteur recalcule).
4. Avocat / SPS / Huissier : pastille « € forfait », colonne Nombre vide.
5. Compteurs : deux cases (Saisie + Nombre).
6. Imprévus : fond gris, pastille avec le taux RÉEL, pas de saisie.
7. Frais bancaires : formule sur les recettes lots Hectare TTC, « ? » sur la ligne.
8. Scénario gelé : tout visible, aucune case.
9. 1366 px et 1920 px : aucun ascenseur horizontal.
10. Compte sans `foncier.prix` : montants toujours masqués.
11. Haut de page (#1641) et grille (#1642) inchangés.

# LEÇON

- Une pile de `<div v-show>` par section n’est pas un tableau : le navigateur ne
  peut pas aligner « où saisir ». Six colonnes fixes répondent à la question
  mieux qu’un libellé d’unité en petites capitales au-dessus de chaque case.
- Ouvrir « Travaux VRD » (12 postes) poussait ~800 px d’un coup parce que chaque
  ligne portait son unité + sa formule + son input. Ranger ces trois informations
  en colonnes ramène la ligne à 27 px sans rien retirer.
- `impots_fonciers` n’a toujours pas de pastille : le #1640 l’a tranché (paramètre,
  pas une saisie). Inventer « € / lot » ici aurait suggéré une case inexistante.
- Les assertions des lots #1636 / #1640 / #1641 / #1642 figent du markup. Un lot
  d’affichage suivant DOIT les relire et les mettre à jour dans le même commit,
  sinon le filtre `Faisabilite|Scenario` casse pour une reformulation.
