---
suivi: 1500
date: 2026-09-10
sujet: Fix f_societe scroll infini mise en paiement
chantier: comptabilite / mise-en-paiement
type: fix
statut: poussé
hash: 02d3cb7d
fichiers:
  - resources/js/Pages/Factures/Paiement/Index.vue
  - tests/Unit/PaiementFiltreFSocieteScroll1500SourceTest.php
  - public/build/
  - docs/suivi/SUIVI_1500_fix_f_societe_scroll_mise_en_paiement.md
---

# SUIVI #1500 — PHASE 2 FIX — `f_societe` sur le scroll infini MEP

## PROMPT ENVOYÉ

PHASE 2 — FIX. Cause établie #1498 et confirmée par mesure prod :
le PHP filtre correctement ; `Index.vue` n’émettait que `entite_id`.
Les lots `/lignes` partaient sans `f_societe`. Périmètre strictement
front, fichier unique `Factures/Paiement/Index.vue`. #1499 en cours
sur LotsGrillePanel / GrillePrixExportService / CommercialisationController
— ne pas les toucher.

## FICHES LUES

- **#1498 LEÇON** — un paramètre serveur nouveau que le Vue de scroll
  infini n’émet pas filtre le premier lot et laisse le reste intact.
  Impact : point de code unique `buildFilterQueryParams` + hydratation
  `f_societe`. PHP inchangé. Point C (1246/1245 vs 1093) expliqué par
  le premier lot filtré / lots suivants non filtrés — non rouvert.
  Question métier override JSON : ouverte, hors périmètre.
- **#1496 LEÇON** — factoriser le parseur avant de propager un filtre ;
  `f_societe` CSV canonique, `entite_id` alias, `f_societe` gagne si
  les deux sont présents. Impact : le Vue émet désormais les deux
  (CSV + alias mono) pour coller à cette priorité sans casser le chemin
  mesuré `?entite_id=13`.
- **#1483 LEÇON** — le clic ouvre exactement le périmètre du compteur.
  Impact : `f_societe` issu du tableau de bord doit survivre jusqu’au
  `fetch` du curseur, pas seulement au GET Inertia initial.
- **#1499** (lu après fetch, déjà sur origin/main au démarrage du lot)
  — LotsGrillePanel / export grille. Impact : rebase sur `79f0ffaa`
  avant le rebuild pour ne pas écraser `Commercialisation-*.js`.

## BASE GIT

Attendu prompt : `063ae1c0` (fiche #1497). Réel au fetch :
`79f0ffaa` chore hash fiche #1499 (export grille). Rebase = checkout
depuis origin/main à jour. Aucun fichier #1499 touché. Aide (#1497)
non touchée. Aucun PHP modifié. Aucun runtime PHP installé.

## SYNTHÈSE

Régression d’intégration du #1496 (trou Vue), pas un changement de
sémantique PHP. `entite_id` (préexistant, mesuré 15/15 E-13) reste
émis. `f_societe` CSV (nouveau #1496, ignoré par le Vue) est désormais
émis par `buildFilterQueryParams`, donc par `applyFilters` ET par
chaque `loadMoreLignes` (IntersectionObserver `rootMargin: 200px`
inclus).

Select **reste mono**. Pas de refonte du filtre visible. Une URL
`?f_societe=13,4` (union) n’est pas représentable dans le select :
il reste sur « Toutes les sociétés » mais le CSV complet est conservé
dans `filtres.f_societe_csv` et renvoyé à chaque `/lignes`. Une URL
mono (`f_societe=13` ou `entite_id=13`) positionne le select sur cette
société.

### Ce que le front émet désormais

| Situation | `f_societe` | `entite_id` | Pourquoi |
|---|---|---|---|
| Select mono choisi / URL `entite_id=N` / `f_societe=N` | `N` | `N` | CSV canonique #1496 + alias mesuré qui fonctionne |
| URL `f_societe=13,4` (union, select vide) | `13,4` | (absent) | le select mono ne peut pas porter l’union ; le CSV seul suffit, priorité serveur |
| Réinitialiser | (absent) | (absent) | reset volontaire |

Si les deux sont présents, le serveur (#1496) fait gagner `f_societe`.
Quand ils portent le même id, le résultat est identique au chemin
`entite_id` mesuré en prod.

Aucun PHP. Pas de migration. Pas d’entrée de journal (aucun geste
nouveau : le filtre existait, il traverse maintenant le scroll).

## TABLEAU DE MAPPING

| Libellé affiché | Valeur postée (select) | Paramètre d’URL | Champ back | Si vide |
|---|---|---|---|---|
| « Toutes les sociétés » | `''` | aucun `f_societe` ni `entite_id` (sauf union CSV hydratée, voir ci-dessous) | `filtres['f_societe']` / `filtres['entite_id']` lus par `filtresFromRequest` → `entiteIdsFromFiltres` vide | file complète, inchangée |
| Une société (ex. E-13) | id numérique unique (`'13'`) | **`f_societe=13` ET `entite_id=13`** | `QueryIdListParser` : `f_societe` d’abord, sinon `entite_id` | — |
| Union dashboard `?f_societe=13,4` | select vide (mono, non transformé) | **`f_societe=13,4`** (conservé) | même parseur, `[13, 4]` | le CSV hydrate `f_societe_csv` ; le select n’affiche pas l’union |

Le front émet **`f_societe` CSV dès qu’un filtre société est actif**,
et **`entite_id` en plus** dès que le select a une valeur unique.

## RECENSEMENT XHR

| Appel | Filtre liste ? | Transmission |
|---|---|---|
| `router.get(..., buildFilterQueryParams())` Appliquer | oui | `f_societe` + `entite_id` |
| `router.get(..., {})` Réinitialiser | oui (vide) | volontairement aucun |
| `fetch(/lignes?…)` `loadMoreLignes` | oui | `URLSearchParams(buildFilterQueryParams())` + cursor |
| `router.reload({ only: ['lignes'] })` après payer / annuler compta | oui (URL courante Inertia) | query string de la page, donc `f_societe` une fois dans l’URL |
| `axios.patch .../lignes/{lineKey}` | non | ligne déjà chargée |
| `axios.patch .../reglement-statut` | non | facture déjà affichée |
| `axios.patch .../paiement-fonds-propres` | non | dépôt déjà affiché |
| `axios.post .../traiter` | non | payload des lignes **sélectionnées** (inchangé) |
| `axios.get .../ecritures/{uuid}` | non | dépôt déjà affiché |
| `router.visit` fiche facture | navigation | hors liste |

## DÉPLOIEMENT / TEST

```
git pull origin main
php artisan optimize:clear
php artisan view:clear
```

Pas de migrate. Pas de journal:sync. Pas de npm/composer/optimize
sur OVH. `route:clear` inutile (aucune route ajoutée).

Aucun PHP modifié — ne pas installer de runtime PHP.

Recoupement **Sabrina (24) ou Rudy**, pas Robin
(`hasAnyM365Group` TRUE d’emblée via `isAdminERP` / Gate::before).
Laisser la page charger entièrement (scroll jusqu’en bas) avant
de compter :

1. `/factures/mise-en-paiement?entite_id=13` → 15 lignes, toutes E-13.
2. `/factures/mise-en-paiement?f_societe=13` → même résultat que (1).
3. `/factures/mise-en-paiement?f_societe=13,4` → uniquement E-13 et E-04.
   Aucune E-03, E-10, E-11, E-17, E-19, E-23, E-24.
4. URL `f_societe` mono : le select affiche la société, pas « Toutes ».
   URL `f_societe=13,4` : select reste « Toutes » (mono) ; la liste est
   filtrée via le CSV.
5. Aucune ligne en double après chargement complet.
6. `/factures/mise-en-paiement` sans filtre → inchangé.

sqlite skipped (`pdo_sqlite` absent) : aucune valeur de preuve ici.
Le défaut est dans le navigateur. Seule la mesure en production tranche.

## LEÇON

Un GET Inertia initial filtré ne prouve rien si le scroll infini
reconstruit la query sans le paramètre canonique. `entite_id` (l’UI)
et `f_societe` (l’URL tableau de bord) doivent sortir de la **même**
fonction jusqu’au `fetch` du curseur. Tester le second lot XHR, pas
seulement l’URL du premier rendu.
