feat(T2): reconciliere anti-duplicat + retry/backoff + recuperare orfane
Inchide bucla de trimitere (plan.md sect. 4 worker, failure registry).
- app/reconcile.py: match_finalizata pe vin+dataPrestatie+odometruFinal (int),
alege id maxim la duplicate (RAR accepta duplicate, confirmat live)
- app/rar_client.get_finalizate: parseaza data.content (descoperit live ca
ruta = GET /prezentari/getAllPrezentariFinalizate; filtrele nu merg pe test)
- app/worker rescris:
- recuperare orfane (rand 'sending' peste lease = worker mort mid-POST)
- pe eroare tranzitorie/timeout: reconciliere INAINTE de re-send (anti-duplicat);
daca recordul exista la RAR -> sent fara re-POST
- retry/backoff exponential; peste worker_max_retries -> error + banner
- re-login la token expirat (JWT 30h)
- schema: coloana next_attempt_at (backoff) + migrare aditiva in init_db
- config: worker_sending_lease_s, worker_retry_base_s/max_s, worker_max_retries
- contract: documentata ruta+forma getAllPrezentariFinalizate (verificat live)
Verify: pytest 54 passed (15 noi T2) + validare live (reconciliere record 68514).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -211,12 +211,34 @@ Aplicate deja pe ambele medii (test + producție):
|
||||
- Corecția datelor eronate (după FINALIZATA) = solicitare la **suport.autopass@rarom.ro**
|
||||
(pe test nu e cazul). **Nu există flux API de corecție/anulare pentru records-urile noastre.**
|
||||
|
||||
## Monitorizare (citire prezentări)
|
||||
## Monitorizare (citire prezentări) — VERIFICAT LIVE 2026-06-15
|
||||
|
||||
- Pe **mediul de test**: la interogarea listei de prezentări finalizate **NU primești și `prestatii`** în răspuns.
|
||||
- Pe **producție**: prestațiile sunt disponibile; lista poate fi filtrată după keyword / interval
|
||||
de date și exportată în Excel.
|
||||
- Implicație dashboard: nu te baza pe `prestatii` din listă pe test; le ai în `submissions` local.
|
||||
**Rută:** `GET /prezentari/getAllPrezentariFinalizate` (Bearer). Confirmat live.
|
||||
**Răspuns:** `{statusCode, message, data: {totalCount, content: [...]}}` — listă în `data.content`.
|
||||
|
||||
Fiecare item din `content` (live):
|
||||
```json
|
||||
{
|
||||
"id": 68514, "dataPrestatie": "2026-06-15", "vin": "WVWZZZ1KZAW000123",
|
||||
"odometruFinal": 123456, "idAgent": 40, "tipPrestatie": null,
|
||||
"odometruInitial": null, "idUser": 6766, "sistemReparat": null, "obs": "...",
|
||||
"nrInmatriculare": "B999TST", "listaPrestatii": null, "status": "FINALIZATA",
|
||||
"prestatii": null, "b64Image": null
|
||||
}
|
||||
```
|
||||
|
||||
- **`odometruFinal` e NUMĂR** (int) în listare (deși la `postPrezentare` se trimite string). Reconcilierea
|
||||
compară ca int.
|
||||
- Pe **test**: `prestatii` vine `null` (confirmă: nu te baza pe `prestatii` din listă — le ai local în `submissions`).
|
||||
- **Filtrele NU funcționează pe test**: `?vin=`, `?search=`, `?keyword=`, `?dataPrestatie=` sunt IGNORATE
|
||||
(întorc tot setul). `?page=&size=` rup răspunsul (non-JSON). → **fetch tot setul, filtrează client-side.**
|
||||
Pe prod doc-ul promite filtrare keyword/dată + export Excel (de re-verificat pe prod).
|
||||
- **RAR acceptă DUPLICATE**: live există 2 perechi de records identice pe `vin+dataPrestatie+odometruFinal`
|
||||
(id 63622≡63625, 63623≡63626). De aceea reconcilierea pe răspuns pierdut e necesară, iar matcher-ul
|
||||
alege **id-ul maxim** când există mai multe potriviri.
|
||||
|
||||
> Reconciliere (T2): înainte de re-send pe un rând `sending`, GET finalizate, match pe
|
||||
> `vin + dataPrestatie + odometruFinal(int)`; dacă există → marchează `sent` cu id-ul găsit, NU re-trimite.
|
||||
|
||||
## Corecții față de `docs/plans/*` (citește înainte de a refolosi planurile)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user