nexus-3/backend/core/services/reporting.py
2026-01-26 10:30:49 -05:00

160 lines
5.8 KiB
Python

"""
Reporting services for analytics and business intelligence.
"""
from typing import Dict, Any, List
from datetime import date, timedelta
from django.utils import timezone
from backend.core.repositories.services.services import ServiceRepository
from backend.core.repositories.projects.projects import ProjectRepository
from backend.core.repositories.invoices.invoices import InvoiceRepository
from backend.core.repositories.reports.reports import ReportRepository
from backend.core.repositories.revenues.revenues import RevenueRepository
from backend.core.repositories.labor.labor import LaborRepository
class ReportingService:
"""
Service for generating business reports and analytics.
"""
@staticmethod
def get_monthly_summary(year: int, month: int) -> Dict[str, Any]:
"""
Get monthly business summary.
Args:
year: Year
month: Month (1-12)
Returns:
Dictionary with monthly summary data
"""
# Calculate date range for the month
start_date = date(year, month, 1)
if month == 12:
end_date = date(year + 1, 1, 1) - timedelta(days=1)
else:
end_date = date(year, month + 1, 1) - timedelta(days=1)
# Get services in the month
services = ServiceRepository.get_by_date_range(start_date, end_date)
# Get projects in the month
projects = ProjectRepository.get_by_date_range(start_date, end_date)
# Get invoices in the month
invoices = InvoiceRepository.get_by_date_range(start_date, end_date)
# Get paid invoices in the month
paid_invoices = invoices.filter(status='paid')
# Calculate total revenue and labor for the month
total_revenue = RevenueRepository.get_total_revenue(None, start_date, end_date)
total_labor = LaborRepository.get_total_labor_cost(None, start_date, end_date)
# Calculate profit
profit = total_revenue - total_labor
# Service statistics
service_stats = {
'total': services.count(),
'completed': services.filter(status='completed').count(),
'cancelled': services.filter(status='cancelled').count(),
'completion_rate': services.filter(
status='completed').count() / services.count() if services.count() > 0 else 0
}
# Project statistics
project_stats = {
'total': projects.count(),
'completed': projects.filter(status='completed').count(),
'cancelled': projects.filter(status='cancelled').count(),
'completion_rate': projects.filter(
status='completed').count() / projects.count() if projects.count() > 0 else 0,
'total_amount': sum(p.amount for p in projects),
'total_labor': sum(p.labor for p in projects),
'profit': sum(p.amount - p.labor for p in projects)
}
# Invoice statistics
invoice_stats = {
'total': invoices.count(),
'paid': paid_invoices.count(),
'payment_rate': paid_invoices.count() / invoices.count() if invoices.count() > 0 else 0,
'total_amount': sum(i.total_amount for i in invoices),
'paid_amount': sum(i.total_amount for i in paid_invoices)
}
return {
'period': {
'year': year,
'month': month,
'start_date': start_date.isoformat(),
'end_date': end_date.isoformat()
},
'financials': {
'revenue': total_revenue,
'labor': total_labor,
'profit': profit,
'profit_margin': (profit / total_revenue) * 100 if total_revenue > 0 else 0
},
'services': service_stats,
'projects': project_stats,
'invoices': invoice_stats
}
@staticmethod
def get_team_performance(start_date: date = None, end_date: date = None) -> List[Dict[str, Any]]:
"""
Get team member performance metrics.
Args:
start_date: Start date (inclusive)
end_date: End date (inclusive)
Returns:
List of team member performance data
"""
# Set default date range to current month if not provided
if not start_date:
today = timezone.now().date()
start_date = date(today.year, today.month, 1)
if not end_date:
end_date = timezone.now().date()
# Get team members with activity
team_activity = ReportRepository.get_team_summary(start_date, end_date)
team_performance = []
for member_id, summary in team_activity.get('member_summaries', {}).items():
# Get services completed by the team member
services_completed = ServiceRepository.get_by_team_member(member_id).filter(
status='completed',
date__gte=start_date,
date__lte=end_date
).count()
# Get projects completed by the team member
projects_completed = ProjectRepository.get_by_team_member(member_id).filter(
status='completed',
date__gte=start_date,
date__lte=end_date
).count()
# Calculate metrics
performance = {
'member_id': member_id,
'name': summary['name'],
'reports_submitted': summary['report_count'],
'services_completed': services_completed,
'projects_completed': projects_completed,
'total_work_items': services_completed + projects_completed
}
team_performance.append(performance)
# Sort by total work items descending
team_performance.sort(key=lambda x: x['total_work_items'], reverse=True)
return team_performance