From 331d140b42b4b69bcbb1bf647a0e981608b8b978 Mon Sep 17 00:00:00 2001 From: Vladless Date: Wed, 28 May 2025 22:49:59 +0300 Subject: [PATCH] restore hot leads export and stats section --- database/statistics.py | 20 +++++++++++- handlers/admin/stats/stats_handler.py | 3 ++ utils/csv_export.py | 47 +++++++++++++++------------ 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/database/statistics.py b/database/statistics.py index 3c99f8b7..e79b539d 100644 --- a/database/statistics.py +++ b/database/statistics.py @@ -1,6 +1,6 @@ from datetime import date, datetime -from sqlalchemy import and_, func, not_, select +from sqlalchemy import and_, func, not_, select, exists from sqlalchemy.ext.asyncio import AsyncSession from database.models import Key, Payment, Referral, Tariff, User @@ -125,3 +125,21 @@ async def sum_total_payments(session: AsyncSession) -> float: ) ) return round(float(result), 2) + + +async def count_hot_leads(session: AsyncSession) -> int: + subquery_active_keys = ( + select(Key.tg_id) + .where(Key.expiry_time > int(datetime.utcnow().timestamp() * 1000)) + .distinct() + ) + + stmt = ( + select(Payment.tg_id) + .where(Payment.status == "success") + .where(not_(exists(subquery_active_keys.where(Key.tg_id == Payment.tg_id)))) + .distinct() + ) + + result = await session.execute(select(func.count()).select_from(stmt.subquery())) + return result.scalar() \ No newline at end of file diff --git a/handlers/admin/stats/stats_handler.py b/handlers/admin/stats/stats_handler.py index f8e0c46c..ad0b8232 100644 --- a/handlers/admin/stats/stats_handler.py +++ b/handlers/admin/stats/stats_handler.py @@ -24,6 +24,7 @@ from database import ( sum_payments_between, sum_payments_since, sum_total_payments, + count_hot_leads ) from filters.admin import IsAdminFilter from logger import logger @@ -117,6 +118,7 @@ async def handle_stats(callback_query: CallbackQuery, session: AsyncSession): session, last_month_start, today.replace(day=1) ) total_payments_all_time = await sum_total_payments(session) + hot_leads_count = await count_hot_leads(session) update_time = datetime.now(moscow_tz).strftime("%d.%m.%y %H:%M:%S") @@ -152,6 +154,7 @@ async def handle_stats(callback_query: CallbackQuery, session: AsyncSession): f"├ 📆 Прошлый месяц: {total_payments_last_month} ₽\n" f"└ 🏦 Всего: {total_payments_all_time} ₽\n" f"\n" + f"🔥 Горячие лиды: {hot_leads_count}\n" f"⏱️ Последнее обновление: {update_time}" ) diff --git a/utils/csv_export.py b/utils/csv_export.py index eb2476b0..0bdbc6d3 100644 --- a/utils/csv_export.py +++ b/utils/csv_export.py @@ -3,7 +3,7 @@ from datetime import datetime from io import StringIO from aiogram.types import BufferedInputFile -from sqlalchemy import func, join, select +from sqlalchemy import func, join, select, exists, not_ from sqlalchemy.ext.asyncio import AsyncSession from database.models import Key, Payment, Referral, Tariff, User @@ -164,41 +164,46 @@ async def export_referrals_csv( async def export_hot_leads_csv(session: AsyncSession) -> BufferedInputFile: - users_alias = User.__table__.alias("u") - payments_alias = Payment.__table__.alias("p") - keys_alias = Key.__table__.alias("k") + now_ts = int(datetime.utcnow().timestamp() * 1000) - j = users_alias.join( - payments_alias, users_alias.c.tg_id == payments_alias.c.tg_id - ).outerjoin(keys_alias, users_alias.c.tg_id == keys_alias.c.tg_id) - - query = ( + stmt = ( select( - users_alias.c.tg_id, - users_alias.c.username, - users_alias.c.first_name, - users_alias.c.last_name, - users_alias.c.updated_at, + User.tg_id, + User.username, + User.first_name, + User.last_name, + User.updated_at, ) - .select_from(j) - .where(payments_alias.c.status == "success", keys_alias.c.tg_id is None) - .distinct() - .order_by(users_alias.c.updated_at.desc()) + .where( + exists( + select(Payment.tg_id) + .where(Payment.tg_id == User.tg_id) + .where(Payment.status == "success") + ), + not_( + exists( + select(Key.client_id) + .where(Key.tg_id == User.tg_id) + .where(Key.expiry_time > now_ts) + ) + ) + ) + .order_by(User.updated_at.desc()) ) - result = await session.execute(query) + result = await session.execute(stmt) users = result.all() buffer = StringIO() writer = csv.writer(buffer) writer.writerow(["tg_id", "username", "first_name", "last_name", "updated_at"]) - for user in users: writer.writerow(user) buffer.seek(0) return BufferedInputFile( - file=buffer.getvalue().encode("utf-8-sig"), filename="hot_leads_export.csv" + file=buffer.getvalue().encode("utf-8-sig"), + filename="hot_leads_export.csv", )