Merge pull request #2460 from BEDOLAGA-DEV/main

w
This commit is contained in:
Egor
2026-01-30 20:40:52 +03:00
committed by GitHub
2 changed files with 156 additions and 0 deletions

View File

@@ -132,6 +132,28 @@ class PaymentCommonMixin:
payment_method_title: str | None = None,
) -> None:
"""Отправляет пользователю уведомление об успешном платеже."""
# Lazy import to avoid circular dependency
from app.cabinet.routes.websocket import notify_user_balance_topup
# Send WebSocket notification to cabinet frontend (works for both Telegram and email-only users)
user_id = getattr(user, 'id', None) if user else None
if user_id:
try:
# Get new balance from user
new_balance = getattr(user, 'balance_kopeks', 0)
await notify_user_balance_topup(
user_id=user_id,
amount_kopeks=amount_kopeks,
new_balance_kopeks=new_balance,
description=payment_method_title or '',
)
except Exception as ws_error:
logger.warning(
'Не удалось отправить WS уведомление о пополнении баланса для user_id=%s: %s',
user_id,
ws_error,
)
if not getattr(self, 'bot', None):
# Если бот не передан (например, внутри фоновых задач), уведомление пропускаем.
return

View File

@@ -347,6 +347,9 @@ async def _auto_extend_subscription(
*,
bot: Bot | None = None,
) -> bool:
# Lazy import to avoid circular dependency
from app.cabinet.routes.websocket import notify_user_subscription_renewed
try:
prepared = await _prepare_auto_extend_context(db, user, cart_data)
except Exception as error: # pragma: no cover - defensive logging
@@ -559,6 +562,20 @@ async def _auto_extend_subscription(
_format_user_id(user),
)
# Send WebSocket notification to cabinet frontend
try:
await notify_user_subscription_renewed(
user_id=user.id,
new_expires_at=new_end_date.isoformat() if new_end_date else '',
amount_kopeks=prepared.price_kopeks,
)
except Exception as ws_error:
logger.warning(
'⚠️ Автопокупка: не удалось отправить WS уведомление о продлении для %s: %s',
_format_user_id(user),
ws_error,
)
return True
@@ -570,6 +587,11 @@ async def _auto_purchase_tariff(
bot: Bot | None = None,
) -> bool:
"""Автоматическая покупка периодного тарифа из сохранённой корзины."""
# Lazy imports to avoid circular dependency
from app.cabinet.routes.websocket import (
notify_user_subscription_activated,
notify_user_subscription_renewed,
)
from app.database.crud.server_squad import get_all_server_squads
from app.database.crud.subscription import (
create_paid_subscription,
@@ -814,6 +836,29 @@ async def _auto_purchase_tariff(
_format_user_id(user),
)
# Send WebSocket notification to cabinet frontend
try:
if existing_subscription:
# Renewal of existing subscription
await notify_user_subscription_renewed(
user_id=user.id,
new_expires_at=subscription.end_date.isoformat() if subscription.end_date else '',
amount_kopeks=final_price,
)
else:
# New subscription activation
await notify_user_subscription_activated(
user_id=user.id,
expires_at=subscription.end_date.isoformat() if subscription.end_date else '',
tariff_name=tariff.name,
)
except Exception as ws_error:
logger.warning(
'⚠️ Автопокупка тарифа: не удалось отправить WS уведомление для %s: %s',
_format_user_id(user),
ws_error,
)
return True
@@ -827,6 +872,11 @@ async def _auto_purchase_daily_tariff(
"""Автоматическая покупка суточного тарифа из сохранённой корзины."""
from datetime import datetime, timedelta
# Lazy imports to avoid circular dependency
from app.cabinet.routes.websocket import (
notify_user_subscription_activated,
notify_user_subscription_renewed,
)
from app.database.crud.server_squad import get_all_server_squads
from app.database.crud.subscription import create_paid_subscription, get_subscription_by_user_id
from app.database.crud.tariff import get_tariff_by_id
@@ -1051,6 +1101,29 @@ async def _auto_purchase_daily_tariff(
_format_user_id(user),
)
# Send WebSocket notification to cabinet frontend
try:
if existing_subscription:
# Renewal/upgrade of existing subscription
await notify_user_subscription_renewed(
user_id=user.id,
new_expires_at=subscription.end_date.isoformat() if subscription.end_date else '',
amount_kopeks=daily_price,
)
else:
# New subscription activation
await notify_user_subscription_activated(
user_id=user.id,
expires_at=subscription.end_date.isoformat() if subscription.end_date else '',
tariff_name=tariff.name,
)
except Exception as ws_error:
logger.warning(
'⚠️ Автопокупка суточного тарифа: не удалось отправить WS уведомление для %s: %s',
_format_user_id(user),
ws_error,
)
return True
@@ -1061,6 +1134,11 @@ async def auto_purchase_saved_cart_after_topup(
bot: Bot | None = None,
) -> bool:
"""Attempts to automatically purchase a subscription from a saved cart."""
# Lazy imports to avoid circular dependency
from app.cabinet.routes.websocket import (
notify_user_subscription_activated,
notify_user_subscription_renewed,
)
if not settings.is_auto_purchase_after_topup_enabled():
return False
@@ -1243,6 +1321,29 @@ async def auto_purchase_saved_cart_after_topup(
_format_user_id(user),
)
# Send WebSocket notification to cabinet frontend
try:
if was_trial_conversion:
# Trial conversion = activation
await notify_user_subscription_activated(
user_id=user.id,
expires_at=subscription.end_date.isoformat() if subscription and subscription.end_date else '',
tariff_name='',
)
else:
# Regular purchase = renewal or new activation
await notify_user_subscription_renewed(
user_id=user.id,
new_expires_at=subscription.end_date.isoformat() if subscription and subscription.end_date else '',
amount_kopeks=pricing.final_total,
)
except Exception as ws_error:
logger.warning(
'⚠️ Автопокупка: не удалось отправить WS уведомление для %s: %s',
_format_user_id(user),
ws_error,
)
return True
@@ -1273,6 +1374,11 @@ async def auto_activate_subscription_after_topup(
"""
from datetime import datetime
# Lazy imports to avoid circular dependency
from app.cabinet.routes.websocket import (
notify_user_subscription_activated,
notify_user_subscription_renewed,
)
from app.database.crud.server_squad import get_available_server_squads, get_server_ids_by_uuids
from app.database.crud.subscription import create_paid_subscription, get_subscription_by_user_id
from app.database.crud.transaction import create_transaction
@@ -1397,6 +1503,20 @@ async def auto_activate_subscription_after_topup(
best_price,
)
# Send WebSocket notification to cabinet frontend
try:
await notify_user_subscription_renewed(
user_id=user.id,
new_expires_at=result.subscription.end_date.isoformat() if result.subscription.end_date else '',
amount_kopeks=best_price,
)
except Exception as ws_error:
logger.warning(
'⚠️ Автоактивация: не удалось отправить WS уведомление о продлении для %s: %s',
_format_user_id(user),
ws_error,
)
# Уведомление пользователю (только для Telegram-пользователей)
if bot and user.telegram_id:
try:
@@ -1475,6 +1595,20 @@ async def auto_activate_subscription_after_topup(
best_price,
)
# Send WebSocket notification to cabinet frontend
try:
await notify_user_subscription_activated(
user_id=user.id,
expires_at=new_subscription.end_date.isoformat() if new_subscription.end_date else '',
tariff_name='',
)
except Exception as ws_error:
logger.warning(
'⚠️ Автоактивация: не удалось отправить WS уведомление об активации для %s: %s',
_format_user_id(user),
ws_error,
)
# Уведомление пользователю (только для Telegram-пользователей)
if bot and user.telegram_id:
try: