---
suivi: 1078
date: 2026-07-30
sujet: Module Foncier Lot 6 — offres formelles
chantier: module-foncier
type: feature
statut: poussé
hash: f9210c9c
fichiers:
  - database/migrations/2026_07_30_180000_create_offres_foncieres_table.php
  - app/Models/OffreFonciere.php
  - app/Http/Controllers/Foncier/OffreFonciereController.php
  - app/Support/Foncier/Alertes/Types/OffreExpirationType.php
  - resources/js/Pages/Foncier/Dossiers/Show.vue
  - tests/Feature/Foncier/FoncierOffresFormellesTest.php
  - docs/suivi/SUIVI_1078_foncier_offres.md
---

## PROMPT ENVOYÉ

SUIVI #1078 — MODULE FONCIER LOT 6 : OFFRES FORMELLES.
Table offres_foncieres / OffreFonciere, UI fiche (onglets), alerte expiration
branchée #1077 sans modifier le moteur, indicateur écart + slot promesse vide.

## SYNTHÈSE

### Grep collision (avant code)
`rg OffreFonciere|offres_foncieres|class Offre\b` → aucune occurrence.

### Fiche dossier → onglets
La fiche #1075 empilait déjà synthèse / parcelles / propriétaires / habilitations /
fil. Ajout d'un 4e bloc empilé aurait rendu illisible → TabView :
Synthèse | Parcelles | Offres | Suivi | Accès.

### Alerte offre_expiration (déclaration seule)
- Classe `OffreExpirationType` + 1 ligne `FoncierAlerteTypeRegistry::TYPES`
- Seed `foncier_alerte_configs`
- Alertable = DossierFoncier (ACL socle) ; palier `j-N.o{id}` pour dédup/offre
- git diff EvaluationService / Middleware / migrations #1077 = vide (hors TYPES)

### Mapping statuts / modes

| Libellé UI | Valeur postée | Colonne DB | Libellé back |
|------------|---------------|------------|--------------|
| Envoyée | envoyee | statut | Envoyée |
| Acceptée | acceptee | statut | Acceptée |
| Refusée | refusee | statut | Refusée |
| Contre-offre | contre_offre | statut | Contre-offre |
| Expirée | expiree | statut | Expirée |
| Sans réponse | sans_reponse | statut | Sans réponse |
| Forfaitaire | forfaitaire | mode_prix | Forfaitaire |
| Au m² | au_m2 | mode_prix | Au m² |

## DÉPLOIEMENT / TEST
1. git pull && migrate --force && view:clear && route:clear && journal:sync
2. Fiche dossier → onglet Offres : 3 offres successives, 2 propriétaires
3. User sans foncier.prix : offre visible, montant null dans JSON
4. Accès direct `/foncier/offres-foncieres/{id}` hors ACL → 403
5. Offre envoyee J-7 → 1 alerte ; acceptee → 0

## LEÇON
Nommer `OffreFonciere` / `offres_foncieres` dès la Phase 0 évite la collision
`Offre` / `offres`. Réorganiser en onglets dès le 3e bloc, pas au 9e.
