""" Repository for Revenue model operations. """ from typing import Optional, List from datetime import date from django.db.models import QuerySet, Q from django.utils import timezone from backend.core.models import Revenue from backend.core.repositories.base import BaseRepository class RevenueRepository(BaseRepository[Revenue]): """ Repository for Revenue model operations. """ model = Revenue @classmethod def get_by_account(cls, account_id: str) -> QuerySet[Revenue]: """ Get revenues by account. Args: account_id: The account ID Returns: QuerySet of revenues for the account """ return Revenue.objects.filter(account_id=account_id) @classmethod def get_active(cls) -> QuerySet[Revenue]: """ Get active revenues. Returns: QuerySet of active revenues """ current_date = timezone.now().date() return Revenue.objects.filter( start_date__lte=current_date ).filter( Q(end_date__isnull=True) | Q(end_date__gte=current_date) ) @classmethod def get_active_by_account(cls, account_id: str) -> Optional[Revenue]: """ Get active revenue for an account. Args: account_id: The account ID Returns: Active revenue for the account or None if not found """ current_date = timezone.now().date() return Revenue.objects.filter( account_id=account_id, start_date__lte=current_date ).filter( Q(end_date__isnull=True) | Q(end_date__gte=current_date) ).first() @classmethod def end_revenue(cls, revenue_id: str) -> Optional[Revenue]: """ End a revenue record by setting its end date to today. Args: revenue_id: The revenue ID Returns: The updated revenue or None if not found """ return cls.update(revenue_id, {'end_date': timezone.now().date()}) @classmethod def get_by_date_range(cls, start_date: date = None, end_date: date = None) -> QuerySet[Revenue]: """ Get revenues that were active during a date range. Args: start_date: Start date (inclusive) end_date: End date (inclusive) Returns: QuerySet of revenues active during the date range """ queryset = Revenue.objects.all() if start_date: # Exclude revenues that ended before the start date queryset = queryset.exclude( end_date__isnull=False, end_date__lt=start_date ) if end_date: # Exclude revenues that started after the end date queryset = queryset.exclude(start_date__gt=end_date) return queryset @classmethod def search(cls, search_term: str, search_fields: List[str] = None) -> QuerySet[Revenue]: """ Search revenue records. Args: search_term: The search term search_fields: Optional list of fields to search (ignored, using predefined fields) Returns: QuerySet of matching revenue records """ return super().search( search_term, ['account__name'] ) @classmethod def get_total_revenue(cls, account_id: str = None, start_date: date = None, end_date: date = None) -> float: """ Get total revenue for an account or all accounts within a date range. Args: account_id: Optional account ID to filter by start_date: Optional start date for the period end_date: Optional end date for the period Returns: Total revenue """ revenues = cls.get_by_date_range(start_date, end_date) if account_id: revenues = revenues.filter(account_id=account_id) # Calculate proportional revenue for records that span beyond the range total_revenue = 0 for revenue in revenues: # Get the effective start and end dates for the calculation # (intersection of revenue period and requested period) effective_start = max(revenue.start_date, start_date) if start_date else revenue.start_date current_date = timezone.now().date() if revenue.end_date: effective_end = min(revenue.end_date, end_date) if end_date else revenue.end_date else: effective_end = end_date if end_date else current_date # Calculate days in range days_in_range = (effective_end - effective_start).days + 1 # Calculate total days for revenue period if revenue.end_date: total_days = (revenue.end_date - revenue.start_date).days + 1 else: total_days = (current_date - revenue.start_date).days + 1 # Avoid division by zero if total_days <= 0: total_days = 1 # Calculate proportional revenue proportional_revenue = revenue.amount * (days_in_range / total_days) total_revenue += proportional_revenue return float(total_revenue) @classmethod def get_inactive(cls) -> QuerySet[Revenue]: """ Get inactive revenues. Returns: QuerySet of inactive revenues """ current_date = timezone.now().date() return Revenue.objects.filter(end_date__lt=current_date)