160 lines
5.8 KiB
Python
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 |