---
suivi: 1320
date: 2026-08-13
sujet: liberation_rg_demandes
chantier: marches_compta
type: feature
statut: poussé
hash: 8bb2edc8
fichiers:
  - database/migrations/2026_08_13_140000_create_demandes_liberation_rg_table.php
  - database/migrations/2026_08_13_140100_create_demande_liberation_rg_justificatifs_table.php
  - app/Models/DemandeLiberationRg.php
  - app/Models/DemandeLiberationRgJustificatif.php
  - app/Policies/DemandeLiberationRgPolicy.php
  - app/Services/DemandeLiberationRgService.php
  - app/Http/Controllers/DemandeLiberationRgController.php
  - app/Http/Controllers/MarcheController.php
  - app/Providers/AppServiceProvider.php
  - routes/web.php
  - config/services.php
  - resources/js/Pages/Marches/Show.vue
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - public/build/
  - docs/suivi/SUIVI_1320_liberation_rg_demandes.md
---

## PROMPT ENVOYÉ

PHASE 2 #1320 — modèle + demande + états + affichage Retenues & Pénalités.
Diag #1309. HEAD attendu c8d2a327. Partie 2 (Synthèse / KPI / libellé « à libérer »)
HORS PÉRIMÈTRE. Porte STOP Sage.

## SYNTHÈSE

### Fiches lues
- `#1309` LEÇON : colonnes `retenues_garantie.statut/date_liberation` inutilisables
  (reset upsert) ; MRES ne filtre pas statut → **nouvelle table**.
- `#1304` / `#1306` / `#1308` : HT, anatomie blocs, CP — **non touchés**.
- `#1311` : `date_reception_travaux` pour échéance informative.
- `#1319` : Teleport `defer` — **non défait**.
- `#1268` : pas de FIFO.
- `#1234` / `#1301` : `m365GroupNames()` brut vs `hasAnyM365Group`.

### Décisions respectées
- Demande sur le **marché**, montant HT libre, pas d’allocation FIFO.
- Plafond = `etats.rg.montant_retenu` (HT) − somme Demandée+Payée.
- Justificatif SP obligatoire ; échec upload ⇒ **rien créé**.
- États Demandée → Payée | Refusée ; payer/refuser = GS_COMPTABILITE|GS_ADMIN_ERP
  via `m365GroupNames()` brut (`DemandeLiberationRgPolicy`).
- **Porte STOP Sage / Intacct** : aucune écriture comptable automatique.

### Mécanisme SharePoint
Réutilise `SharePointService::createFolderInParentItem` + `uploadFichierApp`
(même famille que `MarcheController::uploadDocumentToSharePoint` ~L2866 et
`persistDocumentUpload` local-first ~L2430). Sous-dossier : **« Libération RG »**
sous `sharepoint_folder_pieces_admin` / `sharepoint_folder_id` du marché.
`sharepoint_item_id` NOT NULL + indexé.

### Vérification écran / marché 109
**NON** — stub local `erp_immo_migrate_1113` : 0 marché ; pas de session prod.
Lot **non validé** sur les tests métier 3–17 (argent réel). Migrations + Reflection OK en local.

## DÉPLOIEMENT-TEST

```bash
git pull origin main
php artisan migrate --force
php artisan migrate:status | grep -c Pending
php artisan optimize:clear
php artisan view:clear
php artisan route:clear
php artisan journal:sync
```

Porte STOP : ne pas brancher Intacct/Sage avant validation Sabrina BARTOLI / Rudy BENOR
(direction débit 401400).

## LEÇON

Des colonnes « libération » déjà présentes mais reset à chaque upsert + cumuls qui
ignorent le statut = fausse piste. Une table de demandes avec plafond dérivé de
`montant_retenu` HT et justificatif `sharepoint_item_id` obligatoire évite d’effacer
une libération au prochain rapprochement. Toujours tester les groupes M365 en brut.
