---
suivi: 1840
date: 2026-10-09
sujet: Synthèse CIE — une ligne par marché
chantier: programmes / CIE
type: évolution
statut: poussé
hash: b4d75b561
fichiers:
  - app/Console/Commands/CieRattacherMarchesCommand.php
  - app/Http/Controllers/CieController.php
  - app/Models/CieRepartitionRattachement.php
  - app/Services/CieService.php
  - database/migrations/2026_10_09_170000_create_cie_repartition_rattachements_table.php
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - resources/js/Pages/Cie/CieSyntheseGrille.vue
  - resources/js/Pages/Cie/Index.vue
  - tests/Feature/Cie/CieRattachementMarche1840Test.php
  - public/build/
---

# SUIVI #1840 — grille CIE par marché

Fiches lues avant le code : #1773 (grille par fournisseur, ne pas recréer les répartitions en bloc, Facturé lu sur les prélèvements), #1280 (bandeau sans marché). Le diagnostic #1839 n’a pas de fiche : le rapport de la conversation tient lieu de source. La commande existante #987 écrivait `cie_operations.marche_id`. Elle est remplacée : elle n’écrit plus que `cie_repartitions.marche_id`.

## PROMPT ENVOYÉ

Phase 2 du diagnostic #1839. Une ligne par marché (référence · poste), marchés de la rubrique « 4 — TRAVAUX » et `applicable_cie`. Lignes « À répartir » et « Sans marché ». Commande `cie:rattacher-marches` en aperçu, `--appliquer`, `--annuler=LOT`. Aucun prélèvement créé ou modifié. Saisie facture, comptabilisation et Sage non touchés.

## SYNTHÈSE

### Mapping

| Ligne / cellule / bouton | Route ou valeur postée | Champ | Calcul / effet |
|---|---|---|---|
| Ligne marché, nom en gras | — | `fournisseurs.nom` | via `marches.fournisseur_id` |
| Sous-titre | — | `marches.reference`, `postes_budgetaires_types.libelle` | `{reference} · {poste}` |
| Cellule Ventilé d’un marché | `PATCH programmes.cie.ventilation` `fournisseur_id`, `marche_id` de la ligne, `montant_ht` | `cie_repartitions.montant_calcule_ht` et `marche_id` | somme des répartitions de ce marché ; un `marche_id` null n’y entre que si le fournisseur n’a qu’un marché R2 |
| Cellule Facturé | — | `cie_prelevements.montant_retenu_ht` | `factureHtNv1` : statut différent de `annule`, dépôt au-delà du NV1 |
| % ventilé | — | `cie_operations.montant_total_ht` | `round(somme de toutes les ventilations / montant × 100)`, inchangé |
| Total HT opération | — | `montant_total_ht`, somme facturée | inchangé |
| KPI Avancé / Déjà retenu / Reste | — | sommes des répartitions et des prélèvements actifs | inchangés |
| Ligne « À répartir — {fournisseur} », bouton Rattacher | `PATCH` `deplacer=true`, `fournisseur_id`, `marche_id` choisi | `cie_repartitions.marche_id` | déplacement des lignes `marche_id` null ; refus si un prélèvement actif existe |
| Ligne « Sans marché » | aucune | lecture seule | infobulle « Aucun marché de travaux pour ce fournisseur : créez le marché pour pouvoir retenir. » |
| `php artisan cie:rattacher-marches` | aperçu | — | aucune écriture |
| `--appliquer` | — | `cie_repartitions.marche_id` | seulement si null et un seul marché R2 ; journal `cie_repartition_rattachements` |
| `--annuler=LOT` | — | `marche_id` remis à null | seulement si le marché et le montant n’ont pas changé depuis |

### Ce qui a été fait

- Marché R2 = marché vivant, `fournisseur_id` renseigné, rubrique « 4 — TRAVAUX » (tirets ou « 4. ») et `postes_budgetaires_types.applicable_cie`.
- La grille ne regroupe plus par fournisseur. Deux marchés du même fournisseur font deux lignes.
- Le bandeau sépare « à répartir », « sans marché » et les montants à un seul marché pas encore rattachés.
- La commande n’écrit pas `cie_operations.marche_id`, ni `cumul_retenu_ht`, ni `cie_prelevements`.
- `DepotFactureSaisieForm` et `DepotFactureController` ne sont pas modifiés.

## DÉPLOIEMENT-TEST

```
git pull origin main
php artisan optimize:clear
php artisan view:clear
php artisan migrate --force
php artisan journal:sync
php artisan cie:rattacher-marches
php artisan cie:rattacher-marches --appliquer
php artisan cie:rattacher-marches --annuler=LOT
```

Pas de `npm` ni de `composer` sur le serveur. Lancer d’abord l’aperçu, puis `--appliquer` seulement après lecture. Louis Pasteur : la commande ne crée aucune retenue.

## LEÇON

`cie_operations.marche_id` est le marché de l’avanceur. Le rattachement d’une ventilation est `cie_repartitions.marche_id`. Ne pas réécrire l’ancienne commande #987 sur la colonne de l’opération. Une cellule marché ne doit pas supprimer les ventilations des autres marchés du même fournisseur. Un prélèvement actif interdit le déplacement et la suppression, pas le simple remplissage d’un `marche_id` encore null.
