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
|
|
@ -188,8 +188,15 @@ def start():
|
|||
replace_existing=True,
|
||||
misfire_grace_time=3600,
|
||||
)
|
||||
_scheduler.add_job(
|
||||
_job_subscription_check,
|
||||
CronTrigger(hour=3, minute=0),
|
||||
id="subscription_check",
|
||||
replace_existing=True,
|
||||
misfire_grace_time=3600,
|
||||
)
|
||||
_scheduler.start()
|
||||
logger.info("Scheduler gestartet — Health-Reminder 08:00, Giftköder-Archiv 03:00, Wetter-Alert 07:30, Meilenstein-Check 00:05, Event-Import So 02:00, Rassen-Seed monatlich 1. des Monats, Status-Report täglich 06:00, Moderation-Overdue 12:00, Quartalsbericht 1. Feb/Mai/Aug/Nov 07:00, Streak-Reminder 19:00, Rückruf-Check 08:00, Goldene-Gassi-Stunde 07:00, Jahrestags-Erinnerungen 09:00, Monatlicher-Rückblick 1. des Monats 10:00, Foto-Challenge Mo 08:00. OSM-Cache: on-demand (kein Prewarm).")
|
||||
logger.info("Scheduler gestartet — Health-Reminder 08:00, Giftköder-Archiv 03:00, Wetter-Alert 07:30, Meilenstein-Check 00:05, Event-Import So 02:00, Rassen-Seed monatlich 1. des Monats, Status-Report täglich 06:00, Moderation-Overdue 12:00, Quartalsbericht 1. Feb/Mai/Aug/Nov 07:00, Streak-Reminder 19:00, Rückruf-Check 08:00, Goldene-Gassi-Stunde 07:00, Jahrestags-Erinnerungen 09:00, Monatlicher-Rückblick 1. des Monats 10:00, Foto-Challenge Mo 08:00, Abo-Check 03:00. OSM-Cache: on-demand (kein Prewarm).")
|
||||
|
||||
|
||||
def stop():
|
||||
|
|
@ -197,6 +204,82 @@ def stop():
|
|||
logger.info("Scheduler gestoppt.")
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# JOB: Abo-Ablauf prüfen (täglich 03:00)
|
||||
# ------------------------------------------------------------------
|
||||
async def _job_subscription_check():
|
||||
"""Abgelaufene Abos auf Standard setzen; Warnmails 30 und 7 Tage vorher."""
|
||||
from database import db as _db
|
||||
from mailer import send_email, email_html
|
||||
import html as _html
|
||||
now = datetime.now(_TZ)
|
||||
today = now.date()
|
||||
|
||||
with _db() as conn:
|
||||
users = conn.execute(
|
||||
"""SELECT id, name, email, subscription_tier, subscription_expires_at
|
||||
FROM users
|
||||
WHERE subscription_tier IN ('pro','breeder')
|
||||
AND subscription_expires_at IS NOT NULL"""
|
||||
).fetchall()
|
||||
|
||||
for u in users:
|
||||
try:
|
||||
expires = datetime.fromisoformat(u["subscription_expires_at"].replace('Z', '+00:00')).date()
|
||||
days_left = (expires - today).days
|
||||
tier_label = {"pro": "Ban Yaro Pro", "breeder": "Züchter"}.get(u["subscription_tier"], u["subscription_tier"])
|
||||
|
||||
# Abgelaufen → auf Standard setzen
|
||||
if days_left < 0:
|
||||
with _db() as conn:
|
||||
dog_count = conn.execute(
|
||||
"SELECT COUNT(*) FROM dogs WHERE user_id=? AND is_active!=0", (u["id"],)
|
||||
).fetchone()[0]
|
||||
needs_sel = 1 if dog_count > 1 else 0
|
||||
conn.execute(
|
||||
"""UPDATE users SET subscription_tier='standard',
|
||||
needs_dog_selection=? WHERE id=?""",
|
||||
(needs_sel, u["id"])
|
||||
)
|
||||
logger.info(f"Abo abgelaufen: {u['email']} → standard (needs_dog_selection={needs_sel})")
|
||||
body = f"""
|
||||
<p>Hallo {_html.escape(u['name'])},</p>
|
||||
<p>dein <strong>{tier_label}</strong>-Abo ist heute abgelaufen.
|
||||
Dein Account wurde auf den kostenlosen Tarif gesetzt.</p>
|
||||
<p>Deine Daten sind vollständig erhalten. Du kannst jederzeit wieder upgraden.</p>"""
|
||||
if needs_sel:
|
||||
body += "<p><strong>Wichtig:</strong> Du hattest mehrere Hunde. Öffne die App und wähle deinen Haupthund aus — alle anderen Profile bleiben gespeichert.</p>"
|
||||
html = email_html(body, cta_url="https://banyaro.app", cta_label="Ban Yaro öffnen")
|
||||
await send_email(u["email"], f"Dein {tier_label}-Abo ist abgelaufen", html,
|
||||
f"Hallo {u['name']},\ndein {tier_label}-Abo ist abgelaufen. Daten bleiben erhalten.")
|
||||
|
||||
# 30 Tage Warnung
|
||||
elif days_left == 30:
|
||||
body = f"""
|
||||
<p>Hallo {_html.escape(u['name'])},</p>
|
||||
<p>dein <strong>{tier_label}</strong>-Abo läuft in <strong>30 Tagen</strong>
|
||||
(am {expires.strftime('%d.%m.%Y')}) ab.</p>
|
||||
<p>Um weiterzumachen, überweise einfach den Jahresbetrag und schreib uns kurz —
|
||||
wir verlängern deinen Zugang sofort.</p>"""
|
||||
html = email_html(body, cta_url="https://banyaro.app", cta_label="Abo verlängern")
|
||||
await send_email(u["email"], f"Dein {tier_label}-Abo läuft in 30 Tagen ab", html,
|
||||
f"Hallo {u['name']},\ndein {tier_label}-Abo läuft in 30 Tagen ab ({expires}).")
|
||||
|
||||
# 7 Tage Warnung
|
||||
elif days_left == 7:
|
||||
body = f"""
|
||||
<p>Hallo {_html.escape(u['name'])},</p>
|
||||
<p>dein <strong>{tier_label}</strong>-Abo läuft in <strong>7 Tagen</strong>
|
||||
(am {expires.strftime('%d.%m.%Y')}) ab.</p>
|
||||
<p>Jetzt verlängern und nahtlos weitermachen!</p>"""
|
||||
html = email_html(body, cta_url="https://banyaro.app", cta_label="Abo verlängern")
|
||||
await send_email(u["email"], f"Nur noch 7 Tage — {tier_label}-Abo läuft ab", html,
|
||||
f"Hallo {u['name']},\nnur noch 7 Tage für dein {tier_label}-Abo.")
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"subscription_check Fehler für {u['email']}: {e}")
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# JOB: Gesundheits-Erinnerungen
|
||||
# ------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue