feat(admin): add admin notification system for deposits, purchases, and renewals
This commit is contained in:
111
services/admin_notifications.py
Normal file
111
services/admin_notifications.py
Normal file
@@ -0,0 +1,111 @@
|
||||
import logging
|
||||
from html import escape
|
||||
|
||||
from aiogram import Bot
|
||||
|
||||
from config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def _send_admin_log(bot: Bot, topic_id: int | None, text: str) -> None:
|
||||
if settings.admin_log_chat_id is None or topic_id is None:
|
||||
return
|
||||
|
||||
try:
|
||||
await bot.send_message(
|
||||
settings.admin_log_chat_id,
|
||||
text,
|
||||
message_thread_id=topic_id,
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
except Exception:
|
||||
logger.warning("Failed to send admin log notification", exc_info=True)
|
||||
|
||||
|
||||
def _format_username(username: str | None) -> str:
|
||||
if not username:
|
||||
return "-"
|
||||
return "@" + escape(username)
|
||||
|
||||
|
||||
async def notify_deposit(
|
||||
bot: Bot,
|
||||
*,
|
||||
user_id: int,
|
||||
amount: int,
|
||||
balance_before: int,
|
||||
balance_after: int,
|
||||
bill_id: int,
|
||||
payment_id: str,
|
||||
) -> None:
|
||||
await _send_admin_log(
|
||||
bot,
|
||||
settings.admin_log_deposit_topic_id,
|
||||
"\n".join(
|
||||
[
|
||||
"<b>Пополнение баланса</b>",
|
||||
f"Пользователь: <code>{user_id}</code>",
|
||||
f"Сумма: <b>{amount}₽</b>",
|
||||
f"Баланс: {balance_before}₽ -> {balance_after}₽",
|
||||
f"Bill ID: <code>{bill_id}</code>",
|
||||
f"Payment ID: <code>{escape(payment_id)}</code>",
|
||||
]
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def notify_subscription_purchase(
|
||||
bot: Bot,
|
||||
*,
|
||||
user_id: int,
|
||||
username: str | None,
|
||||
amount: int,
|
||||
balance_before: int,
|
||||
balance_after: int,
|
||||
devices: int,
|
||||
duration_days: int,
|
||||
whitelists: bool,
|
||||
credit: int,
|
||||
) -> None:
|
||||
lines = [
|
||||
"<b>Покупка подписки</b>",
|
||||
f"Пользователь: <code>{user_id}</code> ({_format_username(username)})",
|
||||
f"Стоимость: <b>{amount}₽</b>",
|
||||
f"Баланс: {balance_before}₽ -> {balance_after}₽",
|
||||
f"Устройства: {devices}",
|
||||
f"Срок: {duration_days} дн.",
|
||||
f"Whitelist: {'да' if whitelists else 'нет'}",
|
||||
]
|
||||
if credit > 0:
|
||||
lines.append(f"Зачет неиспользованных дней: {credit}₽")
|
||||
|
||||
await _send_admin_log(bot, settings.admin_log_subscriptions_topic_id, "\n".join(lines))
|
||||
|
||||
|
||||
async def notify_subscription_renewal(
|
||||
bot: Bot,
|
||||
*,
|
||||
user_id: int,
|
||||
amount: int,
|
||||
balance_before: int,
|
||||
balance_after: int,
|
||||
devices: int,
|
||||
duration_days: int,
|
||||
whitelists: bool,
|
||||
end_date: str,
|
||||
) -> None:
|
||||
await _send_admin_log(
|
||||
bot,
|
||||
settings.admin_log_subscriptions_topic_id,
|
||||
(
|
||||
"<b>Продление подписки</b>",
|
||||
f"Пользователь: <code>{user_id}</code>",
|
||||
f"Стоимость: <b>{amount}₽</b>",
|
||||
f"Баланс: {balance_before}₽ -> {balance_after}₽",
|
||||
f"Устройства: {devices}",
|
||||
f"Срок: {duration_days} дн.",
|
||||
f"Whitelist: {'да' if whitelists else 'нет'}",
|
||||
f"Новая дата окончания: {escape(end_date)}",
|
||||
),
|
||||
)
|
||||
@@ -14,6 +14,7 @@ from repositories.subscriptions import SubscriptionRepository
|
||||
from repositories.users import UserRepository
|
||||
from schemas.subscriptions import InternalSquads, SubscriptionPlan, SubscriptionStatus
|
||||
from services import rw as rw_service
|
||||
from services.admin_notifications import notify_subscription_renewal
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -91,7 +92,7 @@ class RenewalService:
|
||||
await self._notify_user(user_id, AUTORENEWAL_INSUFFICIENT_FUNDS)
|
||||
return False
|
||||
|
||||
result = await self.user_repository.decrease_user_balance(
|
||||
renewed_user = await self.user_repository.decrease_user_balance(
|
||||
session,
|
||||
user_id,
|
||||
price,
|
||||
@@ -99,7 +100,7 @@ class RenewalService:
|
||||
description=f"autorenewal: devices={subscription.devices}, duration={subscription.duration_days}d, whitelists={subscription.whitelists}",
|
||||
)
|
||||
|
||||
if not result:
|
||||
if not renewed_user:
|
||||
logger.error("Failed to decrease balance for user %d", user_id)
|
||||
return False
|
||||
|
||||
@@ -136,6 +137,17 @@ class RenewalService:
|
||||
end_date=new_end_date.strftime("%d.%m.%Y"),
|
||||
),
|
||||
)
|
||||
await notify_subscription_renewal(
|
||||
self.bot,
|
||||
user_id=user_id,
|
||||
amount=price,
|
||||
balance_before=renewed_user.balance + price,
|
||||
balance_after=renewed_user.balance,
|
||||
devices=subscription.devices,
|
||||
duration_days=subscription.duration_days,
|
||||
whitelists=subscription.whitelists,
|
||||
end_date=new_end_date.strftime("%d.%m.%Y"),
|
||||
)
|
||||
|
||||
logger.info("Successfully renewed subscription for user %d", user_id)
|
||||
return True
|
||||
|
||||
Reference in New Issue
Block a user