feat(api): validare cod_prestatie la nomenclator + optiune on_unmapped_error

Cod_prestatie necunoscut in nomenclator nu se mai trimite raw la RAR (HTTP 500
ORA-12899 + record partial FINALIZATA pe care reconcilierea il marca fals sent):
e promovat la cod_op_service si tratat ca operatie de mapat.

Optiune top-level boolean on_unmapped_error pe POST /v1/prezentari + /valideaza:
  - false (default) -> submission needs_mapping (intra in editor)
  - true            -> respinge fara enqueue (status error, submission_id=null, erori)
  - None            -> default per-cont accounts.on_unmapped_error_default (implicit 0)
Inlocuieste enum-ul anterior on_unmapped (needs_mapping/error) cu un boolean mai
simplu; coloana de cont migrata aditiv la INTEGER on_unmapped_error_default.

Izolare teste de .env-ul de dezvoltare: tests/conftest.py fixeaza default sigur
pe AUTOPASS_REQUIRE_API_KEY / AUTOPASS_WORKER_USE_TEST_CREDS (precedenta peste
.env in pydantic-settings) + fixturile env din test_creds_delivery/test_t1 pineaza
explicit aceste flag-uri, ca fallback-ul creds pe cont sa fie atins.

Teste: 752 passed (fara flag pe CLI).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-06-23 19:35:47 +00:00
parent c842e3352a
commit 6bad6bc01e
17 changed files with 376 additions and 23 deletions

View File

@@ -68,6 +68,46 @@ def test_resolve_op_nemapata_iese_in_unmapped():
assert unmapped == [{"cod_op_service": "9999", "denumire": "Operatie noua"}]
def test_resolve_cod_valid_cu_nomenclator_trece():
"""cod_prestatie in nomenclator -> pastrat (validare activa)."""
resolved, unmapped = resolve_prestatii([{"cod_prestatie": "oe-1"}], {}, valid_codes={"OE-1"})
assert resolved[0]["cod_prestatie"] == "OE-1"
assert unmapped == []
def test_resolve_cod_necunoscut_devine_unmapped():
"""cod_prestatie NECUNOSCUT in nomenclator -> promovat la cod_op_service + needs_mapping.
Regresie pentru bug-ul real: un cod intern in cod_prestatie (ex. 'DIVERSE
VERIFICARI 159002') NU trebuie trimis raw la RAR (HTTP 500 + record partial).
"""
resolved, unmapped = resolve_prestatii(
[{"cod_prestatie": "DIVERSE VERIFICARI 159002"}], {}, valid_codes={"OE-1", "R-ODO"}
)
assert resolved[0]["cod_prestatie"] is None
assert resolved[0]["cod_op_service"] == "DIVERSE VERIFICARI 159002" # promovat
assert unmapped == [{"cod_op_service": "DIVERSE VERIFICARI 159002",
"denumire": "DIVERSE VERIFICARI 159002"}]
def test_resolve_cod_necunoscut_cu_mapare_se_rezolva():
"""Dupa ce codul necunoscut a fost mapat, se rezolva la codul RAR (re-rezolvare)."""
resolved, unmapped = resolve_prestatii(
[{"cod_prestatie": "DIVERSE VERIFICARI 159002"}],
{"DIVERSE VERIFICARI 159002": "OE-1"},
valid_codes={"OE-1"},
)
assert resolved[0]["cod_prestatie"] == "OE-1"
assert unmapped == []
def test_resolve_fara_valid_codes_e_backcompat():
"""valid_codes=None -> validarea dezactivata: cod direct trece neatins (compat)."""
resolved, unmapped = resolve_prestatii([{"cod_prestatie": "ORICE-COD"}], {})
assert resolved[0]["cod_prestatie"] == "ORICE-COD"
assert unmapped == []
# --------------------------------------------------------------------------- #
# Flux complet (API) #
# --------------------------------------------------------------------------- #
@@ -163,6 +203,75 @@ def test_item_fara_cod_si_fara_op_e_422(client):
assert r.status_code == 422
# --------------------------------------------------------------------------- #
# Cod_prestatie necunoscut in nomenclator + optiunea on_unmapped #
# (RAR accepta NUMAI coduri din nomenclator; cod necunoscut -> 500 + record #
# partial. Gateway-ul nu-l mai trimite raw.) #
# --------------------------------------------------------------------------- #
_COD_INTERN = "DIVERSE VERIFICARI 159002" # >5 car., nu e in nomenclator
def test_cod_prestatie_necunoscut_da_needs_mapping(client):
"""Default: cod_prestatie necunoscut -> needs_mapping, apare in pending pentru mapare."""
r = client.post("/v1/prezentari", json=_body([{"cod_prestatie": _COD_INTERN}]))
assert r.status_code == 200
assert r.json()["results"][0]["status"] == "needs_mapping"
pend = client.get("/v1/mapari/pending").json()["pending"]
assert len(pend) == 1
assert pend[0]["cod_op_service"] == _COD_INTERN # promovat din cod_prestatie
def test_cod_necunoscut_mapat_se_trimite(client):
"""Flux complet: cod necunoscut -> needs_mapping -> mapezi -> queued."""
client.post("/v1/prezentari", json=_body([{"cod_prestatie": _COD_INTERN}]))
r = client.post("/v1/mapari", json={"cod_op_service": _COD_INTERN, "cod_prestatie": "OE-1", "auto_send": True})
assert r.json()["reresolve"]["requeued"] == 1
subs = client.get("/v1/prezentari", params={"status": "queued"}).json()["submissions"]
assert len(subs) == 1
def test_on_unmapped_error_respinge_fara_enqueue(client):
"""on_unmapped_error=True per-cerere: cod necunoscut -> status error, fara submission."""
body = _body([{"cod_prestatie": _COD_INTERN}])
body["on_unmapped_error"] = True
r = client.post("/v1/prezentari", json=body)
assert r.status_code == 200
res = r.json()["results"][0]
assert res["status"] == "error"
assert res["submission_id"] is None
assert res["erori"] and res["erori"][0]["cod"] == "COD_NEMAPAT"
# Nu s-a creat nimic in coada.
assert client.get("/v1/prezentari").json()["submissions"] == []
def test_on_unmapped_default_cont_error(client):
"""Default per-cont (on_unmapped_error_default=1) se aplica cand cererea nu specifica optiunea."""
from app.db import get_connection
conn = get_connection()
conn.execute("UPDATE accounts SET on_unmapped_error_default=1 WHERE id=1")
conn.commit()
conn.close()
r = client.post("/v1/prezentari", json=_body([{"cod_prestatie": _COD_INTERN}]))
res = r.json()["results"][0]
assert res["status"] == "error" and res["submission_id"] is None
# Override per-cerere bate default-ul de cont:
body = _body([{"cod_prestatie": _COD_INTERN}], vin="WVWZZZ1KZAW000999")
body["on_unmapped_error"] = False
r2 = client.post("/v1/prezentari", json=body)
assert r2.json()["results"][0]["status"] == "needs_mapping"
def test_valideaza_error_mode(client):
"""Dry-run reflecta modul error: status_estimat='error' pentru cod necunoscut."""
body = _body([{"cod_prestatie": _COD_INTERN}])
body["on_unmapped_error"] = True
r = client.post("/v1/prezentari/valideaza", json=body)
assert r.status_code == 200
res = r.json()["results"][0]
assert res["status_estimat"] == "error" and res["valid"] is False
# --------------------------------------------------------------------------- #
# US-003: 3 niveluri in classify_prezentare (needs_mapping) #
# --------------------------------------------------------------------------- #