Feature: Abo-Kündigung + Ablaufdatum + Dog-Auswahl nach Downgrade (SW by-v945)
This commit is contained in:
parent
44b3fba191
commit
3b666c545f
10 changed files with 341 additions and 11 deletions
|
|
@ -240,7 +240,8 @@ async def me(user=Depends(get_current_user)):
|
|||
profil_sichtbarkeit, avatar_url, created_at,
|
||||
is_founder, is_partner, founder_number, is_founder_pending,
|
||||
notes_ki_enabled, gassi_stunde_push,
|
||||
preferred_theme, subscription_tier
|
||||
preferred_theme, subscription_tier,
|
||||
subscription_expires_at, subscription_cancelled_at, needs_dog_selection
|
||||
FROM users WHERE id=?""",
|
||||
(user["id"],)
|
||||
).fetchone()
|
||||
|
|
@ -394,3 +395,70 @@ async def reset_password(data: ResetPasswordRequest, request: Request):
|
|||
(hash_password(data.password), user["id"])
|
||||
)
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@router.post("/subscription/cancel")
|
||||
async def cancel_subscription(user=Depends(get_current_user)):
|
||||
with db() as conn:
|
||||
row = conn.execute(
|
||||
"SELECT subscription_tier, subscription_expires_at, subscription_cancelled_at FROM users WHERE id=?",
|
||||
(user["id"],)
|
||||
).fetchone()
|
||||
if not row or row["subscription_tier"] in ("standard", "standard_test"):
|
||||
raise HTTPException(400, "Kein aktives Abo vorhanden.")
|
||||
if row["subscription_cancelled_at"]:
|
||||
raise HTTPException(400, "Abo ist bereits gekündigt.")
|
||||
conn.execute(
|
||||
"UPDATE users SET subscription_cancelled_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id=?",
|
||||
(user["id"],)
|
||||
)
|
||||
expires = row["subscription_expires_at"]
|
||||
|
||||
# Bestätigungsmail
|
||||
try:
|
||||
from mailer import send_email, email_html
|
||||
import html as _html
|
||||
tier_label = {"pro": "Ban Yaro Pro", "breeder": "Züchter"}.get(row["subscription_tier"], row["subscription_tier"])
|
||||
expires_fmt = expires[:10] if expires else "—"
|
||||
body_html = f"""
|
||||
<p>Hallo {_html.escape(user['name'])},</p>
|
||||
<p>deine Kündigung für <strong>{tier_label}</strong> wurde bestätigt.</p>
|
||||
<p>Dein Abo ist weiterhin aktiv bis zum <strong>{expires_fmt}</strong>.
|
||||
Ab diesem Datum wirst du automatisch auf den kostenlosen Tarif gesetzt.</p>
|
||||
<p>Deine Daten (Tagebuch, Gesundheit, Notizen) bleiben vollständig erhalten.
|
||||
Wenn du mehrere Hunde hast, kannst du vor dem Ablauf einen als Haupthund festlegen.</p>
|
||||
<p>Wir hoffen, dich bald wieder begrüßen zu dürfen!</p>
|
||||
<p>Viele Grüße<br>René & das Ban Yaro Team</p>"""
|
||||
html = email_html(body_html, cta_url="https://banyaro.app", cta_label="Ban Yaro öffnen")
|
||||
plain = (f"Hallo {user['name']},\n\nKündigung bestätigt für {tier_label}.\n"
|
||||
f"Aktiv bis: {expires_fmt}\n\nAlle Daten bleiben erhalten.\n\nViele Grüße\nRené")
|
||||
await send_email(user["email"], f"Kündigung bestätigt — {tier_label}", html, plain)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {"ok": True, "expires_at": expires}
|
||||
|
||||
|
||||
@router.post("/subscription/select-dog")
|
||||
async def select_primary_dog(body: dict, user=Depends(get_current_user)):
|
||||
"""Nach Downgrade: Haupthund auswählen, Rest bleibt erhalten aber inaktiv."""
|
||||
dog_id = body.get("dog_id")
|
||||
if not dog_id:
|
||||
raise HTTPException(400, "dog_id fehlt.")
|
||||
with db() as conn:
|
||||
dog = conn.execute(
|
||||
"SELECT id FROM dogs WHERE id=? AND user_id=?", (dog_id, user["id"])
|
||||
).fetchone()
|
||||
if not dog:
|
||||
raise HTTPException(404, "Hund nicht gefunden.")
|
||||
# Alle anderen Hunde deaktivieren
|
||||
conn.execute(
|
||||
"UPDATE dogs SET is_active=0 WHERE user_id=? AND id!=?", (user["id"], dog_id)
|
||||
)
|
||||
conn.execute(
|
||||
"UPDATE dogs SET is_active=1 WHERE id=?", (dog_id,)
|
||||
)
|
||||
conn.execute(
|
||||
"UPDATE users SET needs_dog_selection=0 WHERE id=?", (user["id"],)
|
||||
)
|
||||
return {"ok": True}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue