diff --git a/app/handlers/admin/users.py b/app/handlers/admin/users.py
index c786c1cc..dcd29959 100644
--- a/app/handlers/admin/users.py
+++ b/app/handlers/admin/users.py
@@ -23,7 +23,6 @@ from app.localization.texts import get_texts
from app.services.user_service import UserService
from app.services.admin_notification_service import AdminNotificationService
from app.database.crud.promo_group import get_promo_groups_with_counts
-from app.database.crud.subscription import get_subscriptions_statistics
from app.utils.decorators import admin_required, error_handler
from app.utils.formatters import format_datetime, format_time_ago
from app.services.remnawave_service import RemnaWaveService
@@ -899,30 +898,54 @@ async def show_users_statistics(
user_service = UserService()
stats = await user_service.get_user_statistics(db)
+
+ from sqlalchemy import select, func, or_
- from sqlalchemy import select, func
+ current_time = datetime.utcnow()
- sub_stats = await get_subscriptions_statistics(db)
+ active_subscription_query = (
+ select(func.count(Subscription.id))
+ .join(User, Subscription.user_id == User.id)
+ .where(
+ User.status == UserStatus.ACTIVE.value,
+ Subscription.status.in_(
+ [
+ SubscriptionStatus.ACTIVE.value,
+ SubscriptionStatus.TRIAL.value,
+ ]
+ ),
+ Subscription.end_date > current_time,
+ )
+ )
+ users_with_subscription = (
+ await db.execute(active_subscription_query)
+ ).scalar() or 0
- users_with_subscription = int(sub_stats.get("active_subscriptions", 0) or 0)
- trial_users = int(sub_stats.get("trial_subscriptions", 0) or 0)
- paid_users = max(users_with_subscription - trial_users, 0)
+ trial_subscription_query = (
+ select(func.count(Subscription.id))
+ .join(User, Subscription.user_id == User.id)
+ .where(
+ User.status == UserStatus.ACTIVE.value,
+ Subscription.end_date > current_time,
+ or_(
+ Subscription.status == SubscriptionStatus.TRIAL.value,
+ Subscription.is_trial.is_(True),
+ ),
+ )
+ )
+ trial_users = (await db.execute(trial_subscription_query)).scalar() or 0
users_without_subscription = max(
stats["active_users"] - users_with_subscription,
0,
)
-
+
avg_balance_result = await db.execute(
select(func.avg(User.balance_kopeks))
.where(User.status == UserStatus.ACTIVE.value)
)
avg_balance = avg_balance_result.scalar() or 0
- avg_balance_kopeks = int(round(avg_balance))
-
- conversion_percent = (paid_users / max(stats["active_users"], 1) * 100)
- trial_share_percent = (trial_users / max(users_with_subscription, 1) * 100)
-
+
text = f"""
📊 Детальная статистика пользователей
@@ -937,7 +960,7 @@ async def show_users_statistics(
• Без подписки: {users_without_subscription}
💰 Финансы:
-• Средний баланс: {settings.format_price(avg_balance_kopeks)}
+• Средний баланс: {settings.format_price(int(avg_balance))}
📈 Регистрации:
• Сегодня: {stats['new_today']}
@@ -945,8 +968,8 @@ async def show_users_statistics(
• За месяц: {stats['new_month']}
📊 Активность:
-• Конверсия в подписку: {conversion_percent:.1f}%
-• Доля триальных: {trial_share_percent:.1f}%
+• Конверсия в подписку: {(users_with_subscription / max(stats['active_users'], 1) * 100):.1f}%
+• Доля триальных: {(trial_users / max(users_with_subscription, 1) * 100):.1f}%
"""
await callback.message.edit_text(