|
from fastapi import APIRouter |
|
from typing import List |
|
from datetime import datetime, timedelta |
|
from decimal import Decimal |
|
from tortoise.functions import Sum |
|
|
|
from App.Payments.Model import Payment |
|
from App.Users.Model import User |
|
from .Schema import ( |
|
RevenueMetricsResponse, |
|
RecurringUserResponse, |
|
) |
|
|
|
metrics_router = APIRouter(tags=["Metrics"]) |
|
|
|
|
|
|
|
def get_time_frames(): |
|
today = datetime.now() |
|
start_of_day = today.replace(hour=0, minute=0, second=0, microsecond=0) |
|
start_of_week = start_of_day - timedelta( |
|
days=start_of_day.weekday() |
|
) |
|
start_of_month = start_of_day.replace( |
|
day=1, hour=0, minute=0, second=0, microsecond=0 |
|
) |
|
|
|
return start_of_day, start_of_week, start_of_month |
|
|
|
|
|
@metrics_router.get("/metrics/revenue/daily", response_model=RevenueMetricsResponse) |
|
async def get_daily_revenue(): |
|
start_of_day, _, _ = get_time_frames() |
|
|
|
|
|
revenue_data = ( |
|
await Payment.filter(created_time__gte=start_of_day) |
|
.annotate(total_revenue=Sum("amount")) |
|
.values("total_revenue") |
|
) |
|
|
|
if revenue_data and revenue_data[0]["total_revenue"] is not None: |
|
total_revenue = revenue_data[0]["total_revenue"] |
|
else: |
|
total_revenue = Decimal("0.00") |
|
|
|
return RevenueMetricsResponse( |
|
period="daily", |
|
revenue=float(total_revenue), |
|
) |
|
|
|
|
|
@metrics_router.get("/metrics/revenue/weekly", response_model=RevenueMetricsResponse) |
|
async def get_weekly_revenue(): |
|
_, start_of_week, _ = get_time_frames() |
|
|
|
|
|
revenue_data = ( |
|
await Payment.filter(created_time__gte=start_of_week) |
|
.annotate(total_revenue=Sum("amount")) |
|
.values("total_revenue") |
|
) |
|
|
|
if revenue_data and revenue_data[0]["total_revenue"] is not None: |
|
total_revenue = revenue_data[0]["total_revenue"] |
|
else: |
|
total_revenue = Decimal("0.00") |
|
|
|
return RevenueMetricsResponse( |
|
period="weekly", |
|
revenue=float(total_revenue), |
|
) |
|
|
|
|
|
@metrics_router.get("/metrics/revenue/monthly", response_model=RevenueMetricsResponse) |
|
async def get_monthly_revenue(): |
|
_, _, start_of_month = get_time_frames() |
|
|
|
|
|
revenue_data = ( |
|
await Payment.filter(created_time__gte=start_of_month) |
|
.annotate(total_revenue=Sum("amount")) |
|
.values("total_revenue") |
|
) |
|
|
|
if revenue_data and revenue_data[0]["total_revenue"] is not None: |
|
total_revenue = revenue_data[0]["total_revenue"] |
|
else: |
|
total_revenue = Decimal("0.00") |
|
|
|
return RevenueMetricsResponse( |
|
period="monthly", |
|
revenue=float(total_revenue), |
|
) |
|
|
|
|
|
@metrics_router.get( |
|
"/metrics/recurring-users", response_model=List[RecurringUserResponse] |
|
) |
|
async def get_recurring_users(): |
|
|
|
start_of_day, _, _ = get_time_frames() |
|
seven_days_ago = start_of_day - timedelta(days=6) |
|
|
|
|
|
payments = await Payment.filter(created_time__gte=seven_days_ago).values( |
|
"user_id", "created_time" |
|
) |
|
|
|
|
|
user_payment_dates = {} |
|
|
|
|
|
for payment in payments: |
|
user_id = payment["user_id"] |
|
payment_date = payment["created_time"].date() |
|
|
|
if user_id not in user_payment_dates: |
|
user_payment_dates[user_id] = set() |
|
|
|
user_payment_dates[user_id].add(payment_date) |
|
|
|
|
|
expected_dates = set((start_of_day - timedelta(days=i)).date() for i in range(7)) |
|
|
|
|
|
recurring_users = [ |
|
user_id |
|
for user_id, payment_dates in user_payment_dates.items() |
|
if payment_dates == expected_dates |
|
] |
|
|
|
|
|
recurring_user_details = await User.filter(id__in=recurring_users).all() |
|
|
|
return [ |
|
RecurringUserResponse( |
|
user_id=str(user.id), |
|
username=user.username, |
|
email=user.email, |
|
) |
|
for user in recurring_user_details |
|
] |
|
|