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",
)