HH/apps/analytics/ui_views.py
2025-12-24 12:42:31 +03:00

118 lines
3.7 KiB
Python

"""
Analytics Console UI views
"""
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.db.models import Avg, Count
from django.shortcuts import render
from apps.complaints.models import Complaint
from apps.organizations.models import Department, Hospital
from apps.px_action_center.models import PXAction
from apps.surveys.models import SurveyInstance
from .models import KPI, KPIValue
@login_required
def analytics_dashboard(request):
"""
Analytics dashboard with KPIs and charts.
Features:
- KPI cards with current values
- Trend charts
- Department rankings
- Physician rankings
"""
user = request.user
# Get hospital filter
hospital_filter = request.GET.get('hospital')
if hospital_filter:
hospital = Hospital.objects.filter(id=hospital_filter).first()
elif user.hospital:
hospital = user.hospital
else:
hospital = None
# Calculate key metrics
complaints_queryset = Complaint.objects.all()
actions_queryset = PXAction.objects.all()
surveys_queryset = SurveyInstance.objects.filter(status='completed')
if hospital:
complaints_queryset = complaints_queryset.filter(hospital=hospital)
actions_queryset = actions_queryset.filter(hospital=hospital)
surveys_queryset = surveys_queryset.filter(survey_template__hospital=hospital)
# KPI calculations
kpis = {
'total_complaints': complaints_queryset.count(),
'open_complaints': complaints_queryset.filter(status='open').count(),
'overdue_complaints': complaints_queryset.filter(is_overdue=True).count(),
'total_actions': actions_queryset.count(),
'open_actions': actions_queryset.filter(status='open').count(),
'overdue_actions': actions_queryset.filter(is_overdue=True).count(),
'avg_survey_score': surveys_queryset.aggregate(avg=Avg('total_score'))['avg'] or 0,
'negative_surveys': surveys_queryset.filter(is_negative=True).count(),
}
# Department rankings (top 5 by survey score)
department_rankings = Department.objects.filter(
status='active'
).annotate(
avg_score=Avg('journey_stages__survey_instance__total_score'),
survey_count=Count('journey_stages__survey_instance')
).filter(
survey_count__gt=0
).order_by('-avg_score')[:5]
# Get hospitals for filter
hospitals = Hospital.objects.filter(status='active')
if not user.is_px_admin() and user.hospital:
hospitals = hospitals.filter(id=user.hospital.id)
context = {
'kpis': kpis,
'department_rankings': department_rankings,
'hospitals': hospitals,
'selected_hospital': hospital,
}
return render(request, 'analytics/dashboard.html', context)
@login_required
def kpi_list(request):
"""KPI definitions list view"""
queryset = KPI.objects.all()
# Apply filters
category_filter = request.GET.get('category')
if category_filter:
queryset = queryset.filter(category=category_filter)
is_active = request.GET.get('is_active')
if is_active == 'true':
queryset = queryset.filter(is_active=True)
elif is_active == 'false':
queryset = queryset.filter(is_active=False)
# Ordering
queryset = queryset.order_by('category', 'name')
# Pagination
page_size = int(request.GET.get('page_size', 25))
paginator = Paginator(queryset, page_size)
page_number = request.GET.get('page', 1)
page_obj = paginator.get_page(page_number)
context = {
'page_obj': page_obj,
'kpis': page_obj.object_list,
'filters': request.GET,
}
return render(request, 'analytics/kpi_list.html', context)