PRD 5.16 — propagare design finalizata (system font stack, fara IBM Plex self-hostat): - US-001/002/008: tokeni --font-ui/--font-mono (system stack) + scala --fs-*; zero @font-face si zero /static/fonts/; landing aliniat la acelasi stack - US-003: RAR online = dot compact in antet + meniu burger; banda rosie DOAR pe blocat (invariant zero-silent-failures pastrat) - US-010: antet "ROMFAST AUTOPASS" + nume service + /login brandeit 2 coloane + badge plan; meniu burger cu separatoare; gate strict pe is_authenticated - US-011: selector tema pill icon+eticheta (reuse THEMES) - US-004/005/006/007: bug-fix editor prestatii (picker cod+denumire, add_extra in mod operatii, cod ales se salveaza fara "+", Renunta inchide via closest) - US-012/013: landing Autentificare->/login; wizard import colapsat + 4 pasi pe tokeni - fix VERIFY E2E: contoare duplicate pe 390px (inline display:flex batea @media) -> CSS + test-lock PRD 5.17 — tipuri de cont + trial Pro 30z + enforcement DUR: - US-001/002/008: accounts.tier + trial_until (migrare aditiva defensiva); app/plans.py sursa unica (PLANS, FREE_MONTHLY_LIMIT=60, effective_tier(now injectabil), monthly_usage, CONSUMED_STATUSES); create_account trial Pro 30z; CLI set-tier (protejat id=1, audit) - US-003/004/005: enforce volum 60/luna INAINTE de build_key pe ambele canale (PLAN_LIMITA_LUNARA, 3 niveluri + log_event); gate API Pro+ (PLAN_FARA_API 403 actionabil); valideaza/nomenclator raman permise; downgrade lazy; flag AUTOPASS_ENFORCE_PLANS (kill-switch) - US-006: badge plan antet + linie burger + consum N/60 + warn>=80% + 6 stari + copy RO pluralizat + banner one-time trial->Gratuit + pagina Cont Regresie: 1380 passed, 0 failed, 1 deselected (live). E2E browser pe 390/1280 confirmat. Backend trimitere (worker/masina stari/idempotenta/contract RAR) NEATINS. Lucrul 5.18 (corpus kNN) ramane separat, necomis. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
236 lines
8.1 KiB
Python
236 lines
8.1 KiB
Python
"""Catalog central de erori AutoPass.
|
|
|
|
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_EROARE_SERVER": {
|
|
"problema": "RAR a esuat la inregistrarea prezentarii",
|
|
"fix": (
|
|
"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": {
|
|
"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_INTERNA": {
|
|
"problema": "Eroare interna a gateway-ului",
|
|
"fix": (
|
|
"Nu e o problema de date trimise de tine. Reincearca peste cateva"
|
|
" momente; daca persista, contacteaza administratorul cu identificatorul"
|
|
" cererii (request_id) afisat."
|
|
),
|
|
},
|
|
# Coduri de plan (PRD 5.17)
|
|
"PLAN_LIMITA_LUNARA": {
|
|
"problema": "Ai atins limita planului Gratuit (60 prestatii/luna)",
|
|
"fix": (
|
|
"Treci pe planul Standard sau Pro, sau asteapta inceperea lunii urmatoare."
|
|
" Numarul de prestatii ramase in luna curenta e in campul cauza."
|
|
),
|
|
},
|
|
"PLAN_FARA_API": {
|
|
"problema": "Importul prin API e disponibil pe planul Pro",
|
|
"fix": (
|
|
"Planul tau curent nu include accesul la API."
|
|
" Endpoint-ul /v1/prezentari/valideaza ramane disponibil pentru testare fara upgrade."
|
|
" Contacteaza-ne pentru a face upgrade la planul Pro."
|
|
),
|
|
},
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 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,
|
|
}
|