feat: add quick purchase email templates to admin panel
- Register 4 guest purchase template types in admin email templates: guest_subscription_delivered, guest_activation_required, guest_gift_received, guest_cabinet_credentials - Add sample contexts with placeholders for preview/test - Add DB override support to send_guest_notification for all 4 types
This commit is contained in:
@@ -298,6 +298,70 @@ TEMPLATE_TYPES = [
|
||||
},
|
||||
'context_vars': ['username', 'reset_url', 'expire_hours'],
|
||||
},
|
||||
{
|
||||
'type': 'guest_subscription_delivered',
|
||||
'label': {
|
||||
'ru': 'Быстрая покупка: подписка доставлена',
|
||||
'en': 'Quick Purchase: Subscription Delivered',
|
||||
'zh': '快捷购买:订阅已交付',
|
||||
'ua': 'Швидка покупка: підписка доставлена',
|
||||
},
|
||||
'description': {
|
||||
'ru': 'Письмо покупателю после успешной оплаты через лендинг',
|
||||
'en': 'Email to buyer after successful landing page payment',
|
||||
'zh': '通过落地页成功付款后发送给买家的邮件',
|
||||
'ua': 'Лист покупцю після успішної оплати через лендінг',
|
||||
},
|
||||
'context_vars': ['tariff_name', 'period_days', 'cabinet_url'],
|
||||
},
|
||||
{
|
||||
'type': 'guest_activation_required',
|
||||
'label': {
|
||||
'ru': 'Быстрая покупка: требуется активация',
|
||||
'en': 'Quick Purchase: Activation Required',
|
||||
'zh': '快捷购买:需要激活',
|
||||
'ua': 'Швидка покупка: потрібна активація',
|
||||
},
|
||||
'description': {
|
||||
'ru': 'Письмо когда у покупателя уже есть активная подписка',
|
||||
'en': 'Email when buyer already has an active subscription',
|
||||
'zh': '买家已有活跃订阅时发送的邮件',
|
||||
'ua': 'Лист коли у покупця вже є активна підписка',
|
||||
},
|
||||
'context_vars': ['tariff_name', 'period_days', 'success_page_url', 'gift_message'],
|
||||
},
|
||||
{
|
||||
'type': 'guest_gift_received',
|
||||
'label': {
|
||||
'ru': 'Быстрая покупка: подарок получен',
|
||||
'en': 'Quick Purchase: Gift Received',
|
||||
'zh': '快捷购买:收到礼物',
|
||||
'ua': 'Швидка покупка: подарунок отримано',
|
||||
},
|
||||
'description': {
|
||||
'ru': 'Письмо получателю подарочной подписки',
|
||||
'en': 'Email to gift subscription recipient',
|
||||
'zh': '发送给礼物订阅接收者的邮件',
|
||||
'ua': 'Лист отримувачу подарункової підписки',
|
||||
},
|
||||
'context_vars': ['tariff_name', 'period_days', 'cabinet_url', 'gift_message', 'cabinet_email', 'cabinet_password'],
|
||||
},
|
||||
{
|
||||
'type': 'guest_cabinet_credentials',
|
||||
'label': {
|
||||
'ru': 'Быстрая покупка: данные для входа',
|
||||
'en': 'Quick Purchase: Login Credentials',
|
||||
'zh': '快捷购买:登录凭据',
|
||||
'ua': 'Швидка покупка: дані для входу',
|
||||
},
|
||||
'description': {
|
||||
'ru': 'Письмо с логином и паролем для личного кабинета',
|
||||
'en': 'Email with login credentials for the cabinet',
|
||||
'zh': '包含个人中心登录信息的邮件',
|
||||
'ua': 'Лист з логіном та паролем для особистого кабінету',
|
||||
},
|
||||
'context_vars': ['tariff_name', 'period_days', 'cabinet_url', 'cabinet_email', 'cabinet_password'],
|
||||
},
|
||||
]
|
||||
|
||||
SAMPLE_CONTEXTS: dict[str, dict[str, Any]] = {
|
||||
@@ -335,6 +399,34 @@ SAMPLE_CONTEXTS: dict[str, dict[str, Any]] = {
|
||||
'expire_hours': 24,
|
||||
},
|
||||
'password_reset': {'username': 'John', 'reset_url': 'https://example.com/reset?token=abc123', 'expire_hours': 1},
|
||||
'guest_subscription_delivered': {
|
||||
'tariff_name': 'Premium',
|
||||
'period_days': 30,
|
||||
'cabinet_url': 'https://example.com/cabinet',
|
||||
'is_existing_user': False,
|
||||
},
|
||||
'guest_activation_required': {
|
||||
'tariff_name': 'Premium',
|
||||
'period_days': 30,
|
||||
'success_page_url': 'https://example.com/cabinet/buy/success/abc123',
|
||||
'is_gift': True,
|
||||
'gift_message': 'Happy birthday!',
|
||||
},
|
||||
'guest_gift_received': {
|
||||
'tariff_name': 'Premium',
|
||||
'period_days': 30,
|
||||
'cabinet_url': 'https://example.com/cabinet',
|
||||
'gift_message': 'Happy birthday!',
|
||||
'cabinet_email': 'recipient@example.com',
|
||||
'cabinet_password': 'SecurePass123',
|
||||
},
|
||||
'guest_cabinet_credentials': {
|
||||
'tariff_name': 'Premium',
|
||||
'period_days': 30,
|
||||
'cabinet_url': 'https://example.com/cabinet',
|
||||
'cabinet_email': 'user@example.com',
|
||||
'cabinet_password': 'SecurePass123',
|
||||
},
|
||||
}
|
||||
|
||||
AVAILABLE_LANGUAGES = ['ru', 'en', 'zh', 'ua', 'fa']
|
||||
|
||||
@@ -469,7 +469,24 @@ async def send_guest_notification(
|
||||
notification_type = NotificationType.GUEST_SUBSCRIPTION_DELIVERED
|
||||
|
||||
templates = EmailNotificationTemplates()
|
||||
template = templates.get_template(notification_type, language, context)
|
||||
|
||||
# Check DB override first, then fall back to hardcoded template
|
||||
template = None
|
||||
try:
|
||||
from app.cabinet.services.email_template_overrides import get_template_override
|
||||
|
||||
override = await get_template_override(notification_type.value, language)
|
||||
if override:
|
||||
template = {
|
||||
'subject': override['subject'],
|
||||
'body_html': templates._get_base_template(override['body_html'], language),
|
||||
}
|
||||
except Exception as e:
|
||||
logger.debug('Failed to check template override', e=e)
|
||||
|
||||
if not template:
|
||||
template = templates.get_template(notification_type, language, context)
|
||||
|
||||
if not template:
|
||||
logger.warning('No email template found for guest notification', notification_type=notification_type.value)
|
||||
return
|
||||
@@ -497,7 +514,18 @@ async def send_guest_notification(
|
||||
|
||||
# Send separate credentials email for new/upgraded accounts (non-gift self-purchases)
|
||||
if purchase.cabinet_password and not purchase.is_gift:
|
||||
cred_template = templates.get_template(NotificationType.GUEST_CABINET_CREDENTIALS, language, context)
|
||||
cred_template = None
|
||||
try:
|
||||
cred_override = await get_template_override(NotificationType.GUEST_CABINET_CREDENTIALS.value, language)
|
||||
if cred_override:
|
||||
cred_template = {
|
||||
'subject': cred_override['subject'],
|
||||
'body_html': templates._get_base_template(cred_override['body_html'], language),
|
||||
}
|
||||
except Exception:
|
||||
pass
|
||||
if not cred_template:
|
||||
cred_template = templates.get_template(NotificationType.GUEST_CABINET_CREDENTIALS, language, context)
|
||||
if cred_template:
|
||||
cred_result = await asyncio.to_thread(
|
||||
email_service.send_email,
|
||||
|
||||
Reference in New Issue
Block a user