from datetime import datetime from typing import Any import pytz from aiogram import F, Router from aiogram.exceptions import TelegramBadRequest from aiogram.types import CallbackQuery from filters.admin import IsAdminFilter from keyboard import build_stats_kb from logger import logger from utils.csv_export import export_payments_csv, export_users_csv from ..panel.keyboard import AdminPanelCallback, build_admin_back_kb router = Router() @router.callback_query( AdminPanelCallback.filter(F.action == "stats"), IsAdminFilter(), ) async def handle_stats(callback_query: CallbackQuery, session: Any): try: total_users = await session.fetchval("SELECT COUNT(*) FROM users") total_keys = await session.fetchval("SELECT COUNT(*) FROM keys") total_referrals = await session.fetchval("SELECT COUNT(*) FROM referrals") total_payments_today = int( await session.fetchval("SELECT COALESCE(SUM(amount), 0) FROM payments WHERE created_at >= CURRENT_DATE") ) total_payments_week = int( await session.fetchval( "SELECT COALESCE(SUM(amount), 0) FROM payments WHERE created_at >= date_trunc('week', CURRENT_DATE)" ) ) total_payments_month = int( await session.fetchval( "SELECT COALESCE(SUM(amount), 0) FROM payments WHERE created_at >= date_trunc('month', CURRENT_DATE)" ) ) total_payments_all_time = int(await session.fetchval("SELECT COALESCE(SUM(amount), 0) FROM payments")) registrations_today = await session.fetchval("SELECT COUNT(*) FROM users WHERE created_at >= CURRENT_DATE") registrations_week = await session.fetchval( "SELECT COUNT(*) FROM users WHERE created_at >= date_trunc('week', CURRENT_DATE)" ) registrations_month = await session.fetchval( "SELECT COUNT(*) FROM users WHERE created_at >= date_trunc('month', CURRENT_DATE)" ) users_updated_today = await session.fetchval("SELECT COUNT(*) FROM users WHERE updated_at >= CURRENT_DATE") active_keys = await session.fetchval( "SELECT COUNT(*) FROM keys WHERE expiry_time > $1", int(datetime.utcnow().timestamp() * 1000), ) expired_keys = total_keys - active_keys moscow_tz = pytz.timezone("Europe/Moscow") update_time = datetime.now(moscow_tz).strftime("%d.%m.%y %H:%M:%S") stats_message = ( f"📊 Подробная статистика проекта:\n\n" f"👥 Пользователи:\n" f" 📅 За день: {registrations_today}\n" f" 📆 За неделю: {registrations_week}\n" f" 📆 За месяц: {registrations_month}\n" f" 🌐 За все время: {total_users}\n\n" f"🌟 Активные пользователи:\n" f" 🌟 Активных сегодня: {users_updated_today}\n\n" f"👥 Рефералы:\n" f" 🤝 Всего привлечено: {total_referrals}\n\n" f"🔑 Ключи:\n" f" 🌈 Всего сгенерировано: {total_keys}\n" f" ✅ Действующих: {active_keys}\n" f" ❌ Просроченных: {expired_keys}\n\n" f"💰 Финансовая статистика:\n" f" 📅 За день: {total_payments_today} ₽\n" f" 📆 За неделю: {total_payments_week} ₽\n" f" 📆 За месяц: {total_payments_month} ₽\n" f" 🏦 За все время: {total_payments_all_time} ₽\n\n" f" ⏳ Последнее обновление: {update_time}" ) await callback_query.message.edit_text(text=stats_message, reply_markup=build_stats_kb()) except TelegramBadRequest as e: if "message is not modified" not in str(e): # skip when Telegram message is not modified logger.error(f"Error in user_stats_menu: {e}") except Exception as e: logger.error(f"Error in user_stats_menu: {e}") @router.callback_query( AdminPanelCallback.filter(F.action == "stats_export_users_csv"), IsAdminFilter(), ) async def handle_export_users_csv(callback_query: CallbackQuery, session: Any): kb = build_admin_back_kb("stats") try: export = await export_users_csv(session) await callback_query.message.answer_document(document=export, caption="📥 Экспорт пользователей в CSV") except Exception as e: logger.error(f"Ошибка при экспорте пользователей в CSV: {e}") await callback_query.message.edit_text(text=f"❗ Произошла ошибка при экспорте: {e}", reply_markup=kb) @router.callback_query( AdminPanelCallback.filter(F.action == "stats_export_payments_csv"), IsAdminFilter(), ) async def handle_export_payments_csv(callback_query: CallbackQuery, session: Any): kb = build_admin_back_kb("stats") try: export = await export_payments_csv(session) await callback_query.message.answer_document(document=export, caption="📥 Экспорт платежей в CSV") except Exception as e: logger.error(f"Ошибка при экспорте платежей в CSV: {e}") await callback_query.message.edit_text(text=f"❗ Произошла ошибка при экспорте: {e}", reply_markup=kb)