---
suivi: 1592
date: 2026-09-17
sujet: Retrait parcelle du dossier — avertir, pas refuser
chantier: foncier / dossiers
type: feature
statut: poussé
hash: e5766092
fichiers:
  - app/Services/Foncier/DossierFoncierPerimetreService.php
  - app/Http/Controllers/Foncier/DossierFoncierController.php
  - resources/js/Components/Foncier/DossierFoncierTab.vue
  - tests/Unit/DossierFoncier1592RetraitSourceTest.php
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - public/build/
  - docs/suivi/SUIVI_1592_retrait_parcelle_non_bloquant.md
---

# SUIVI #1592 — Retrait parcelle non bloquant

## PROMPT ENVOYÉ

Lever le refus de retrait d’une parcelle engagée (promesse / acte)
du périmètre d’un dossier. Confirmer avec un texte qui nomme les
engagements et rappelle qu’ils ne sont pas affectés. Remplacer
`alert()` / `confirm()` natifs. Recalcul statut #1569 appelé, non
modifié. Filtre commune de l’onglet FONCIER retiré. #1588 intact.

## FICHES LUES

- **#1289** — le refus « engagement bloquant » est né ici
  (`retirerParcelle` + `peut_retirer`). Impact : lever ce refus, pas
  le pivot ni l’audit `perimetre_parcelle`.
- **#1569 LEÇON** — `deduire()` : détenue > sous_compromis > offre >
  dossier_vivant. Impact : après retrait, une promesse signée laisse
  « Sous compromis », un acte laisse « Détenue ». On appelle
  `recalculerIds` déjà branché, on ne change pas `deduire`.
- **#1579 / #1583** — `parcelle_retiree` via audit `perimetre_parcelle`.
  Impact : aucun toucher à l’agrégateur ; le `recordChange` existant
  suffit.
- **#1588 LEÇON** — rattachement à un *nouveau* dossier refuse
  `parcelles.statut = sous_compromis`. Impact : `assertParcellesRattachablesALaCreation`
  intact. Ne pas le confondre avec le retrait.
- **#1591 LEÇON** — Show.vue / DossierSyntheseTab en série. Impact :
  ce lot ne touche pas Show.vue ni AppShell.

## OÙ LE REFUS ÉTAIT PRONONCÉ (établi avant code)

| Couche | Lieu | Comportement avant |
|---|---|---|
| Serveur | `DossierFoncierPerimetreService::retirerParcelle` | `engagementsBloquants()` non vide → `ValidationException` « Impossible de retirer … engagement bloquant » |
| Payload | `serializeParcellesDerivees` / `serializeParcellesOrphelines` | `peut_retirer => $bloquants === []` |
| Client | `DossierFoncierTab.vue` `retirerParcelleDuDossier` | si `peut_retirer === false` → `window.alert('Impossible de retirer …')` ; sinon `confirm()` natif |

Le DELETE `destroyParcellePerimetre` n’avait pas d’autre garde : le
refus était uniquement `engagementsBloquants` + le court-circuit UI.

## RECALCUL STATUT APRÈS RETRAIT

Toujours `ParcelleStatutService::recalculerIds([$parcelleId])` après
delete du pivot. `deduire()` inchangé :

- promesse `signe` → `sous_compromis` (« Sous compromis ») même hors
  dossier ;
- `societe_detentrice_id` → `detenue` (« Détenue ») ;
- plus de dossier vivant et pas d’autre fait → `reperee` (pas
  `exploree` : explorée exige un dossier *clos*).

## NATIFS SUR CET ÉCRAN

Avant : `window.alert` (retrait bloqué) + `confirm()` (retrait) +
`confirm()` (retrait propriétaire). Tous remplacés par
`useConfirm` / `ConfirmDialog` (même patron qu’Avis d’imposition /
Juridique).

Hors onglet FONCIER (non traités) : `Show.vue` a encore
`window.confirm` / `window.alert` (dissocier programme, corbeille
#1589, clôture statut #1591, suppression scénario).

## SYNTHÈSE

Retrait toujours possible après confirmation nominative. Promesse et
acte intacts. Filtre commune de l’onglet retiré ; celui de
Prospection/Index inchangé.

## DÉPLOIEMENT-TEST

OVH : `git pull origin main` ; `php artisan optimize:clear` ;
`journal:sync`. Pas de `migrate`. Pas de `route:clear` (route
inchangée).

## LEÇON

Le refus de retrait était *double* : exception serveur *et*
`alert()` si `peut_retirer === false`. Lever l’un sans l’autre
laissait le blocage. Ne pas absorber le #1588 (création / rattachement
sous compromis) : ce n’est pas le même verbe. `charges_portage` et
avenants figuraient dans `engagementsBloquants` et polluaient
l’`alert()` ; la confirmation ne cite que offre / promesse / acte.
