Partner-Self-Service: Einzel-Code-Status — welcher Sticker ist verbraucht?
Rene: 'wo sieht der Partner welche QR-Codes er hat und wieviele verbraucht
sind?' Neu in 'Meine QR-Codes':
- Kontingent-Zeile zeigt 'X/Y verbraucht' (Codes mit ≥1 bestätigter Registrierung)
- Listen-Button klappt Einzel-Codes auf: #Nr, Kurz-URL, Scans und Status
● verbraucht (mit Registrierungs-Datum) / ◐ gescannt / ○ frei
- Endpoint /partner/my-qr/{id}/codes (owner-gated, keine personenbezogenen
Daten — nur Zähler + Zeitstempel)
This commit is contained in:
parent
970480c1d6
commit
df2f42f8ac
8 changed files with 134 additions and 41 deletions
|
|
@ -583,9 +583,12 @@ def _qr_batch_stats(conn, batch_id: int) -> dict:
|
|||
WHERE q2.batch_id = ? AND u.email_verified = 1) AS registrations,
|
||||
(SELECT COUNT(*) FROM users u
|
||||
JOIN partner_qr_codes q2 ON q2.token = u.referred_qr
|
||||
WHERE q2.batch_id = ? AND u.email_verified = 0) AS attempts
|
||||
WHERE q2.batch_id = ? AND u.email_verified = 0) AS attempts,
|
||||
(SELECT COUNT(DISTINCT q3.id) FROM partner_qr_codes q3
|
||||
JOIN users u ON u.referred_qr = q3.token AND u.email_verified = 1
|
||||
WHERE q3.batch_id = ?) AS codes_used
|
||||
FROM partner_qr_codes q WHERE q.batch_id = ?""",
|
||||
(batch_id, batch_id, batch_id)
|
||||
(batch_id, batch_id, batch_id, batch_id)
|
||||
).fetchone()
|
||||
return dict(row)
|
||||
|
||||
|
|
@ -756,18 +759,44 @@ def my_qr_batches(user=Depends(require_partner)):
|
|||
)
|
||||
|
||||
|
||||
def _require_own_batch(conn, batch_id: int, user: dict):
|
||||
own = conn.execute(
|
||||
"""SELECT b.id FROM partner_qr_batches b
|
||||
JOIN partner_codes pc ON pc.id = b.partner_code_id
|
||||
WHERE b.id=? AND pc.owner_user_id=?""",
|
||||
(batch_id, user["id"])
|
||||
).fetchone()
|
||||
if not own and user.get("rolle") != "admin":
|
||||
raise HTTPException(403, "Kein Zugriff auf dieses Kontingent.")
|
||||
|
||||
|
||||
@router.get("/partner/my-qr/{batch_id}/codes")
|
||||
def my_qr_batch_codes(batch_id: int, user=Depends(require_partner)):
|
||||
"""Einzel-Code-Status fürs eigene Kontingent: welcher Sticker ist verbraucht?
|
||||
Keine personenbezogenen Daten — nur Zähler und Zeitstempel."""
|
||||
with db() as conn:
|
||||
_require_own_batch(conn, batch_id, user)
|
||||
rows = conn.execute(
|
||||
"""SELECT q.seq, q.token, q.scans, q.last_scan_at,
|
||||
(SELECT COUNT(*) FROM users u
|
||||
WHERE u.referred_qr = q.token AND u.email_verified = 1) AS registrations,
|
||||
(SELECT COUNT(*) FROM users u
|
||||
WHERE u.referred_qr = q.token AND u.email_verified = 0) AS attempts,
|
||||
(SELECT MIN(u.created_at) FROM users u
|
||||
WHERE u.referred_qr = q.token AND u.email_verified = 1) AS first_registration_at
|
||||
FROM partner_qr_codes q
|
||||
WHERE q.batch_id = ?
|
||||
ORDER BY q.seq""",
|
||||
(batch_id,)
|
||||
).fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
|
||||
@router.get("/partner/my-qr/{batch_id}/pdf")
|
||||
def qr_batch_pdf_partner(batch_id: int, user=Depends(require_partner)):
|
||||
from fastapi.responses import Response
|
||||
with db() as conn:
|
||||
own = conn.execute(
|
||||
"""SELECT b.id FROM partner_qr_batches b
|
||||
JOIN partner_codes pc ON pc.id = b.partner_code_id
|
||||
WHERE b.id=? AND pc.owner_user_id=?""",
|
||||
(batch_id, user["id"])
|
||||
).fetchone()
|
||||
if not own and user.get("rolle") != "admin":
|
||||
raise HTTPException(403, "Kein Zugriff auf dieses Kontingent.")
|
||||
_require_own_batch(conn, batch_id, user)
|
||||
pdf = _qr_batch_pdf(conn, batch_id)
|
||||
return Response(content=pdf, media_type="application/pdf",
|
||||
headers={"Content-Disposition": f'attachment; filename="banyaro-qr-{batch_id}.pdf"'})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue