La carte d'un lot n'affichait que quatre des huit colonnes du compte rendu, la
colonne Total absente, et le bandeau replié montrait un total figé : corriger un
règlement ne le changeait pas. Pire, les quatre agrégats modifiables ne sont
jamais enregistrés — seules les lignes partent en base (`service.py`) — pendant
que les colonnes réellement écrites, dont Regles et Impayé, n'étaient éditables
nulle part. On corrigeait donc un champ sans effet, et pas celui qu'il fallait.
Le détail des lignes reprend maintenant le tableau du compte rendu, colonne pour
colonne, la ligne « Totaux » comprise en pied. Les dix champs d'une ligne et les
huit de la ligne Totaux sont modifiables, sans exception : cette page sert à
vérifier une extraction avant de l'enregistrer, l'utilisateur y a le dernier mot.
Rien n'est plus recalculé à l'affichage ni reporté d'un champ sur un autre.
Corriger une colonne ne déclenche que ce qui a été demandé — un total réécrit
d'office effacerait sans le dire ce que le compte rendu porte.
Un seul contrôle subsiste, en signalement pur : chaque colonne de la ligne
« Totaux » est confrontée à la somme de cette même colonne sur les lignes. Le
recoupement est celui que fait l'œil sur le tableau. Déduire le total des autres
colonnes laissait passer le cas le plus parlant — une colonne Total qui ne somme
visiblement pas, faute d'avoir extrait la valeur d'une ligne.
Sur les 388 lots des documents extraits, ce contrôle signale quatre lots, tous de
vraies extractions incomplètes : un règlement de 707,29 € qu'aucune ligne ne
porte, un « divers » de 308,76 € sauté à un changement de page, deux lots réglés
sans ligne. La colonne fautive passe en surbrillance et affiche la valeur
calculée sous le montant extrait, sans jamais s'y substituer.
Le solde antérieur quitte la colonne Loyers pour la colonne Période, où le
compte rendu l'imprime. Compté à part sans être affiché à part, il donnait une
colonne Loyers qui semblait ne pas sommer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La fiche compte une dizaine de champs pour une vingtaine de lots : un
formulaire par lot imposerait autant d'allers-retours. Le tableau garde
l'ergonomie du tableur d'où viennent ces données — une ligne par lot, les
colonnes dans le même ordre, chaque cellule enregistrée en la quittant.
Ce que le serveur calcule est affiché comme tel et non saisissable :
échéance du DPE (rouge si périmé, ambre à moins d'un an) et écart de
surface. Le type vu par le PDF reste visible à côté du type saisi quand les
deux se contredisent, plutôt que d'être remplacé sans le dire.
Tri et filtre vivent dans l'en-tête de chaque colonne, jamais au-dessus du
tableau : c'est là qu'on les cherche en lisant la colonne. Une liste de
choix peut proposer, dans un groupe à part, ce qui n'est pas une valeur de
la colonne — rattachement d'un lot aux comptes rendus, désaccord de type.
L'en-tête se fige au défilement, ce qui demande de borner la hauteur du
tableau : sans conteneur à hauteur limitée, `sticky` n'a rien à quoi se
tenir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Refuser une modification, c'est reenvoyer la valeur actuelle du document. Mais
l'enregistrement ramene les donnees a une forme canonique (aujourd'hui les
numeros de lot) : sur ces champs, le refus n'est pas conserve. L'interface le
laissait croire.
Plutot que de traiter le cas des lots en dur, le serveur devient seul juge de ce
qu'il stocke et l'annonce : `canonicalize_extraction` regroupe les reecritures
faites a la persistance, `save_document` et l'apercu passent par elle, et
/api/documents/{id}/re-extract renvoie `previous_canonical` a cote de
`previous_data`. Le front compare ces deux jeux et signale, sous chaque case
decochee, la valeur que l'enregistrement reecrira — sans connaitre aucune regle.
Une transformation ajoutee plus tard remontera donc toute seule dans l'interface.
Toutes les differences restent visibles et toutes les cases actives : voir ce
qui change et pouvoir se prononcer prime, quitte a etre prevenu que ce champ-la
reviendra reecrit.
Supprime au passage frontend/src/utils/lots.js, qui dupliquait la regle de
normalisation cote client.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le balayage n'imposait que le tout ou rien par document. Chaque modification a
desormais sa case : un champ de metadonnee, le nom ou le type d'un locataire,
une operation ajoutee ou supprimee. Les champs textuels retenus sont en outre
modifiables a la main, pour les cas ou ni l'ancienne ni la nouvelle valeur ne
convient. Tout reste coche par defaut : le cas courant tient toujours en un clic.
Les montants et lignes d'un locataire forment un seul bloc : les retenir
separement produirait un total ne correspondant plus a ses lignes, alors que ces
chiffres alimentent les revenus et les depenses.
Le document enregistre est construit par fusion (mergeExtraction) : on part des
donnees en base et on n'y applique que ce qui est retenu. Le diff porte donc
maintenant de quoi rejouer chaque changement (identifiant, chemin, valeurs
brutes) et l'index d'origine des operations supprimees, pour les remettre a leur
place si on refuse leur disparition. Les tags suivent la liste d'operations
finale, y compris ceux d'une operation restauree.
Une reecriture de forme d'un numero de lot ("0001" -> "01") est signalee comme
imposee et sa case verrouillee : le backend normalise tout enregistrement, une
case sans effet aurait laisse croire l'inverse.
Ajoute vitest : la fusion decide de ce qui est ecrit en base, elle est couverte
par 15 tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>