feat(5.9): US-001 - eticheta umana scurta pe rand + cod brut pentru modal (R1)

- _submission_row_view expune eticheta_problema (motiv || eticheta_scurta), gol pe queued/sending/sent, fara decoder nou (R1 DRY)
- parse_erori expune cheia `cod` (cod brut catalog) pe ramurile imbogatite, pentru derivare in modal
- 5 teste US-001 in tests/test_web_submissions.py
- gates: tests PASS (819), /review (backend) PASS

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-06-24 21:17:53 +00:00
parent 0ba728cab5
commit 6d10f92452
5 changed files with 137 additions and 3 deletions

View File

@@ -195,6 +195,84 @@ def test_detaliu_trimitere(client):
assert "99001" in html # nr prezentare RAR
# ---------------------------------------------------------------------------
# US-001 (R1): eticheta umana scurta a problemei pe randul de tabel.
# Teste pure pe _submission_row_view — randarea sub pill e US-002.
# ---------------------------------------------------------------------------
def _fake_row(status: str, *, rar_error=None, id_prezentare=None, payload=None) -> dict:
"""Rand minimal compatibil cu _submission_row_view (acces prin chei)."""
return {
"id": 1,
"status": status,
"id_prezentare": id_prezentare,
"updated_at": "2026-06-24T10:00:00",
"rar_error": rar_error,
"payload_json": json.dumps(payload or {
"vin": "WVWZZZ1JZXW000777",
"nr_inmatriculare": "B777ZZZ",
"data_prestatie": "2026-06-18",
"odometru_final": "55000",
"prestatii": [{"cod_prestatie": "OE-2", "denumire": "Revizie"}],
}),
}
def test_eticheta_umana_sub_pill():
"""R1: randul expune `eticheta_problema` umana, reutilizand motiv (nu un nou decoder)."""
from app.web.routes import _submission_row_view
v = _submission_row_view(_fake_row(
"needs_data",
rar_error=json.dumps([{"field": "odometru_final", "message": "lipsa odometru"}]),
))
# Eticheta = text uman scurt, reutilizeaza motiv (ne-gol)
assert v["eticheta_problema"], "eticheta_problema ar trebui ne-goala pe needs_data"
assert v["eticheta_problema"] == v["motiv"]
# NU expune cod brut de catalog pe rand
assert "COD_" not in v["eticheta_problema"]
assert "RAR_EROARE" not in v["eticheta_problema"]
def test_eticheta_problema_prezenta_pe_error():
"""Eticheta ne-goala pe error chiar fara rar_error (fallback pe eticheta_scurta)."""
from app.web.routes import _submission_row_view
# error cu mesaj RAR
v_err = _submission_row_view(_fake_row(
"error", rar_error=json.dumps({"cod": "RAR_EROARE_SERVER", "problema": "Eroare server RAR"}),
))
assert v_err["eticheta_problema"] == "Eroare server RAR"
# error fara rar_error -> fallback ne-gol (eticheta scurta)
v_fb = _submission_row_view(_fake_row("error", rar_error=None))
assert v_fb["eticheta_problema"] == "Eroare"
def test_eticheta_problema_prezenta_pe_needs_mapping():
"""Eticheta ne-goala pe needs_mapping (stare cu problema)."""
from app.web.routes import _submission_row_view
v = _submission_row_view(_fake_row(
"needs_mapping",
rar_error=json.dumps({"unmapped": [{"cod_op_service": "OP-9", "denumire": "X"}]}),
))
assert v["eticheta_problema"]
assert "OP-9" in v["eticheta_problema"]
def test_eticheta_problema_goala_pe_rand_ok():
"""Eticheta este sir gol pe stari fara problema (queued/sending/sent)."""
from app.web.routes import _submission_row_view
for status in ("queued", "sending", "sent"):
v = _submission_row_view(_fake_row(status))
assert v["eticheta_problema"] == "", f"{status} ar trebui sa aiba eticheta goala"
def test_eticheta_problema_defensiva_json_invalid():
"""rar_error JSON corupt pe stare cu problema -> nu ridica, eticheta ne-goala."""
from app.web.routes import _submission_row_view
v = _submission_row_view(_fake_row("error", rar_error="{invalid json[[["))
assert isinstance(v["eticheta_problema"], str)
assert v["eticheta_problema"] # fallback garanteaza text ne-gol
def test_detaliu_trimitere_404_cross_account(client):
"""Detaliul altui cont -> 404 (fara leak)."""
acct1 = _create_account_user("d1@test.com", name="C1")