Spaces:
Runtime error
Runtime error
Release 2026-06-15/16: B2 billing-orphan fix + demo conversion (B1/B3/B4/B5) + conversation history (72h) + per-tenant teach-the-bot + onboarding videos
4778987 verified | """Trial sweep: pause expired self-serve trials that never subscribed, email the | |
| payment link, and never touch paid or still-running trials.""" | |
| from __future__ import annotations | |
| from datetime import UTC, datetime, timedelta | |
| from sqlalchemy import select | |
| from app.models import Tenant | |
| from app.scheduler import pause_expired_trials | |
| async def test_pause_only_expired_unsubscribed_trials(db_session, monkeypatch): | |
| from app import mailer | |
| sent = [] | |
| async def fake(settings, to, subject, body, **k): | |
| sent.append(to) | |
| return True | |
| monkeypatch.setattr(mailer, "send_email", fake) | |
| past = datetime.now(UTC) - timedelta(hours=1) | |
| future = datetime.now(UTC) + timedelta(days=5) | |
| db_session.add_all([ | |
| Tenant(slug="t-expired", trial_ends_at=past, chatbot_enabled=True, | |
| support_email="e@x.com"), | |
| Tenant(slug="t-paid", trial_ends_at=past, chatbot_enabled=True, | |
| stripe_subscription_id="sub_123", support_email="p@x.com"), | |
| Tenant(slug="t-running", trial_ends_at=future, chatbot_enabled=True, | |
| support_email="r@x.com"), | |
| ]) | |
| await db_session.commit() | |
| n = await pause_expired_trials(db_session) | |
| assert n == 1 # only the expired, unsubscribed one | |
| db_session.expire_all() | |
| async def _get(slug): | |
| return (await db_session.execute(select(Tenant).where(Tenant.slug == slug))).scalar_one() | |
| expired = await _get("t-expired") | |
| assert expired.chatbot_enabled is False | |
| assert expired.disabled_reason == "trial" # kill-switch reason, cuts service everywhere | |
| assert (await _get("t-paid")).chatbot_enabled is True # subscribed -> kept | |
| assert (await _get("t-running")).chatbot_enabled is True # not expired yet | |
| assert "e@x.com" in sent # expired trial got the pay link | |
| assert "p@x.com" not in sent # paid one never emailed | |
| assert "r@x.com" not in sent | |
| async def test_pause_is_idempotent(db_session, monkeypatch): | |
| from app import mailer | |
| monkeypatch.setattr(mailer, "send_email", lambda *a, **k: _noop()) | |
| db_session.add(Tenant(slug="t-x", trial_ends_at=datetime.now(UTC) - timedelta(hours=1), | |
| chatbot_enabled=True, support_email="x@x.com")) | |
| await db_session.commit() | |
| assert await pause_expired_trials(db_session) == 1 | |
| # second sweep: already paused (chatbot_enabled=False) -> not reselected | |
| assert await pause_expired_trials(db_session) == 0 | |
| async def _noop(): | |
| return True | |