QR-Stats: Registrierungen (bestätigt) vs. Versuche (unbestätigt) + Account-Detail-Liste

Rene: Statistik zählte alles in einen Topf (3 statt 2) und zeigte nicht,
WER sich registriert hat. Jetzt:
- registrations = email_verified=1, attempts = unbestätigte Versuche —
  Versuche werden bei späterer Bestätigung automatisch zu Registrierungen
- Admin: 👥-Button pro Kontingent klappt Account-Liste auf (Name, E-Mail,
  Datum, ✓ bestätigt/ Versuch, Sticker-Nr #seq) — lazy geladen, admin-only
  (personenbezogene Daten); Partner sehen weiter nur Zahlen (Registr. +N)
- Test deckt Versuch→Bestätigung-Übergang und Detail-Endpoint ab
This commit is contained in:
rene 2026-06-07 18:43:18 +02:00
parent f604ab7c4f
commit 970480c1d6
9 changed files with 110 additions and 26 deletions

View file

@ -63,7 +63,7 @@ def test_scan_redirects_and_counts(client, admin):
def test_registration_attributed_to_qr(client, admin):
"""Registrierung mit ref+qr -> users.referred_qr gesetzt, Kontingent-Stats zaehlen."""
"""Registrierung mit ref+qr -> referred_qr gesetzt; unbestaetigt=Versuch, bestaetigt=Registrierung."""
code = _create_code(client, admin)
batch = _create_batch(client, admin, code["id"], quantity=2)
token = _batch_tokens(batch["id"])[0]
@ -81,9 +81,27 @@ def test_registration_attributed_to_qr(client, admin):
assert row["referred_by"] == -code["id"]
assert row["referred_qr"] == token
r = client.get("/api/admin/partner/qr-batches", headers=admin["headers"])
mine = [b for b in r.json() if b["id"] == batch["id"]][0]
assert mine["registrations"] == 1
# Frisch registriert = E-Mail unbestaetigt -> zaehlt als Versuch
def _batch():
r = client.get("/api/admin/partner/qr-batches", headers=admin["headers"])
return [b for b in r.json() if b["id"] == batch["id"]][0]
assert _batch()["attempts"] == 1 and _batch()["registrations"] == 0
# Nach E-Mail-Bestaetigung -> echte Registrierung
with db() as conn:
conn.execute("UPDATE users SET email_verified=1 WHERE email=?", (email,))
assert _batch()["registrations"] == 1 and _batch()["attempts"] == 0
# Admin-Detail-Liste: Account mit Datum, Status und Sticker-Nr
r = client.get(f"/api/admin/partner/qr-batches/{batch['id']}/registrations",
headers=admin["headers"])
assert r.status_code == 200
regs = r.json()
assert len(regs) == 1
assert regs[0]["email"] == email
assert regs[0]["email_verified"] == 1
assert regs[0]["seq"] == 1
assert regs[0]["created_at"]
def test_qr_token_must_match_code(client, admin):