---
suivi: 1666
date: 2026-09-22
sujet: Forçage par scénario des taux d'étude financière
chantier: Foncier / Faisabilité
type: feature
statut: poussé
hash: 67949225
fichiers:
  - app/Services/Foncier/ScenarioParametresService.php
  - app/Services/Foncier/ScenarioEtudeFiService.php
  - app/Services/Foncier/ScenarioRecalculABlancService.php
  - app/Services/Foncier/ScenarioFaisabilitePdfExportService.php
  - app/Http/Controllers/Foncier/ScenarioFaisabiliteController.php
  - resources/js/Pages/Foncier/Scenarios/Show.vue
  - tests/Unit/ForcageTauxEtudeFi1666SourceTest.php
  - tests/Unit/ScenarioRecalculABlanc1651SourceTest.php
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - public/build/
  - docs/suivi/SUIVI_1666_forcage_taux_etude_fi.md
---

# SUIVI #1666 — forçage des taux d'étude Fi

## PROMPT ENVOYÉ

Sept postes d'étude Fi actuellement en lecture seule (hérités du
paramètre d'enseigne / barème) redeviennent saisissables PAR
SCÉNARIO. Deux niveaux : A (notaire, bancaires, impôts) pour tout
éditeur ; B (honoraires internes) pour GS_DIRECTION_GENERALE
seulement, cases violettes. Réutiliser `*_force` existants.
Aucune formule. V1 sans forçage = mêmes chiffres.

## FICHES LUES

- **#1640 LEÇON** — taux forçables déjà dans `scenario_parametres`
  (`taux_imprevus_travaux_force`, `taux_frais_bancaires_force`).
  Pastilles doivent lire le résolu, pas un littéral. Conservé :
  même mécanisme `force ?? base` (`ScenarioParametre::resolus`).
- **#1648 LEÇON** — un PUT étude, dirty avant succès. Les forçages
  partent dans le même `saveEtudeFi`.
- **#1651 LEÇON** — recalcul à blanc ne persiste pas ; overlay
  mémoire des forçages saisis, un seul run moteur.
- **#1656 / #1665** — totaux en pied, teinte stone ; non touchés.
- **#1659** — PDF reprend `calculerAffichage` ; libellé « (forcé,
  défaut X) » si `force_actif`.

Anti-collision : dernier numéro **#1665**. **#1666 est libre.**
`Show.vue` en série.

## PHASE 1 — constat

Aucune colonne nouvelle. Toutes existent depuis #1143
(`2026_07_31_240100_create_scenario_parametres_table.php`).

| Poste | Source défaut | Forçage déjà là | Moteur |
|---|---|---|---|
| frais_notaire 2,3 % | `taux_frais_notaire` enseigne → `_base` | `taux_frais_notaire_force` | L44-47 `Dec::mul(achat+ODF, tauxFraisNotaire)` |
| honoraires_montage_ht 3 % | `taux_honoraires_montage` | `taux_honoraires_montage_force` | L930-934 `honorairesLot(..., tauxHonorairesMontage)` |
| honoraires_gestion_ht 3 % | `taux_honoraires_gestion` | `taux_honoraires_gestion_force` | L936-940 idem gestion |
| honoraires_commercialisation 3000 €/lot | **barème palier** `honorairesCommerciauxPourPrixMoyen` (L76-99 Resolus) | `honoraires_commerciaux_forces` | L102-105 : force **court-circuite le barème** — unitaire unique, plus de VLOOKUP |
| communication_groupe 1500 €/lot | `communication_groupe_par_lot` | `communication_groupe_par_lot_force` | L260 `Dec::mul(communicationGroupeParLot, nbHectare)` |
| frais_bancaires 4 % | `taux_frais_bancaires` | `taux_frais_bancaires_force` (écran : **inatteignable** avant ce lot, Excel import seulement) | L265 `Dec::mul(recettesHectareTtc, tauxFraisBancaires)` |
| impots_fonciers 100 €/lot | `impots_fonciers_par_lot` | `impots_fonciers_par_lot_force` | L266 `Dec::mul(impotsFonciersParLot, nbHectare)` |

Colonnes **ajoutées** : aucune. **Déjà là** : les sept ci-dessus.
Pas de migration.

## SYNTHÈSE

Mécanisme unique `ScenarioParametresService::FORCAGES` +
`syncForcages` / `overlaySaisiesSurResolus` / `payloadForcages`.
Saisie % en POINTS (2,3) ; `/100` serveur comme l'import Excel
quand la cellule > 1.

Niveau B : `m365GroupNames()` brut, `abort(403)`. Compte de test
du refus : `foncier.gestion` + habilitation dossier, **sans**
`GS_DIRECTION_GENERALE` ni `GS_ADMIN_ERP`.

Violet : `bg-violet-50` (déjà dans l'ERP). Distinct de gris
calculé `#F3F4F6`, blanc saisie, ambre alerte, beige totaux
`stone-100`.

Signal forcé : « défaut 2,3 % » à côté. Vider = `_force` null.

Enseigne : `updateEtudeFi` n'importe pas `EnseigneFaisabiliteParametre`.
Seul `FaisabiliteParametresController` écrit le barème maison.

## DÉPLOIEMENT-TEST

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

Pas de migrate. `route:clear` inutile.

## LEÇON

Les colonnes `*_force` existaient depuis #1143 (import Excel) mais
n'étaient pas à l'écran : `taux_frais_bancaires_force` était
inatteignable. Réutiliser avant de migrer. Un PUT qui omet les
clés B pour un non-DG évite le 403 tout en laissant les honoraires
internes intacts. Forcer la commercialisation **remplace** le
barème palier : le dire. `Gate::before` / GS_ADMIN_ERP ne prouve
pas un refus — lire `m365GroupNames()` brut.
