fix: conserve l'identite d'un document re-extrait

Le remplacement par ID mettait a jour le document en le supprimant puis en le
recreant : la ligne changeait d'ID, cassant les liens qui la referencent (URL
d'edition, telechargement du PDF) juste apres un balayage de re-extraction. Le
document est desormais mis a jour sur place, seules les donnees derivees
(revenus, depenses) etant regenerees.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 05:17:39 +02:00
parent 9cf0a89aab
commit 6f2530014f
2 changed files with 63 additions and 30 deletions

View File

@@ -171,6 +171,7 @@ class DatabaseService:
# Check for duplicates and preserve existing file paths if overwriting
existing_pdf_path = None
existing_json_path = None
reused: Document | None = None # document mis a jour sur place
if replace_document_id is not None:
existing = self.session.get(Document, replace_document_id)
if existing is None:
@@ -180,20 +181,28 @@ class DatabaseService:
collision = self.check_duplicate(reference, doc_date)
if collision is not None and collision.id != existing.id:
raise DuplicateDocumentError(reference, doc_date)
overwrite = True
existing_pdf_path = existing.pdf_path
existing_json_path = existing.json_path
# Les donnees derivees sont regenerees, mais la ligne document est
# conservee : son ID survit a la re-extraction, donc les liens qui
# la referencent (URL d'edition, PDF) restent valides.
existing.revenus.clear()
existing.depenses.clear()
self.session.flush()
reused = existing
else:
existing = self.check_duplicate(reference, doc_date)
if existing:
if overwrite:
# Preserve existing file paths for reuse
existing_pdf_path = existing.pdf_path
existing_json_path = existing.json_path
# Delete existing document (cascade will delete related data)
# But DON'T delete files - we'll reuse or update them
self.session.delete(existing)
self.session.flush()
else:
raise DuplicateDocumentError(reference, doc_date)
if existing:
if overwrite:
# Preserve existing file paths for reuse
existing_pdf_path = existing.pdf_path
existing_json_path = existing.json_path
# Delete existing document (cascade will delete related data)
# But DON'T delete files - we'll reuse or update them
self.session.delete(existing)
self.session.flush()
else:
raise DuplicateDocumentError(reference, doc_date)
# Get or create immeuble
immeuble = self.get_or_create_immeuble(
@@ -223,23 +232,29 @@ class DatabaseService:
pdf_path = existing_pdf_path
json_path = existing_json_path
# Create document
document = Document(
reference=reference,
date=doc_date,
type=doc_info.get("type"),
source_file=source_file,
immeuble_id=immeuble.id,
json_data=json.dumps(data, ensure_ascii=False, default=str),
editeur_nom=editeur_info.get("nom"),
editeur_siret=editeur_info.get("siret"),
solde_montant=self._normalize_amount(solde_info.get("montant")),
solde_type=solde_info.get("type"),
solde_date_arrete=self._parse_date(solde_info.get("date_arrete")),
pdf_path=pdf_path,
json_path=json_path,
)
self.session.add(document)
# Create document (ou mise a jour sur place lors d'un remplacement)
fields = {
"reference": reference,
"date": doc_date,
"type": doc_info.get("type"),
"source_file": source_file,
"immeuble_id": immeuble.id,
"json_data": json.dumps(data, ensure_ascii=False, default=str),
"editeur_nom": editeur_info.get("nom"),
"editeur_siret": editeur_info.get("siret"),
"solde_montant": self._normalize_amount(solde_info.get("montant")),
"solde_type": solde_info.get("type"),
"solde_date_arrete": self._parse_date(solde_info.get("date_arrete")),
"pdf_path": pdf_path,
"json_path": json_path,
}
if reused is not None:
document = reused
for key, value in fields.items():
setattr(document, key, value)
else:
document = Document(**fields)
self.session.add(document)
self.session.flush()
# Save files to storage