feat(signup+admin): aliniere formular signup la landing + plan cerut, GDPR, control tier/trial in panou

Signup:
- /signup aliniat ca format la formularul din landing (campuri, etichete,
  placeholder-uri, select plan, checkbox GDPR, buton). Eticheta `name` = "Companie"
  (corecta: backendul salveaza nume de firma), uniform si in landing.
- Consimtamant GDPR validat server-side (functional, nu doar client-side) + salvat
  cu marca temporala (accounts.consent_at).
- Plan ales la signup salvat in accounts.requested_plan (intentie, NU drept): tier
  ramane sursa de adevar pentru gate-ul API; coloana pregateste integrarea platilor.
- landing: valorile `plan` = coduri tier (free/standard/pro/premium), data-plan
  sincronizat pe butoanele de pret; checkbox consimtamant primeste name.

Schema/DB:
- accounts: coloane noi requested_plan + consent_at (cu migrare aditiva in db.py).

Panou admin:
- Coloane noi: Plan curent (plan EFECTIV acum + zile trial ramase) si Plan cerut.
- Buton "Aplica" (POST /admin/set-tier): aloca plan real si INCHEIE trial-ul
  (efect imediat; altfel trial-ul Pro universal de 30z masca alegerea).
- Control "Trial Pro N zile" (POST /admin/set-trial via accounts.set_trial):
  acorda/prelungeste trial fara a schimba tier-ul de baza.

Teste: signup (consent obligatoriu, requested_plan persistat, tier ramane free),
panou admin (set-tier incheie trial, free opreste Pro imediat, set-trial, validari
+ CSRF). Call-site-urile existente POST /signup actualizate cu consent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-06-29 16:02:37 +00:00
parent a29896a790
commit 851f76ca16
14 changed files with 528 additions and 42 deletions

View File

@@ -48,6 +48,7 @@ def test_signup_creeaza_cont_user_si_cheie(client):
"cui": "RO12345678",
"email": "test@example.com",
"parola": "parolasecreta",
"consent": "1",
"csrf_token": token,
})
assert resp.status_code == 200
@@ -87,6 +88,7 @@ def test_signup_email_duplicat_eroare(client):
"cui": make_test_cui("dup@example.com"),
"email": "dup@example.com",
"parola": "parolasecreta",
"consent": "1",
"csrf_token": token,
})
@@ -102,6 +104,7 @@ def test_signup_email_duplicat_eroare(client):
"cui": make_test_cui("dup-b@example.com"),
"email": "dup@example.com",
"parola": "altaparola123",
"consent": "1",
"csrf_token": token,
})
assert resp2.status_code in (200, 422)
@@ -139,6 +142,72 @@ def test_signup_parola_scurta_eroare(client):
conn.close()
def test_signup_fara_consent_eroare(client):
"""Consimtamant GDPR lipsa -> 422, fara creare cont; mesaj despre Termeni/GDPR.
Checkbox-ul de consimtamant trebuie validat server-side (functional, nu doar client-side):
fara el contul nu se creeaza si planul/datele introduse se pastreaza in re-render.
"""
from tests.conftest import make_test_cui
resp = client.get("/signup")
token = _csrf(resp.text)
resp = client.post("/signup", data={
"name": "Service Fara Consent",
"cui": make_test_cui("fara-consent@test.com"),
"email": "fara-consent@test.com",
"parola": "parolasecreta123",
# fara "consent"
"csrf_token": token,
})
assert resp.status_code == 422
assert "rfak_" not in resp.text
assert "GDPR" in resp.text or "Termeni" in resp.text
from app.db import get_connection
conn = get_connection()
try:
acct = conn.execute(
"SELECT * FROM accounts WHERE name='Service Fara Consent'"
).fetchone()
assert acct is None, "Cont creat desi consimtamantul lipsea"
finally:
conn.close()
def test_signup_salveaza_requested_plan_si_consent(client):
"""POST /signup cu plan ales -> accounts.requested_plan = codul ales, consent_at setat,
iar tier RAMANE 'free' (planul cerut NU acorda drepturi)."""
from tests.conftest import make_test_cui
resp = client.get("/signup")
token = _csrf(resp.text)
resp = client.post("/signup", data={
"name": "Service Plan Pro",
"cui": make_test_cui("plan-pro@test.com"),
"email": "plan-pro@test.com",
"parola": "parolasecreta123",
"plan": "pro",
"consent": "1",
"csrf_token": token,
})
assert resp.status_code == 200
assert "rfak_" in resp.text
from app.db import get_connection
conn = get_connection()
try:
acct = conn.execute(
"SELECT * FROM accounts WHERE name='Service Plan Pro'"
).fetchone()
assert acct is not None
assert acct["requested_plan"] == "pro", "Planul cerut nu a fost salvat"
assert acct["tier"] == "free", "tier NU trebuie urcat din planul cerut (doar dupa plata)"
assert acct["consent_at"], "consent_at trebuie setat la signup cu consimtamant"
finally:
conn.close()
def test_cheie_afisata_o_data(client):
"""Cheia rfak_ apare in raspunsul POST /signup; GET /signup nu o contine."""
from tests.conftest import make_test_cui
@@ -150,6 +219,7 @@ def test_cheie_afisata_o_data(client):
"cui": make_test_cui("cheie@test.com"),
"email": "cheie@test.com",
"parola": "parolasecreta",
"consent": "1",
"csrf_token": token,
})
assert resp_post.status_code == 200