---
suivi: 1440
date: 2026-09-04
sujet: Avis d'imposition — largeurs, filtre TLVH, exports, récap
chantier: foncier
type: feature
statut: poussé
hash: 1159a5ec
fichiers:
  - app/Http/Controllers/Foncier/AvisImpositionController.php
  - app/Services/Foncier/AvisImpositionExportService.php
  - app/Services/Foncier/AvisImpositionRecapService.php
  - resources/js/Pages/Foncier/Patrimoine/AvisImposition/Index.vue
  - resources/views/pdfs/avis-imposition-table.blade.php
  - routes/web.php
  - tests/Unit/AvisImposition1440SourceTest.php
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - public/build/
---

# SUIVI #1440 — Largeurs, filtre TLVH, exports, récap

## PROMPT ENVOYÉ

Quatre volets sur Avis d'imposition : colonnes trop larges (filtre qui impose
une min-width) ; filtre TLVH encore texte alors que la colonne est une case ;
exports PDF/Excel de la vue filtrée ; bouton Récap fidèle à la feuille Excel.
Pas de nouvelle dépendance. Réutiliser vendor/. Ne pas défaire #1435–#1439.

## FICHES LUES

- `SUIVI_1439` — historique par ligne, GROUPES_SUPPRESSION, pas de N+1 index.
- `SUIVI_1438` LEÇON — min-w-0, overflow-x: scroll, flex-nowrap, jamais
  overflow-x-hidden. GROUPES_SUPPRESSION + m365GroupNames brut.
- `SUIVI_1437` — TLVH = « Oui » ou NULL ; 38 Oui. Filtre texte à remplacer.
- `SUIVI_1435` — contrat PATCH {champ, valeur}.
- `SUIVI_1422` — Adresse sticky left:0.
- `SUIVI_1423` — 311 lignes ; structures mesurées (dont 38 vides / TLVH et
  11 MR ET MME PORTALES).
- `SUIVI_1271` — pas overflow-x-hidden.

## SYNTHÈSE

### Prérequis
origin/main = 9aaf44e8 (fiche #1439), feature #1439 = 7f15251b. Ancêtre
confirmé (et db6d1853 #1438).

### Bibliothèques d'export (vendor/, aucune ajoutée)
- phpoffice/phpspreadsheet (déjà : TresoreriePlanExcelExport, AoLotsTableExportService)
- barryvdh/laravel-dompdf + dompdf/dompdf (déjà : factures/AO/NF Habitat)
Retenues telles quelles. composer.json inchangé.

### Volet 1 — largeurs
| Type | Colonnes | Largeur |
|------|----------|---------|
| très étroit | TLVH | 4.5rem |
| étroit | totaux 2021–2026, montant dégrevé, date | 6.75rem |
| moyen | structure, département, commune, interlocuteur, CDIF, n° avis, RP, DGVMT | 8.5rem |
| large | adresse, observation, commentaire | 14rem |

Filtre `w-full max-w-full min-width:0` (plus de `min-w-[5rem]`). Redimensionnement
PrimeVue `resizableColumns` + `columnResizeMode=expand`, **sans** `stateKey` :
session seule, perdu au rechargement. Adresse sticky + scroll #1438 conservés.
Table `width/min-width: max-content` (plus `min-width:100%` qui étirait).

### Volet 2 — filtre TLVH
Select Tous / Oui / Non. `FilterService` `tlvhTriEtat` : oui = `Oui` ;
non = null ou '' (pas la chaîne « Non »). Tri inchangé (colonne string).

### Volet 3 — exports
POST `/patrimoine/avis-imposition/export/{excel|pdf}` (pas GET devinable).
Même `peutAcceder` / `m365GroupNames()` brut que la page. Corps : `ids` dans
l'ordre de la vue + `columns` whitelist. Une `whereIn`, réordonnancement PHP.
Totaux recalculés. Fichier `avis-imposition_YYYY-MM-DD.xlsx|.pdf`.

PDF : A4 paysage, police 6,5 px, `table-layout:fixed`, padding 2 px — 21
colonnes sur une page en largeur ; le surplus de **lignes** passe aux pages
suivantes. Pas A3 pour rester imprimable A4.

### Volet 4 — Récap
GET `/patrimoine/avis-imposition/recap`, une requête `GROUP BY` des expressions
(compatible `only_full_group_by`), SUM des 6 millésimes. Sélecteur d'année
(défaut = plus récente non nulle). Mention : « sur l'ensemble des avis
(filtres du tableau ignorés) ».

**38 lignes sans structure (TLVH)** : bloc AUTRES, ligne « Sans structure (TLVH) »,
en dernier avant le sous-total. **MR ET MME PORTALES** : AUTRES, ligne à son nom
(absent de l'Excel d'origine, présent en base — ne pas faire disparaître).
Total général = somme des trois blocs.

### Droits
Accès page inchangé. Exports/récap = même liste. Historique/suppression #1438
inchangés. Lecture seule métier (aucune écriture, aucune migration).

## DÉPLOIEMENT-TEST

```
git pull origin main
php artisan optimize:clear
php artisan view:clear
php artisan route:clear
php artisan journal:sync
```

Pas de migrate. Pas de composer/npm sur OVH.

## LEÇON

Un `min-w` sur le champ de filtre impose la largeur de colonne : le retirer et
fixer la largeur sur le `Column`. Export GET + ids en query = URL copiable =
fuite patrimoine ; POST + même `peutAcceder` que la page. Récap ≠ export :
l'un ignore les filtres, l'autre les suit — le dire dans la fenêtre. Les 38
TLVH sans structure et « MR ET MME PORTALES » doivent apparaître dans AUTRES
sinon le total général est faux.
