175 lines
5.4 KiB
Python
175 lines
5.4 KiB
Python
import asyncio
|
|
from datetime import datetime, timezone
|
|
from types import SimpleNamespace
|
|
|
|
from bot.services import subscription_lifecycle_notifications as lifecycle
|
|
from bot.services.subscription_lifecycle_notifications import (
|
|
SubscriptionLifecycleNotificationService,
|
|
SubscriptionNotificationStage,
|
|
)
|
|
|
|
|
|
class FakeI18n:
|
|
def gettext(self, lang_code, key, **kwargs):
|
|
messages = {
|
|
"subscription_72h_notification": "Hi {user_name}, expires on {end_date}",
|
|
"email_subscription_lifecycle_subject_before_days": "{days} days left",
|
|
"email_subscription_lifecycle_subject_before_hours": "{hours} hours left",
|
|
"email_subscription_lifecycle_subject_expired": "Expired",
|
|
"email_subscription_lifecycle_subject_expired_after": "Expired yesterday",
|
|
"email_subscription_lifecycle_subject_autorenew": "Auto-renewal tomorrow",
|
|
"email_subscription_lifecycle_intro": "Subscription notice",
|
|
"email_subscription_lifecycle_row_end_date": "Active until",
|
|
"email_subscription_lifecycle_cta": "Open dashboard",
|
|
"email_subscription_lifecycle_text_renew": "Dashboard: {url}",
|
|
"email_footer_auto": "Sent by {brand}",
|
|
}
|
|
return messages.get(key, key).format(**kwargs)
|
|
|
|
|
|
class FakeBot:
|
|
def __init__(self):
|
|
self.messages = []
|
|
|
|
async def send_message(self, chat_id, text, reply_markup=None):
|
|
self.messages.append(
|
|
{
|
|
"chat_id": chat_id,
|
|
"text": text,
|
|
"reply_markup": reply_markup,
|
|
}
|
|
)
|
|
|
|
|
|
class FakeEmailService:
|
|
def __init__(self):
|
|
self.messages = []
|
|
|
|
async def send_rendered_email(self, *, email, content):
|
|
self.messages.append({"email": email, "content": content})
|
|
|
|
|
|
def _settings(**overrides):
|
|
return SimpleNamespace(
|
|
DEFAULT_LANGUAGE="ru",
|
|
SUBSCRIPTION_EMAIL_NOTIFICATIONS_ENABLED=True,
|
|
SUBSCRIPTION_MINI_APP_URL="https://app.example.test/",
|
|
WEBAPP_PRIMARY_COLOR="#00fe7a",
|
|
WEBAPP_TITLE="Minishop",
|
|
WEBAPP_LOGO_USE_EMOJI=False,
|
|
WEBAPP_LOGO_URL="",
|
|
email_auth_configured=True,
|
|
**overrides,
|
|
)
|
|
|
|
|
|
def _subscription():
|
|
return SimpleNamespace(
|
|
subscription_id=42,
|
|
user_id=123,
|
|
end_date=datetime(2026, 6, 1, tzinfo=timezone.utc),
|
|
)
|
|
|
|
|
|
def _user(**overrides):
|
|
return SimpleNamespace(
|
|
user_id=123,
|
|
telegram_id=555,
|
|
email="user@example.test",
|
|
language_code="ru",
|
|
first_name="Ada",
|
|
**overrides,
|
|
)
|
|
|
|
|
|
def test_send_stage_records_telegram_and_email_channel_keys(monkeypatch):
|
|
recorded = []
|
|
|
|
async def fake_has(session, subscription_id, notification_key):
|
|
return notification_key in recorded
|
|
|
|
async def fake_record(session, subscription_id, notification_key, *, sent_at=None):
|
|
recorded.append(notification_key)
|
|
|
|
monkeypatch.setattr(lifecycle.subscription_dal, "has_subscription_notification", fake_has)
|
|
monkeypatch.setattr(lifecycle.subscription_dal, "record_subscription_notification", fake_record)
|
|
|
|
bot = FakeBot()
|
|
email_service = FakeEmailService()
|
|
service = SubscriptionLifecycleNotificationService(
|
|
_settings(),
|
|
bot,
|
|
FakeI18n(),
|
|
email_service=email_service,
|
|
)
|
|
|
|
async def run():
|
|
return await service.send_stage(
|
|
object(),
|
|
_subscription(),
|
|
SubscriptionNotificationStage(
|
|
key="before_3d",
|
|
message_key="subscription_72h_notification",
|
|
days_left=3,
|
|
),
|
|
user=_user(),
|
|
telegram_markup="markup",
|
|
)
|
|
|
|
delivery = asyncio.run(run())
|
|
|
|
assert delivery.telegram_sent is True
|
|
assert delivery.email_sent is True
|
|
assert bot.messages == [
|
|
{
|
|
"chat_id": 555,
|
|
"text": "Hi Ada, expires on 2026-06-01",
|
|
"reply_markup": "markup",
|
|
}
|
|
]
|
|
assert email_service.messages[0]["email"] == "user@example.test"
|
|
assert recorded == ["before_3d:telegram", "before_3d:email"]
|
|
|
|
|
|
def test_legacy_stage_key_suppresses_only_telegram(monkeypatch):
|
|
recorded = ["before_3d"]
|
|
|
|
async def fake_has(session, subscription_id, notification_key):
|
|
return notification_key in recorded
|
|
|
|
async def fake_record(session, subscription_id, notification_key, *, sent_at=None):
|
|
recorded.append(notification_key)
|
|
|
|
monkeypatch.setattr(lifecycle.subscription_dal, "has_subscription_notification", fake_has)
|
|
monkeypatch.setattr(lifecycle.subscription_dal, "record_subscription_notification", fake_record)
|
|
|
|
bot = FakeBot()
|
|
email_service = FakeEmailService()
|
|
service = SubscriptionLifecycleNotificationService(
|
|
_settings(),
|
|
bot,
|
|
FakeI18n(),
|
|
email_service=email_service,
|
|
)
|
|
|
|
async def run():
|
|
return await service.send_stage(
|
|
object(),
|
|
_subscription(),
|
|
SubscriptionNotificationStage(
|
|
key="before_3d",
|
|
message_key="subscription_72h_notification",
|
|
days_left=3,
|
|
),
|
|
user=_user(),
|
|
telegram_markup="markup",
|
|
)
|
|
|
|
delivery = asyncio.run(run())
|
|
|
|
assert delivery.telegram_sent is False
|
|
assert delivery.email_sent is True
|
|
assert bot.messages == []
|
|
assert email_service.messages[0]["email"] == "user@example.test"
|
|
assert recorded == ["before_3d", "before_3d:email"]
|