118 lines
3.7 KiB
Python
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)
|