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"]) # Helper function to get the start of the week, month, and day 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 the current week (Monday) start_of_month = start_of_day.replace( day=1, hour=0, minute=0, second=0, microsecond=0 ) # Start of the current month 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() # Sum up the payments made today using Tortoise ORM's annotate and values 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() # Sum up the payments made in the current week 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() # Sum up the payments made in the current month 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(): # Get the start of the day and 6 days ago (total of 7 days including today) start_of_day, _, _ = get_time_frames() seven_days_ago = start_of_day - timedelta(days=6) # Find all payments in the last 7 days payments = await Payment.filter(created_time__gte=seven_days_ago).values( "user_id", "created_time" ) # Initialize a dictionary to hold payment dates per user user_payment_dates = {} # Collect payment dates per user 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) # Calculate the set of dates we expect payments on expected_dates = set((start_of_day - timedelta(days=i)).date() for i in range(7)) # Filter users who have made payments on each expected date recurring_users = [ user_id for user_id, payment_dates in user_payment_dates.items() if payment_dates == expected_dates ] # Fetch user details for recurring users recurring_user_details = await User.filter(id__in=recurring_users).all() return [ RecurringUserResponse( user_id=str(user.id), username=user.username, # Adjust this field based on your User model email=user.email, # Adjust as necessary ) for user in recurring_user_details ]