Files
pdf_oralia_vibe/tests/test_lots.py
Bertrand Benjamin ea5bdac18a refactor: retire les parseurs texte de repli
Les parseurs géométriques (par cellules de tableau) traitent les 5 PDF du
corpus sans jamais déclencher le repli : les parseurs texte étaient 586
lignes de regex fragiles, non testées, à maintenir à chaque évolution du
format de sortie. Les références golden sont inchangées après leur
suppression — l'extraction produit exactement la même chose.

Le parseur géométrique devient donc le seul chemin : ce qu'il ne lit pas
est perdu. L'orchestrateur distingue maintenant les deux cas :

- aucun lot lu -> ExtractionError (422 côté API). Un compte rendu sans
  lot n'existe pas : c'est le tableau qui n'a pas été reconnu, et mieux
  vaut échouer que d'enregistrer un document vide découvert bien plus
  tard, au moment de relire les chiffres ;
- aucune opération -> accepté. Un mois sans dépense reste plausible.

_extract_lot_code_from_description était la seule fonction encore
utilisée : elle rejoint utils.lots sous le nom
extract_lot_numero_from_description, à côté de normalize_lot_numero.
extract_text_from_pdf, sans appelant, disparaît au passage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 09:44:20 +02:00

125 lines
3.7 KiB
Python

"""Tests de la normalisation des numéros de lot."""
import pytest
from plesna_gerance.utils.lots import (
extract_lot_numero_from_description,
normalize_extraction_lots,
normalize_lot_numero,
)
@pytest.mark.parametrize(
"raw,expected",
[
("0006", "06"),
("06", "06"),
("6", "06"),
(6, "06"),
("0020", "20"),
("20", "20"),
("Lot 6", "06"),
(" 7 ", "07"),
("0000", "00"),
("0", "00"),
# Plus de 2 chiffres significatifs : on ne tronque pas
("0123", "123"),
# Rien d'exploitable
(None, None),
("", None),
("abc", None),
],
)
def test_normalize_lot_numero(raw, expected):
assert normalize_lot_numero(raw) == expected
@pytest.mark.parametrize(
"description,expected",
[
("M06 - Commande moteur pompe", "06"),
("S05 - Mise en service", "05"),
("B01 - Plaques", "01"),
("S10 - Reparation", "10"),
("S 17 - Espace dans le code", "17"),
("S01 SOLDE LOCATAIRE", "01"),
("Nettoyage immeuble", None),
("", None),
],
)
def test_extract_lot_numero_from_description(description, expected):
assert extract_lot_numero_from_description(description) == expected
def test_normalize_extraction_lots():
data = {
"situation_locataires": [
{"lot": {"numero": "0006", "type": "Appartement T3"}},
{"lot": {"numero": "7", "type": "Studio"}},
{"lot": {"numero": None, "type": "Garage"}},
],
"recapitulatif_operations": [
{"lot_numero": "0013"},
{"lot_numero": "1"},
{"lot_numero": None},
],
}
normalize_extraction_lots(data)
assert [s["lot"]["numero"] for s in data["situation_locataires"]] == [
"06",
"07",
None,
]
assert [o["lot_numero"] for o in data["recapitulatif_operations"]] == [
"13",
"01",
None,
]
def test_normalize_extraction_lots_tolerates_missing_sections():
# Une extraction partielle ne doit pas lever
assert normalize_extraction_lots({}) == {}
assert normalize_extraction_lots({"situation_locataires": None}) == {
"situation_locataires": None
}
def test_get_or_create_lot_deduplicates_formats(db_session):
""""0006", "06" et "6" désignent le même lot : un seul enregistrement."""
from plesna_gerance.database.models import Immeuble, Lot
from plesna_gerance.database.service import DatabaseService
service = DatabaseService(db_session)
immeuble = service.get_or_create_immeuble(code="IMM1")
lots = [
service.get_or_create_lot(immeuble_id=immeuble.id, numero=numero)
for numero in ("0006", "06", "6")
]
assert {lot.id for lot in lots} == {lots[0].id}
assert lots[0].numero == "06"
assert db_session.query(Lot).filter_by(immeuble_id=immeuble.id).count() == 1
assert db_session.query(Immeuble).count() == 1
def test_save_document_normalizes_lot_numero(db_session, sample_data):
from plesna_gerance.database.models import Lot
from plesna_gerance.database.service import DatabaseService
sample_data["situation_locataires"][0]["lot"]["numero"] = "0001"
sample_data["recapitulatif_operations"][0]["lot_numero"] = "1"
service = DatabaseService(db_session)
doc = service.save_document(data=sample_data)
# Le lot du locataire et celui de l'opération sont le même
assert db_session.query(Lot).count() == 1
assert db_session.query(Lot).first().numero == "01"
# Le JSON persisté est normalisé lui aussi
assert '"numero": "01"' in doc.json_data
assert '"lot_numero": "01"' in doc.json_data