diff --git a/app/handlers/admin/users.py b/app/handlers/admin/users.py index d0e858e4..9b7a9c2a 100644 --- a/app/handlers/admin/users.py +++ b/app/handlers/admin/users.py @@ -685,7 +685,8 @@ async def process_balance_edit( description = f"Списание администратором: {int(amount_rubles)} ₽" success = await user_service.update_user_balance( - db, user_id, amount_kopeks, description, db_user.id + db, user_id, amount_kopeks, description, db_user.id, + bot=message.bot, admin_name=db_user.full_name ) if success: diff --git a/app/services/user_service.py b/app/services/user_service.py index 0c65fde0..f26e14b2 100644 --- a/app/services/user_service.py +++ b/app/services/user_service.py @@ -3,6 +3,8 @@ from datetime import datetime, timedelta from typing import Optional, List, Dict, Any from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import delete, select, update +from aiogram import Bot +from aiogram.exceptions import TelegramBadRequest, TelegramForbiddenError from app.database.crud.user import ( get_user_by_id, get_user_by_telegram_id, get_users_list, get_users_count, get_users_statistics, get_inactive_users, @@ -23,6 +25,59 @@ logger = logging.getLogger(__name__) class UserService: + async def _send_balance_notification( + self, + bot: Bot, + user: User, + amount_kopeks: int, + admin_name: str + ) -> bool: + """Отправляет уведомление пользователю о пополнении/списании баланса""" + try: + if amount_kopeks > 0: + # Пополнение + emoji = "💰" + action = "пополнен" + amount_text = f"+{settings.format_price(amount_kopeks)}" + message = ( + f"{emoji} Баланс пополнен!\n\n" + f"💵 Сумма: {amount_text}\n" + f"👤 Администратор: {admin_name}\n" + f"💳 Текущий баланс: {settings.format_price(user.balance_kopeks)}\n\n" + f"Спасибо за использование нашего сервиса! 🎉" + ) + else: + # Списание + emoji = "💸" + action = "списан" + amount_text = f"-{settings.format_price(abs(amount_kopeks))}" + message = ( + f"{emoji} Средства списаны с баланса\n\n" + f"💵 Сумма: {amount_text}\n" + f"👤 Администратор: {admin_name}\n" + f"💳 Текущий баланс: {settings.format_price(user.balance_kopeks)}\n\n" + f"Если у вас есть вопросы, обратитесь в поддержку." + ) + + await bot.send_message( + chat_id=user.telegram_id, + text=message, + parse_mode="HTML" + ) + + logger.info(f"✅ Уведомление о изменении баланса отправлено пользователю {user.telegram_id}") + return True + + except TelegramForbiddenError: + logger.warning(f"⚠️ Пользователь {user.telegram_id} заблокировал бота") + return False + except TelegramBadRequest as e: + logger.error(f"❌ Ошибка Telegram API при отправке уведомления пользователю {user.telegram_id}: {e}") + return False + except Exception as e: + logger.error(f"❌ Неожиданная ошибка при отправке уведомления пользователю {user.telegram_id}: {e}") + return False + async def get_user_profile( self, db: AsyncSession, @@ -128,22 +183,41 @@ class UserService: user_id: int, amount_kopeks: int, description: str, - admin_id: int + admin_id: int, + bot: Optional[Bot] = None, + admin_name: Optional[str] = None ) -> bool: try: user = await get_user_by_id(db, user_id) if not user: return False + # Сохраняем старый баланс для уведомления + old_balance = user.balance_kopeks + if amount_kopeks > 0: await add_user_balance(db, user, amount_kopeks, description=description) logger.info(f"Админ {admin_id} пополнил баланс пользователя {user_id} на {amount_kopeks/100}₽") - return True + success = True else: success = await subtract_user_balance(db, user, abs(amount_kopeks), description) if success: logger.info(f"Админ {admin_id} списал с баланса пользователя {user_id} {abs(amount_kopeks)/100}₽") - return success + + # Отправляем уведомление пользователю, если операция прошла успешно + if success and bot: + # Обновляем пользователя для получения нового баланса + await db.refresh(user) + + # Получаем имя администратора + if not admin_name: + admin_user = await get_user_by_id(db, admin_id) + admin_name = admin_user.full_name if admin_user else f"Админ #{admin_id}" + + # Отправляем уведомление (не блокируем операцию если не удалось отправить) + await self._send_balance_notification(bot, user, amount_kopeks, admin_name) + + return success except Exception as e: logger.error(f"Ошибка изменения баланса пользователя: {e}")