---
suivi: 1168
date: 2026-08-03
sujet: Commercial — prix par lot + KPI frais une fois + annul groupée (brique 2/3)
chantier: commercialisation
type: feature
statut: poussé
hash: 6a0fa556
fichiers:
  - database/migrations/2026_08_03_180000_backfill_reservation_lots_prix_vente_ttc.php
  - app/Support/Commercial/ReservationLotsSync.php
  - app/Support/Commercial/ReservationLotsCoherence.php
  - app/Support/Commercial/RemisesAccordeesCalculator.php
  - app/Services/ReservationAcquereurUpdateService.php
  - app/Services/GenerationAppelFondService.php
  - app/Http/Controllers/ReservationController.php
  - app/Http/Controllers/CommercialController.php
  - app/Http/Controllers/Concerns/ManagesCommercialLotPayload.php
  - app/Observers/ReservationObserver.php
  - app/Support/ReservationHistoriquePresenter.php
  - resources/js/Composables/useRemisesAccordees.js
  - tests/Unit/RemisesAccordeesFraisUneFois1168Test.php
  - tools/diag/diag_remises_kpi_1168.php
  - public/build/
  - docs/suivi/SUIVI_1168_commercial_prix_multi_lots.md
---

## PROMPT ENVOYÉ

SUIVI #1168 brique 2/3 — l’argent : prix pivot source de vérité, total résa
dérivé, verrou AF sur prix lot, KPI frais une fois/résa, AdF sur total /
FK principal, annulation groupée. Pas d’UI multi-lot (3/3).

## SYNTHÈSE

### Fiches lues
- `SUIVI_1154` / `SUIVI_1161` — lecteurs prix / AF / KPI.
- `SUIVI_1167` — pivot + dual-write FK ; 0 anomalie.

### Prix (D1 / D1b)
- Source : `reservation_lots.prix_vente_ttc` (backfill depuis résa).
- Dérivé : `reservations.prix_vente_ttc` = Σ pivot (recalcul à chaque écriture).
- Copie : `lots_commerciaux.prix_vente_ttc` depuis sa ligne pivot.
- Saisie legacy (fiche / API) → écrit le **principal** puis recalcule.
- Verrou #1162 factorisé aussi sur `appliquerPrixLotPivot`.

### KPI remises
- Commercial par lot ; frais d’acte **une fois** par réservation (#1166+#1168).
- Test unitaire `RemisesAccordeesFraisUneFois1168Test` (3 assertions OK).
- Mesure prod : `php tools/diag/diag_remises_kpi_1168.php` AVANT/APRÈS
  (doit être identique au centime tant qu’il n’y a qu’1 lot/résa).

### AdF (D2)
- Montant inchangé mécaniquement (prix résa = somme).
- Convention transitoire : `appels_de_fonds.lot_commercial_id` = **lot principal**.
- Dette documentée ; schéma AF non modifié.
- 4 points comptables hors périmètre : **non touchés** (TVA 20 %, AR HT,
  706000, dual tables).

### Annulation (D3)
- Tous les lots du pivot → `en_stock`, prix lot NULL.
- Prix **pivot conservés** (restauration). Transaction unique.

### Audit
- `prix_vente_lot_ttc` + `numero_lot` / `lot_commercial_id` dans historique.

## DÉPLOIEMENT-TEST

1. `php tools/diag/diag_remises_kpi_1168.php` → noter KPI **avant**
2. `git pull` ; `php artisan migrate --force`
3. Lire `storage/app/migration_1168_reservation_lots_prix_report.json`
4. `php artisan commercial:coherence-reservation-lots` → 0 anomalie
5. Re-mesurer KPI → identique
6. Smoke grille / fiche / AdF

## LEÇON

Frais d’acte au niveau réservation + KPI itéré sur lots = double comptage
latent dès N lots. Factoriser « une fois par résa » dès la brique prix,
avant l’UI multi-lot.
