feat: cache Ollama + parallélisation ThreadPool + filtrage DAS renforcé + modules GHM/CPAM/export RUM
- Cache persistant JSON thread-safe pour les résultats Ollama (invalidation par modèle) - Parallélisation des appels Ollama (ThreadPoolExecutor, 2 workers) - 6 nouvelles règles de filtrage DAS parasites (doublons, ponctuation, OCR, labo, fragments) - Client Ollama centralisé (mode JSON natif + retry) - Module GHM (estimation CMD/sévérité) - Module contrôle CPAM (parser + contre-argumentation RAG) - Export RUM (format RSS) - Viewer enrichi (détail dossier) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
130
tests/test_cpam_parser.py
Normal file
130
tests/test_cpam_parser.py
Normal file
@@ -0,0 +1,130 @@
|
||||
"""Tests pour le parser de contrôle CPAM."""
|
||||
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import openpyxl
|
||||
import pytest
|
||||
|
||||
from src.config import ControleCPAM
|
||||
from src.control.cpam_parser import match_dossier_ogc, parse_cpam_excel
|
||||
|
||||
|
||||
def _create_test_xlsx(rows: list[tuple], path: Path) -> None:
|
||||
"""Crée un fichier xlsx de test avec les lignes données."""
|
||||
wb = openpyxl.Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "OGC Contrôle T2A"
|
||||
ws.append(("N° OGC", "Titre", "Arg_UCR", "Décision_UCR", "DP_UCR", "DA_UCR", "DR_UCR", "Actes_UCR"))
|
||||
for row in rows:
|
||||
ws.append(row)
|
||||
wb.save(path)
|
||||
|
||||
|
||||
class TestParseCpamExcel:
|
||||
def test_parse_basic(self, tmp_path):
|
||||
xlsx = tmp_path / "test.xlsx"
|
||||
_create_test_xlsx([
|
||||
(17, "Désaccord sur les DAS", "Argument UCR...", "UCR retient", None, None, None, None),
|
||||
(21, "Désaccord sur le DP", "Autre argument", "UCR confirme avis", "K85.1", None, None, None),
|
||||
], xlsx)
|
||||
|
||||
result = parse_cpam_excel(xlsx)
|
||||
|
||||
assert 17 in result
|
||||
assert 21 in result
|
||||
assert len(result[17]) == 1
|
||||
assert len(result[21]) == 1
|
||||
assert result[17][0].titre == "Désaccord sur les DAS"
|
||||
assert result[17][0].decision_ucr == "UCR retient"
|
||||
assert result[21][0].dp_ucr == "K85.1"
|
||||
|
||||
def test_parse_multiple_same_ogc(self, tmp_path):
|
||||
xlsx = tmp_path / "test.xlsx"
|
||||
_create_test_xlsx([
|
||||
(17, "Titre 1", "Arg 1", "Décision 1", None, None, None, None),
|
||||
(17, "Titre 2", "Arg 2", "Décision 2", None, None, None, None),
|
||||
], xlsx)
|
||||
|
||||
result = parse_cpam_excel(xlsx)
|
||||
|
||||
assert len(result[17]) == 2
|
||||
|
||||
def test_parse_empty_file(self, tmp_path):
|
||||
xlsx = tmp_path / "empty.xlsx"
|
||||
_create_test_xlsx([], xlsx)
|
||||
|
||||
result = parse_cpam_excel(xlsx)
|
||||
|
||||
assert result == {}
|
||||
|
||||
def test_parse_nonexistent_file(self):
|
||||
result = parse_cpam_excel("/nonexistent/path.xlsx")
|
||||
assert result == {}
|
||||
|
||||
def test_parse_optional_fields(self, tmp_path):
|
||||
xlsx = tmp_path / "test.xlsx"
|
||||
_create_test_xlsx([
|
||||
(42, "Titre", "Arg", "Décision", "E11.40", "G63.2", "E11.9", "ABCD123"),
|
||||
], xlsx)
|
||||
|
||||
result = parse_cpam_excel(xlsx)
|
||||
|
||||
ctrl = result[42][0]
|
||||
assert ctrl.dp_ucr == "E11.40"
|
||||
assert ctrl.da_ucr == "G63.2"
|
||||
assert ctrl.dr_ucr == "E11.9"
|
||||
assert ctrl.actes_ucr == "ABCD123"
|
||||
|
||||
|
||||
class TestMatchDossierOGC:
|
||||
def setup_method(self):
|
||||
self.cpam_data = {
|
||||
17: [ControleCPAM(numero_ogc=17, titre="Test 17")],
|
||||
21: [ControleCPAM(numero_ogc=21, titre="Test 21")],
|
||||
}
|
||||
|
||||
def test_match_found(self):
|
||||
result = match_dossier_ogc("17_23100690", self.cpam_data)
|
||||
assert len(result) == 1
|
||||
assert result[0].numero_ogc == 17
|
||||
|
||||
def test_match_not_found(self):
|
||||
result = match_dossier_ogc("15_23096332", self.cpam_data)
|
||||
assert result == []
|
||||
|
||||
def test_match_no_prefix(self):
|
||||
result = match_dossier_ogc("nodash", self.cpam_data)
|
||||
assert result == []
|
||||
|
||||
def test_match_empty_data(self):
|
||||
result = match_dossier_ogc("17_23100690", {})
|
||||
assert result == []
|
||||
|
||||
|
||||
class TestControleCPAMModel:
|
||||
def test_serialization(self):
|
||||
ctrl = ControleCPAM(
|
||||
numero_ogc=17,
|
||||
titre="Désaccord sur les DAS",
|
||||
arg_ucr="Argument...",
|
||||
decision_ucr="UCR retient",
|
||||
dp_ucr="K85.1",
|
||||
)
|
||||
data = ctrl.model_dump()
|
||||
assert data["numero_ogc"] == 17
|
||||
assert data["dp_ucr"] == "K85.1"
|
||||
assert data["contre_argumentation"] is None
|
||||
|
||||
def test_deserialization(self):
|
||||
data = {
|
||||
"numero_ogc": 21,
|
||||
"titre": "Test",
|
||||
"arg_ucr": "Arg",
|
||||
"decision_ucr": "Décision",
|
||||
"contre_argumentation": "Ma réponse",
|
||||
}
|
||||
ctrl = ControleCPAM(**data)
|
||||
assert ctrl.numero_ogc == 21
|
||||
assert ctrl.contre_argumentation == "Ma réponse"
|
||||
assert ctrl.sources_reponse == []
|
||||
Reference in New Issue
Block a user