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

@@ -280,8 +280,17 @@ Campul `detail` din raspunsurile de eroare este superset: contine cheile vechi `
| Cod | Problema | Fix |
|---|---|---|
| `RAR_VALIDARE` | RAR a respins prezentarea | Corecteaza campul semnalat de RAR (vezi cauza) si reincearca; detaliile exacte sunt in mesajul tehnic RAR. |
| `RAR_EROARE_SERVER` | RAR a esuat la inregistrarea prezentarii | RAR a raspuns cu o eroare de server (vezi cauza). Trimiterea NU se reincearca automat si NU a fost confirmata — verifica datele (in special codul prestatiei) si re-trimite dupa corectare. |
| `RAR_CREDS_INVALIDE` | Credentiale RAR invalide | Verifica email-ul si parola contului RAR in tab-ul Cont; trimiterea nu se reincearca automat la credentiale gresite. |
> **Clasificarea esecurilor RAR la `postPrezentare` (worker).** Un **400** -> `needs_data`
> (validare continut). Un **500 cu corp de eroare** (`{statusCode,message}`, ex. `ORA-12899`)
> e un esec DEFINITIV: RAR a raspuns „am esuat", deci NU e o pierdere de raspuns ambigua
> -> worker-ul marcheaza `error` (`RAR_EROARE_SERVER`), **fara reconciliere si fara retry**
> (altfel ar marca fals `sent` pe un record PARTIAL pe care RAR, ne-tranzactional, il lasa
> la esec). Doar erorile **ambigue** — timeout / TransportError / 502/503/504 / 429 / 408 —
> declanseaza reconcilierea anti-duplicat + retry cu backoff.
#### Import fisier
| Cod | Problema | Fix |
@@ -393,7 +402,7 @@ Aceasta e suprafata **gateway-ului**, nu RAR. Un item din `prestatii` la
| Camp item | Note |
|---|---|
| `cod_prestatie` | cod RAR direct (ex. `OE-1`). Trece neatins -> validare T3 -> coada. |
| `cod_prestatie` | cod RAR direct (ex. `OE-1`). **Validat fata de nomenclator** -> validare T3 -> coada. Cod NECUNOSCUT in nomenclator e tratat ca operatie de mapat (vezi mai jos). |
| `cod_op_service` | cod intern ROAAUTO. Gateway-ul il traduce in cod RAR prin `operations_mapping`. |
| `denumire` | denumirea operatiei ROAAUTO; folosita pentru fuzzy lookup in editor. |
@@ -404,6 +413,23 @@ web. La salvarea maparii, submission-urile blocate pe acel cod se re-rezolva aut
rezolvat se scrie inapoi in `payload_json`, deci payload builder + worker raman
code-driven.
**Validare `cod_prestatie` la ingestie (2026-06-23).** RAR accepta NUMAI coduri din
nomenclator: coloana `COD_PRESTATIE` are max 5 caractere si un cod necunoscut
intoarce **HTTP 500** (`ORA-12899`) — confirmat live. Periculos: RAR NU e tranzactional
si lasa un **record partial** (`FINALIZATA`, terminal) chiar cand apelul esueaza, iar
reconcilierea worker-ului il poate marca fals `sent`. De aceea gateway-ul NU mai trimite
un `cod_prestatie` care nu e in nomenclator: il promoveaza la `cod_op_service` (cu
`denumire`=cod, pentru fuzzy) si il trateaza ca operatie de mapat.
**Optiunea `on_unmapped_error`** (camp boolean top-level optional pe `POST /v1/prezentari`
si `/v1/prezentari/valideaza`) controleaza ce se intampla la cod necunoscut/nemapat:
- `false` (default) — submission `needs_mapping`, apare in editor (non-distructiv);
- `true` — respinge fara enqueue: `SubmissionResult` cu `status="error"`,
`submission_id=null`, `erori=[COD_NEMAPAT...]`.
Cand campul lipseste se aplica default-ul contului (`accounts.on_unmapped_error_default`,
implicit `false`/`0`). Override per-cerere > default cont > `false`.
Endpointuri noi:
- `GET /v1/mapari/pending` — operatii nemapate distincte + sugestii fuzzy (`{cod_prestatie, nume_prestatie, score}`).
- `POST /v1/mapari` `{account_id?, cod_op_service, cod_prestatie, auto_send}` — upsert mapare + re-rezolvare. Respinge `cod_prestatie` inexistent in nomenclator (422).