mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-20 03:40:26 +00:00
295 lines
11 KiB
Python
295 lines
11 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from app.database.crud.referral import get_referral_statistics
|
|
from app.database.crud.subscription import get_subscriptions_statistics, get_trial_statistics
|
|
from app.database.crud.transaction import get_transactions_statistics
|
|
from app.database.crud.user import get_users_statistics
|
|
|
|
from fastapi import APIRouter, Depends, Security
|
|
from sqlalchemy import func, select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.database.models import (
|
|
Subscription,
|
|
SubscriptionStatus,
|
|
Ticket,
|
|
TicketStatus,
|
|
Transaction,
|
|
TransactionType,
|
|
User,
|
|
UserStatus,
|
|
)
|
|
|
|
from ..dependencies import get_db_session, require_api_token
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def _kopeks_to_rubles(value: int | float | None) -> float:
|
|
return round((value or 0) / 100, 2)
|
|
|
|
|
|
async def _get_overview(db: AsyncSession) -> dict[str, object]:
|
|
total_users = await db.scalar(select(func.count()).select_from(User)) or 0
|
|
active_users = await db.scalar(
|
|
select(func.count()).select_from(User).where(User.status == UserStatus.ACTIVE.value)
|
|
) or 0
|
|
blocked_users = await db.scalar(
|
|
select(func.count()).select_from(User).where(User.status == UserStatus.BLOCKED.value)
|
|
) or 0
|
|
|
|
total_balance_kopeks = await db.scalar(
|
|
select(func.coalesce(func.sum(User.balance_kopeks), 0))
|
|
) or 0
|
|
|
|
active_subscriptions = await db.scalar(
|
|
select(func.count()).select_from(Subscription).where(
|
|
Subscription.status == SubscriptionStatus.ACTIVE.value,
|
|
)
|
|
) or 0
|
|
|
|
expired_subscriptions = await db.scalar(
|
|
select(func.count()).select_from(Subscription).where(
|
|
Subscription.status == SubscriptionStatus.EXPIRED.value,
|
|
)
|
|
) or 0
|
|
|
|
pending_tickets = await db.scalar(
|
|
select(func.count()).select_from(Ticket).where(
|
|
Ticket.status.in_([TicketStatus.OPEN.value, TicketStatus.ANSWERED.value])
|
|
)
|
|
) or 0
|
|
|
|
today = datetime.utcnow().date()
|
|
today_transactions = await db.scalar(
|
|
select(func.coalesce(func.sum(Transaction.amount_kopeks), 0)).where(
|
|
func.date(Transaction.created_at) == today,
|
|
Transaction.type == TransactionType.DEPOSIT.value,
|
|
)
|
|
) or 0
|
|
|
|
return {
|
|
"users": {
|
|
"total": total_users,
|
|
"active": active_users,
|
|
"blocked": blocked_users,
|
|
"balance_kopeks": int(total_balance_kopeks),
|
|
"balance_rubles": _kopeks_to_rubles(total_balance_kopeks),
|
|
},
|
|
"subscriptions": {
|
|
"active": active_subscriptions,
|
|
"expired": expired_subscriptions,
|
|
},
|
|
"support": {
|
|
"open_tickets": pending_tickets,
|
|
},
|
|
"payments": {
|
|
"today_kopeks": int(today_transactions),
|
|
"today_rubles": _kopeks_to_rubles(today_transactions),
|
|
},
|
|
}
|
|
|
|
|
|
@router.get(
|
|
"/overview",
|
|
summary="Общая статистика",
|
|
response_description="Агрегированные показатели пользователей, подписок, саппорта и платежей",
|
|
responses={
|
|
200: {
|
|
"content": {
|
|
"application/json": {
|
|
"example": {
|
|
"users": {
|
|
"total": 12345,
|
|
"active": 9876,
|
|
"blocked": 321,
|
|
"balance_kopeks": 1234567,
|
|
"balance_rubles": 12345.67,
|
|
},
|
|
"subscriptions": {
|
|
"active": 4321,
|
|
"expired": 210,
|
|
},
|
|
"support": {
|
|
"open_tickets": 42,
|
|
},
|
|
"payments": {
|
|
"today_kopeks": 654321,
|
|
"today_rubles": 6543.21,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
)
|
|
async def stats_overview(
|
|
_: object = Security(require_api_token),
|
|
db: AsyncSession = Depends(get_db_session),
|
|
) -> dict[str, object]:
|
|
return await _get_overview(db)
|
|
|
|
|
|
@router.get(
|
|
"/full",
|
|
summary="Полная статистика",
|
|
response_description="Расширенные показатели пользователей, подписок, платежей и рефералов",
|
|
responses={
|
|
200: {
|
|
"content": {
|
|
"application/json": {
|
|
"example": {
|
|
"overview": {
|
|
"users": {
|
|
"total": 12345,
|
|
"active": 9876,
|
|
"blocked": 321,
|
|
"balance_kopeks": 1234567,
|
|
"balance_rubles": 12345.67,
|
|
},
|
|
"subscriptions": {
|
|
"active": 4321,
|
|
"expired": 210,
|
|
},
|
|
"support": {
|
|
"open_tickets": 42,
|
|
},
|
|
"payments": {
|
|
"today_kopeks": 654321,
|
|
"today_rubles": 6543.21,
|
|
},
|
|
},
|
|
"users": {
|
|
"total_users": 12345,
|
|
"active_users": 9876,
|
|
"blocked_users": 321,
|
|
"new_today": 12,
|
|
"new_week": 345,
|
|
"new_month": 1234,
|
|
},
|
|
"subscriptions": {
|
|
"total_subscriptions": 9876,
|
|
"active_subscriptions": 8765,
|
|
"trial_subscriptions": 321,
|
|
"paid_subscriptions": 8444,
|
|
"purchased_today": 12,
|
|
"purchased_week": 210,
|
|
"purchased_month": 765,
|
|
"trial_to_paid_conversion": 42.5,
|
|
"renewals_count": 123,
|
|
"trial_statistics": {
|
|
"used_trials": 555,
|
|
"active_trials": 210,
|
|
"resettable_trials": 42,
|
|
},
|
|
},
|
|
"transactions": {
|
|
"period": {
|
|
"start_date": "2024-06-01T00:00:00Z",
|
|
"end_date": "2024-06-30T23:59:59Z",
|
|
},
|
|
"totals": {
|
|
"income_kopeks": 1234567,
|
|
"income_rubles": 12345.67,
|
|
"expenses_kopeks": 21000,
|
|
"expenses_rubles": 210,
|
|
"profit_kopeks": 1213567,
|
|
"profit_rubles": 12135.67,
|
|
"subscription_income_kopeks": 987654,
|
|
"subscription_income_rubles": 9876.54,
|
|
},
|
|
"today": {
|
|
"transactions_count": 42,
|
|
"income_kopeks": 654321,
|
|
"income_rubles": 6543.21,
|
|
},
|
|
"by_type": {
|
|
"deposit": {"count": 123, "amount": 1234567},
|
|
"withdrawal": {"count": 10, "amount": 21000},
|
|
},
|
|
"by_payment_method": {
|
|
"card": {"count": 100, "amount": 1000000}
|
|
},
|
|
},
|
|
"referrals": {
|
|
"users_with_referrals": 4321,
|
|
"active_referrers": 123,
|
|
"total_paid_kopeks": 765432,
|
|
"total_paid_rubles": 7654.32,
|
|
"today_earnings_kopeks": 12345,
|
|
"today_earnings_rubles": 123.45,
|
|
"week_earnings_kopeks": 23456,
|
|
"week_earnings_rubles": 234.56,
|
|
"month_earnings_kopeks": 34567,
|
|
"month_earnings_rubles": 345.67,
|
|
"top_referrers": [
|
|
{
|
|
"user_id": 123456789,
|
|
"display_name": "@testuser",
|
|
"username": "testuser",
|
|
"telegram_id": 123456789,
|
|
"total_earned_kopeks": 54321,
|
|
"referrals_count": 42,
|
|
}
|
|
],
|
|
},
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
)
|
|
async def stats_full(
|
|
_: object = Security(require_api_token),
|
|
db: AsyncSession = Depends(get_db_session),
|
|
) -> dict[str, object]:
|
|
overview = await _get_overview(db)
|
|
|
|
users_stats = await get_users_statistics(db)
|
|
subscriptions_stats = await get_subscriptions_statistics(db)
|
|
trial_stats = await get_trial_statistics(db)
|
|
transactions_stats = await get_transactions_statistics(db)
|
|
referral_stats = await get_referral_statistics(db)
|
|
|
|
transactions_totals = transactions_stats.get("totals", {})
|
|
transactions_today = transactions_stats.get("today", {})
|
|
|
|
transactions_totals = {
|
|
**transactions_totals,
|
|
"income_rubles": _kopeks_to_rubles(transactions_totals.get("income_kopeks")),
|
|
"expenses_rubles": _kopeks_to_rubles(transactions_totals.get("expenses_kopeks")),
|
|
"profit_rubles": _kopeks_to_rubles(transactions_totals.get("profit_kopeks")),
|
|
"subscription_income_rubles": _kopeks_to_rubles(
|
|
transactions_totals.get("subscription_income_kopeks")
|
|
),
|
|
}
|
|
|
|
transactions_today = {
|
|
**transactions_today,
|
|
"income_rubles": _kopeks_to_rubles(transactions_today.get("income_kopeks")),
|
|
}
|
|
|
|
referral_stats = {
|
|
**referral_stats,
|
|
"total_paid_rubles": _kopeks_to_rubles(referral_stats.get("total_paid_kopeks")),
|
|
"today_earnings_rubles": _kopeks_to_rubles(
|
|
referral_stats.get("today_earnings_kopeks")
|
|
),
|
|
"week_earnings_rubles": _kopeks_to_rubles(referral_stats.get("week_earnings_kopeks")),
|
|
"month_earnings_rubles": _kopeks_to_rubles(referral_stats.get("month_earnings_kopeks")),
|
|
}
|
|
|
|
return {
|
|
"overview": overview,
|
|
"users": users_stats,
|
|
"subscriptions": {**subscriptions_stats, "trial_statistics": trial_stats},
|
|
"transactions": {
|
|
**transactions_stats,
|
|
"totals": transactions_totals,
|
|
"today": transactions_today,
|
|
},
|
|
"referrals": referral_stats,
|
|
}
|