feat(errors): erori pe 3 niveluri (problema+cauza+fix) pe API si UI (PRD 5.4)
Catalog central pur app/errors.py ca sursa unica cod->{problema,fix},
consumat de API+UI+worker. Aditiv (field/message pastrate la octet) +
rar_error stocat superset. Scope: fluxul de declarare; login/signup/CSRF
neatinse. labels.parse_erori degradeaza gratios; UI progresiv AA light+dark.
631 teste.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
203
app/errors.py
Normal file
203
app/errors.py
Normal file
@@ -0,0 +1,203 @@
|
||||
"""Catalog central de erori AutoPass (PRD 5.4).
|
||||
|
||||
Singura sursa de adevar care mapeaza fiecare cod de eroare la (problema, fix),
|
||||
cu un helper care construieste obiectul de eroare pe 3 niveluri:
|
||||
- nivel 1 (tehnic): `cod` + `cauza` — ce s-a intamplat exact
|
||||
- nivel 2 (utilizator): `problema` — descriere scurta, inteligibila
|
||||
- nivel 3 (actiune): `fix` — ce trebuie facut pentru a remedia
|
||||
|
||||
Modul PUR — fara import DB sau HTTP.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CATALOG
|
||||
# cheie = cod (string), valoare = {"problema": str, "fix": str}
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
CATALOG: dict[str, dict[str, str]] = {
|
||||
"VIN_FORMAT": {
|
||||
"problema": "VIN invalid",
|
||||
"fix": (
|
||||
"Verifica VIN-ul pe talon (pozitia E) sau pe caroserie: exact 17 caractere"
|
||||
" majuscule, fara spatii si fara literele O, I, Q."
|
||||
),
|
||||
},
|
||||
"NR_INMATRICULARE_FORMAT": {
|
||||
"problema": "Numar de inmatriculare invalid",
|
||||
"fix": (
|
||||
"Foloseste doar litere si cifre majuscule, maxim 10 caractere, fara spatii"
|
||||
" sau cratima (ex. B123ABC)."
|
||||
),
|
||||
},
|
||||
"DATA_FORMAT": {
|
||||
"problema": "Data prestatiei in format gresit",
|
||||
"fix": "Scrie data ca AAAA-LL-ZZ (ex. 2026-06-22).",
|
||||
},
|
||||
"DATA_PREA_VECHE": {
|
||||
"problema": "Data prestatiei prea veche",
|
||||
"fix": (
|
||||
"RAR accepta prestatii doar incepand cu 01.12.2024;"
|
||||
" verifica data prestatiei."
|
||||
),
|
||||
},
|
||||
"DATA_VIITOR": {
|
||||
"problema": "Data prestatiei in viitor",
|
||||
"fix": "Data prestatiei nu poate fi dupa ziua de azi; corecteaza data.",
|
||||
},
|
||||
"ODOMETRU_FINAL_FORMAT": {
|
||||
"problema": "Odometru final invalid",
|
||||
"fix": (
|
||||
"Scrie kilometrajul final ca numar intreg, fara zecimale sau text"
|
||||
" (ex. 145000)."
|
||||
),
|
||||
},
|
||||
"ODOMETRU_INITIAL_LIPSA": {
|
||||
"problema": "Lipseste odometrul initial",
|
||||
"fix": (
|
||||
"Prestatiile R-ODO / I-ODO cer kilometrajul initial; completeaza-l."
|
||||
),
|
||||
},
|
||||
"ODOMETRU_INITIAL_FORMAT": {
|
||||
"problema": "Odometru initial invalid",
|
||||
"fix": (
|
||||
"Scrie kilometrajul initial ca numar intreg, fara zecimale sau text."
|
||||
),
|
||||
},
|
||||
"ODOMETRU_INITIAL_ORDINE": {
|
||||
"problema": "Odometru initial mai mare decat finalul",
|
||||
"fix": (
|
||||
"Kilometrajul initial trebuie sa fie mai mic sau egal cu cel final;"
|
||||
" verifica cele doua valori."
|
||||
),
|
||||
},
|
||||
"PRESTATII_GOALE": {
|
||||
"problema": "Nicio prestatie",
|
||||
"fix": "Adauga cel putin o prestatie cu cod RAR valid.",
|
||||
},
|
||||
"B64_INVALID": {
|
||||
"problema": "Imaginea nu este base64 valid",
|
||||
"fix": (
|
||||
"Trimite imaginea codata base64 corect, sau omite campul daca nu ai imagine."
|
||||
),
|
||||
},
|
||||
"COD_NEMAPAT": {
|
||||
"problema": "Lipseste codul RAR al operatiei",
|
||||
"fix": (
|
||||
"Alege codul RAR pentru aceasta operatie in tab-ul Mapari"
|
||||
" (ai sugestii automate)."
|
||||
),
|
||||
},
|
||||
"AUTO_SEND_OPRIT": {
|
||||
"problema": "Necesita confirmare manuala",
|
||||
"fix": (
|
||||
"Codul e mapat cu trimitere automata oprita; verifica randul si"
|
||||
" pune-l manual in coada."
|
||||
),
|
||||
},
|
||||
"RAR_VALIDARE": {
|
||||
"problema": "RAR a respins prezentarea",
|
||||
"fix": (
|
||||
"Corecteaza campul semnalat de RAR (vezi cauza) si reincearca;"
|
||||
" detaliile exacte sunt in mesajul tehnic RAR."
|
||||
),
|
||||
},
|
||||
"RAR_CREDS_INVALIDE": {
|
||||
"problema": "Credentiale RAR invalide",
|
||||
"fix": (
|
||||
"Verifica email-ul si parola contului RAR in tab-ul Cont;"
|
||||
" trimiterea nu se reincearca automat la credentiale gresite."
|
||||
),
|
||||
},
|
||||
"IMPORT_FISIER_PREA_MARE": {
|
||||
"problema": "Fisier prea mare",
|
||||
"fix": (
|
||||
"Imparte fisierul in bucati de maxim 5000 de randuri si incarca-le pe rand."
|
||||
),
|
||||
},
|
||||
"IMPORT_ANTET_NECLAR": {
|
||||
"problema": "Antet de coloane neclar",
|
||||
"fix": (
|
||||
"Asigura-te ca primul rand contine numele coloanelor"
|
||||
" (ex. VIN, Numar, Data)."
|
||||
),
|
||||
},
|
||||
"IMPORT_ENCODING": {
|
||||
"problema": "Codare de caractere nesuportata",
|
||||
"fix": "Salveaza fisierul ca CSV UTF-8 (sau xlsx) si reincarca.",
|
||||
},
|
||||
"IMPORT_FISIER_NERECUNOSCUT": {
|
||||
"problema": "Fisier nerecunoscut",
|
||||
"fix": "Incarca un fisier .xlsx sau .csv valid.",
|
||||
},
|
||||
"IMPORT_MULTIPLE_SHEETS": {
|
||||
"problema": "Mai multe foi in fisier",
|
||||
"fix": "Pastreaza datele intr-o singura foaie sau alege foaia de import.",
|
||||
},
|
||||
"IMPORT_FARA_MAPARE_COLOANE": {
|
||||
"problema": "Coloanele nu sunt mapate",
|
||||
"fix": (
|
||||
"Mapeaza intai coloanele fisierului la campurile cerute, apoi continua."
|
||||
),
|
||||
},
|
||||
"IMPORT_CONFIRMARE_GRESITA": {
|
||||
"problema": "Numar confirmat gresit",
|
||||
"fix": (
|
||||
"Numarul confirmat difera de randurile gata de trimis;"
|
||||
" verifica preview-ul si reconfirma."
|
||||
),
|
||||
},
|
||||
"IMPORT_OVERRIDE_ILIZIBIL": {
|
||||
"problema": "Editarea anterioara nu se poate citi",
|
||||
"fix": (
|
||||
"Editarea salvata este ilizibila (probabil cheia s-a schimbat);"
|
||||
" reediteaza randul."
|
||||
),
|
||||
},
|
||||
"COLOANE_FORMAT_JSON": {
|
||||
"problema": "Format de coloane (JSON) invalid",
|
||||
"fix": (
|
||||
"Verifica sintaxa JSON a maparii de coloane"
|
||||
" (ghilimele duble, acolade inchise corect)."
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# eroare()
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def eroare(
|
||||
cod: str,
|
||||
*,
|
||||
field: str | None = None,
|
||||
cauza: str | None = None,
|
||||
) -> dict:
|
||||
"""Construieste un obiect de eroare pe 3 niveluri din CATALOG.
|
||||
|
||||
Parametri
|
||||
---------
|
||||
cod: Codul de eroare (cheie in CATALOG). Ridica KeyError daca absent.
|
||||
field: Campul care a generat eroarea (optional, pentru context).
|
||||
cauza: Descrierea tehnica a erorii concrete (optional).
|
||||
Daca lipseste, `cauza` si `message` preiau valoarea `problema` din catalog.
|
||||
|
||||
Returneaza
|
||||
----------
|
||||
dict cu exact cheile: field, cod, problema, cauza, fix, message.
|
||||
"""
|
||||
entry = CATALOG[cod] # ridica KeyError daca cod absent
|
||||
problema = entry["problema"]
|
||||
fix = entry["fix"]
|
||||
cauza_efectiva = cauza if cauza is not None else problema
|
||||
message = cauza if cauza is not None else problema
|
||||
return {
|
||||
"field": field,
|
||||
"cod": cod,
|
||||
"problema": problema,
|
||||
"cauza": cauza_efectiva,
|
||||
"fix": fix,
|
||||
"message": message,
|
||||
}
|
||||
Reference in New Issue
Block a user