feat: annonce les reecritures que l'enregistrement imposera

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>
This commit is contained in:
2026-07-26 06:43:02 +02:00
parent 43efea4945
commit a1da4fc97f
10 changed files with 268 additions and 86 deletions

View File

@@ -202,6 +202,7 @@
<ExtractionDiffDetails
:diff="item.diff"
:selection="item.selection"
:server-overrides="item.serverOverrides"
@update:selection="updateSelection(item, $event)"
/>
@@ -321,7 +322,11 @@
import { computed, onMounted, onBeforeUnmount, reactive, ref } from 'vue'
import ExtractionDiffDetails from '../components/ExtractionDiffDetails.vue'
import TagAutocomplete from '../components/TagAutocomplete.vue'
import { computeExtractionDiff, listChangeIds } from '../utils/diffExtraction.js'
import {
computeExtractionDiff,
computeServerOverrides,
listChangeIds,
} from '../utils/diffExtraction.js'
import { countAccepted, mergeExtraction } from '../utils/mergeExtraction.js'
import { fillPredictions, remapTags, toDepensesTags } from '../utils/tagRemap.js'
@@ -432,6 +437,8 @@ function resetItems() {
newData: null,
// État des cases du détail, par identifiant de changement.
selection: {},
// Changements que l'enregistrement réécrira, quel que soit le choix.
serverOverrides: {},
changeIds: [],
counts: { accepted: 0, total: 0 },
tags: {},
@@ -492,6 +499,11 @@ async function scanOne(item) {
item.changeIds = listChangeIds(diff)
item.selection = {}
item.counts = countAccepted(item.changeIds, {})
item.serverOverrides = computeServerOverrides(
diff,
result.previous_data,
result.previous_canonical
)
await prepareTags(item, result)
item.status = 'modifie'