diff --git a/handlers/admin/admin_stats.py b/handlers/admin/admin_stats.py index ff5191b6..8a7d836e 100644 --- a/handlers/admin/admin_stats.py +++ b/handlers/admin/admin_stats.py @@ -9,6 +9,7 @@ from filters.admin import IsAdminFilter from keyboards.admin.panel_kb import AdminPanelCallback, build_admin_back_kb from keyboards.admin.stats_kb import build_stats_kb from logger import logger +from utils.csv_export import export_payments_csv, export_users_csv router = Router() @@ -17,7 +18,10 @@ router = Router() AdminPanelCallback.filter(F.action == "stats"), IsAdminFilter(), ) -async def handle_stats(callback_query: CallbackQuery, session: Any): +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") @@ -90,48 +94,18 @@ async def handle_stats(callback_query: CallbackQuery, session: Any): AdminPanelCallback.filter(F.action == "stats_export_users_csv"), IsAdminFilter(), ) -async def handle_export_users_csv(callback_query: CallbackQuery, session: Any): +async def handle_export_users_csv( + callback_query: CallbackQuery, + session: Any +): kb = build_admin_back_kb("stats") try: - users = await session.fetch( - """ - SELECT - u.tg_id, - u.username, - u.first_name, - u.last_name, - u.language_code, - u.is_bot, - c.balance, - c.trial - FROM users u - LEFT JOIN connections c ON u.tg_id = c.tg_id - """ - ) - - if not users: - await callback_query.message.edit_text( - text="📭 Нет пользователей для экспорта.", - reply_markup=kb - ) - return - - csv_data = "tg_id,username,first_name,last_name,language_code,is_bot,balance,trial\n" # Заголовки CSV - for user in users: - csv_data += f"{user['tg_id']},{user['username']},{user['first_name']},{user['last_name']},{user['language_code']},{user['is_bot']},{user['balance']},{user['trial']}\n" - - file_name = BytesIO(csv_data.encode("utf-8-sig")) - file_name.seek(0) - - file = BufferedInputFile(file_name.getvalue(), filename="users_export.csv") - + export = await export_users_csv(session) await callback_query.message.answer_document( - document=file, + document=export, caption="📥 Экспорт пользователей в CSV" ) - file_name.close() - except Exception as e: logger.error(f"Ошибка при экспорте пользователей в CSV: {e}") await callback_query.message.edit_text( @@ -144,47 +118,18 @@ async def handle_export_users_csv(callback_query: CallbackQuery, session: Any): AdminPanelCallback.filter(F.action == "stats_export_payments_csv"), IsAdminFilter(), ) -async def handle_export_payments_csv(callback_query: CallbackQuery, session: Any): +async def handle_export_payments_csv( + callback_query: CallbackQuery, + session: Any +): kb = build_admin_back_kb("stats") try: - payments = await session.fetch( - """ - SELECT - u.tg_id, - u.username, - u.first_name, - u.last_name, - p.amount, - p.payment_system, - p.status, - p.created_at - FROM users u - JOIN payments p ON u.tg_id = p.tg_id - """ - ) - - if not payments: - await callback_query.message.edit_text( - text="📭 Нет платежей для экспорта.", - reply_markup=kb - ) - return - - csv_data = "tg_id,username,first_name,last_name,amount,payment_system,status,created_at\n" # Заголовки CSV - for payment in payments: - csv_data += f"{payment['tg_id']},{payment['username']},{payment['first_name']},{payment['last_name']},{payment['amount']},{payment['payment_system']},{payment['status']},{payment['created_at']}\n" - - file_name = BytesIO(csv_data.encode("utf-8-sig")) - file_name.seek(0) - - file = BufferedInputFile(file_name.getvalue(), filename="payments_export.csv") - + export = await export_payments_csv(session) await callback_query.message.answer_document( - document=file, + document=export, caption="📥 Экспорт платежей в CSV" ) - file_name.close() except Exception as e: logger.error(f"Ошибка при экспорте платежей в CSV: {e}") diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/utils/csv_export.py b/utils/csv_export.py new file mode 100644 index 00000000..08cc1c59 --- /dev/null +++ b/utils/csv_export.py @@ -0,0 +1,101 @@ +from io import StringIO +from typing import Any + +from aiogram.types import BufferedInputFile + + +async def export_users_csv(session: Any) -> BufferedInputFile: + # Получение данных о платежах пользователя + query = """ + SELECT + u.tg_id, + u.username, + u.first_name, + u.last_name, + u.language_code, + u.is_bot, + c.balance, + c.trial + FROM users u + LEFT JOIN connections c ON u.tg_id = c.tg_id + """ + + users = await session.fetch(query) + + buffer = StringIO() + buffer.write("tg_id,username,first_name,last_name,language_code,is_bot,balance,trial\n") + + # Запись данных + for user in users: + buffer.write( + f"{user['tg_id']},{user['username']},{user['first_name']},{user['last_name']}," + f"{user['language_code']},{user['is_bot']},{user['balance']},{user['trial']}\n" + ) + + # Перемещение указателя в начало для чтения + buffer.seek(0) + + return BufferedInputFile( + file=buffer.getvalue().encode("utf-8-sig"), + filename="users_export.csv" + ) + + +async def export_payments_csv(session: Any) -> BufferedInputFile: + # Получение данных о всех платежах + query = """ + SELECT + u.tg_id, + u.username, + u.first_name, + u.last_name, + p.amount, + p.payment_system, + p.status, + p.created_at + FROM users u + JOIN payments p ON u.tg_id = p.tg_id + """ + payments = await session.fetch(query) + return _export_payments_csv(payments, "payments_export.csv") + + +async def export_user_payments_csv(tg_id: int, session: Any) -> BufferedInputFile: + # Получение данных о платежах пользователя + query = """ + SELECT + u.tg_id, + u.username, + u.first_name, + u.last_name, + p.amount, + p.payment_system, + p.status, + p.created_at + FROM users u + JOIN payments p ON u.tg_id = p.tg_id + WHERE u.tg_id = $1 + """ + payments = await session.fetch(query, tg_id) + return _export_payments_csv(payments, f"payments_export_{tg_id}.csv") + + +def _export_payments_csv(payments: list, filename: str) -> BufferedInputFile: + # Формирование CSV данных через StringIO + buffer = StringIO() + buffer.write("tg_id,username,first_name,last_name,amount,payment_system,status,created_at\n") + + # Запись данных + for payment in payments: + buffer.write( + f"{payment['tg_id']},{payment['username']},{payment['first_name']},{payment['last_name']}," + f"{payment['amount']},{payment['payment_system']},{payment['status']},{payment['created_at']}\n" + ) + + # Перемещение указателя в начало для чтения + buffer.seek(0) + + return BufferedInputFile( + file=buffer.getvalue().encode("utf-8-sig"), + filename=filename + )