agdar/psychology/api_views.py
Marwan Alwali 2f1681b18c update
2025-11-11 13:44:48 +03:00

396 lines
16 KiB
Python

"""
Django REST Framework API views for psychology app.
"""
from rest_framework import viewsets, filters, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django_filters.rest_framework import DjangoFilterBackend
from django.db.models import Q, Count, Avg
from django.utils import timezone
from datetime import timedelta
from .models import (
PsychologyConsultation,
PsychologyAssessment,
PsychologySession,
PsychologyGoal,
PsychologyProgressReport,
)
from .serializers import (
PsychologyConsultationSerializer,
PsychologyAssessmentSerializer,
PsychologySessionSerializer,
PsychologyGoalSerializer,
PsychologyProgressReportSerializer,
)
class PsychologyConsultationViewSet(viewsets.ModelViewSet):
"""
API endpoint for psychology consultations.
Provides CRUD operations and additional actions for consultations.
"""
queryset = PsychologyConsultation.objects.all()
serializer_class = PsychologyConsultationSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['patient', 'provider', 'referral_reason', 'suicide_risk', 'homicide_risk', 'tenant']
search_fields = ['patient__first_name_en', 'patient__last_name_en', 'patient__mrn',
'presenting_problem', 'clinical_impressions', 'provisional_diagnosis']
ordering_fields = ['consultation_date', 'created_at']
ordering = ['-consultation_date']
def get_queryset(self):
"""Filter queryset based on user permissions."""
queryset = super().get_queryset()
return queryset.select_related('patient', 'provider', 'tenant', 'appointment')
@action(detail=False, methods=['get'])
def high_risk(self, request):
"""Get consultations with high suicide or homicide risk."""
high_risk_consultations = self.get_queryset().filter(
Q(suicide_risk__in=['MODERATE', 'HIGH']) |
Q(homicide_risk__in=['MODERATE', 'HIGH'])
)
serializer = self.get_serializer(high_risk_consultations, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def recent(self, request):
"""Get consultations from the last 30 days."""
thirty_days_ago = timezone.now().date() - timedelta(days=30)
recent_consultations = self.get_queryset().filter(
consultation_date__gte=thirty_days_ago
)
serializer = self.get_serializer(recent_consultations, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def statistics(self, request):
"""Get consultation statistics."""
queryset = self.get_queryset()
stats = {
'total_consultations': queryset.count(),
'by_referral_reason': dict(
queryset.values('referral_reason').annotate(count=Count('id')).values_list('referral_reason', 'count')
),
'high_risk_count': queryset.filter(
Q(suicide_risk__in=['MODERATE', 'HIGH']) |
Q(homicide_risk__in=['MODERATE', 'HIGH'])
).count(),
'signed_count': queryset.filter(signed_by__isnull=False).count(),
'unsigned_count': queryset.filter(signed_by__isnull=True).count(),
}
return Response(stats)
@action(detail=True, methods=['post'])
def sign(self, request, pk=None):
"""Sign a consultation."""
consultation = self.get_object()
if consultation.signed_by:
return Response(
{'error': 'Consultation already signed'},
status=status.HTTP_400_BAD_REQUEST
)
consultation.signed_by = request.user
consultation.signed_at = timezone.now()
consultation.save()
serializer = self.get_serializer(consultation)
return Response(serializer.data)
class PsychologyAssessmentViewSet(viewsets.ModelViewSet):
"""
API endpoint for psychology assessments.
Provides CRUD operations and additional actions for assessments.
"""
queryset = PsychologyAssessment.objects.all()
serializer_class = PsychologyAssessmentSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['patient', 'provider', 'assessment_type', 'tenant']
search_fields = ['patient__first_name_en', 'patient__last_name_en', 'patient__mrn',
'reason_for_assessment', 'diagnostic_impressions', 'dsm5_diagnosis']
ordering_fields = ['assessment_date', 'created_at']
ordering = ['-assessment_date']
def get_queryset(self):
"""Filter queryset based on user permissions."""
queryset = super().get_queryset()
return queryset.select_related('patient', 'provider', 'tenant', 'appointment')
@action(detail=False, methods=['get'])
def by_type(self, request):
"""Get assessments grouped by type."""
assessment_type = request.query_params.get('type')
if assessment_type:
assessments = self.get_queryset().filter(assessment_type=assessment_type)
else:
assessments = self.get_queryset()
serializer = self.get_serializer(assessments, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def statistics(self, request):
"""Get assessment statistics."""
queryset = self.get_queryset()
stats = {
'total_assessments': queryset.count(),
'by_type': dict(
queryset.values('assessment_type').annotate(count=Count('id')).values_list('assessment_type', 'count')
),
'signed_count': queryset.filter(signed_by__isnull=False).count(),
'unsigned_count': queryset.filter(signed_by__isnull=True).count(),
}
return Response(stats)
class PsychologySessionViewSet(viewsets.ModelViewSet):
"""
API endpoint for psychology sessions.
Provides CRUD operations and additional actions for sessions.
"""
queryset = PsychologySession.objects.all()
serializer_class = PsychologySessionSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['patient', 'provider', 'session_type', 'therapy_modality', 'current_risk_level', 'tenant']
search_fields = ['patient__first_name_en', 'patient__last_name_en', 'patient__mrn',
'presenting_issues', 'interventions_used', 'clinical_notes']
ordering_fields = ['session_date', 'session_number', 'created_at']
ordering = ['-session_date', '-session_number']
def get_queryset(self):
"""Filter queryset based on user permissions."""
queryset = super().get_queryset()
return queryset.select_related('patient', 'provider', 'tenant', 'appointment')
@action(detail=False, methods=['get'])
def by_patient(self, request):
"""Get all sessions for a specific patient."""
patient_id = request.query_params.get('patient_id')
if not patient_id:
return Response(
{'error': 'patient_id parameter required'},
status=status.HTTP_400_BAD_REQUEST
)
sessions = self.get_queryset().filter(patient_id=patient_id)
serializer = self.get_serializer(sessions, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def high_risk(self, request):
"""Get sessions with high risk levels."""
high_risk_sessions = self.get_queryset().filter(
current_risk_level__in=['MODERATE', 'HIGH']
)
serializer = self.get_serializer(high_risk_sessions, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def statistics(self, request):
"""Get session statistics."""
queryset = self.get_queryset()
stats = {
'total_sessions': queryset.count(),
'by_type': dict(
queryset.values('session_type').annotate(count=Count('id')).values_list('session_type', 'count')
),
'by_modality': dict(
queryset.values('therapy_modality').annotate(count=Count('id')).values_list('therapy_modality', 'count')
),
'average_duration': queryset.aggregate(avg_duration=Avg('duration_minutes'))['avg_duration'],
'high_risk_count': queryset.filter(current_risk_level__in=['MODERATE', 'HIGH']).count(),
'signed_count': queryset.filter(signed_by__isnull=False).count(),
'unsigned_count': queryset.filter(signed_by__isnull=True).count(),
}
return Response(stats)
@action(detail=False, methods=['get'])
def recent(self, request):
"""Get sessions from the last 30 days."""
thirty_days_ago = timezone.now().date() - timedelta(days=30)
recent_sessions = self.get_queryset().filter(
session_date__gte=thirty_days_ago
)
serializer = self.get_serializer(recent_sessions, many=True)
return Response(serializer.data)
class PsychologyGoalViewSet(viewsets.ModelViewSet):
"""
API endpoint for psychology goals.
Provides CRUD operations and additional actions for goals.
"""
queryset = PsychologyGoal.objects.all()
serializer_class = PsychologyGoalSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['patient', 'consultation', 'status']
search_fields = ['patient__first_name_en', 'patient__last_name_en', 'patient__mrn',
'goal_description', 'progress_notes']
ordering_fields = ['target_date', 'progress_percentage', 'created_at']
ordering = ['target_date']
def get_queryset(self):
"""Filter queryset based on user permissions."""
queryset = super().get_queryset()
return queryset.select_related('patient', 'consultation')
@action(detail=False, methods=['get'])
def active(self, request):
"""Get active goals (in progress)."""
active_goals = self.get_queryset().filter(status='IN_PROGRESS')
serializer = self.get_serializer(active_goals, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def achieved(self, request):
"""Get achieved goals."""
achieved_goals = self.get_queryset().filter(status='ACHIEVED')
serializer = self.get_serializer(achieved_goals, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def overdue(self, request):
"""Get overdue goals."""
today = timezone.now().date()
overdue_goals = self.get_queryset().filter(
target_date__lt=today,
status__in=['NOT_STARTED', 'IN_PROGRESS']
)
serializer = self.get_serializer(overdue_goals, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def statistics(self, request):
"""Get goal statistics."""
queryset = self.get_queryset()
stats = {
'total_goals': queryset.count(),
'by_status': dict(
queryset.values('status').annotate(count=Count('id')).values_list('status', 'count')
),
'average_progress': queryset.aggregate(avg_progress=Avg('progress_percentage'))['avg_progress'],
'achieved_count': queryset.filter(status='ACHIEVED').count(),
'in_progress_count': queryset.filter(status='IN_PROGRESS').count(),
'overdue_count': queryset.filter(
target_date__lt=timezone.now().date(),
status__in=['NOT_STARTED', 'IN_PROGRESS']
).count(),
}
return Response(stats)
@action(detail=True, methods=['post'])
def update_progress(self, request, pk=None):
"""Update goal progress percentage."""
goal = self.get_object()
progress = request.data.get('progress_percentage')
if progress is None:
return Response(
{'error': 'progress_percentage required'},
status=status.HTTP_400_BAD_REQUEST
)
try:
progress = int(progress)
if not 0 <= progress <= 100:
raise ValueError
except (ValueError, TypeError):
return Response(
{'error': 'progress_percentage must be between 0 and 100'},
status=status.HTTP_400_BAD_REQUEST
)
goal.progress_percentage = progress
# Auto-update status based on progress
if progress == 0:
goal.status = 'NOT_STARTED'
elif progress == 100:
goal.status = 'ACHIEVED'
goal.achieved_date = timezone.now().date()
else:
goal.status = 'IN_PROGRESS'
goal.save()
serializer = self.get_serializer(goal)
return Response(serializer.data)
class PsychologyProgressReportViewSet(viewsets.ModelViewSet):
"""
API endpoint for psychology progress reports.
Provides CRUD operations and additional actions for progress reports.
"""
queryset = PsychologyProgressReport.objects.all()
serializer_class = PsychologyProgressReportSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['patient', 'provider', 'continue_treatment', 'tenant']
search_fields = ['patient__first_name_en', 'patient__last_name_en', 'patient__mrn',
'presenting_problems_summary', 'overall_progress', 'recommendations']
ordering_fields = ['report_date', 'created_at']
ordering = ['-report_date']
def get_queryset(self):
"""Filter queryset based on user permissions."""
queryset = super().get_queryset()
return queryset.select_related('patient', 'provider', 'tenant')
@action(detail=False, methods=['get'])
def recent(self, request):
"""Get reports from the last 90 days."""
ninety_days_ago = timezone.now().date() - timedelta(days=90)
recent_reports = self.get_queryset().filter(
report_date__gte=ninety_days_ago
)
serializer = self.get_serializer(recent_reports, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def discharge_ready(self, request):
"""Get reports recommending discharge."""
discharge_reports = self.get_queryset().filter(continue_treatment=False)
serializer = self.get_serializer(discharge_reports, many=True)
return Response(serializer.data)
@action(detail=False, methods=['get'])
def statistics(self, request):
"""Get progress report statistics."""
queryset = self.get_queryset()
stats = {
'total_reports': queryset.count(),
'continue_treatment_count': queryset.filter(continue_treatment=True).count(),
'discharge_recommended_count': queryset.filter(continue_treatment=False).count(),
'average_attendance_rate': queryset.aggregate(
avg_attendance=Avg('sessions_attended') / Avg('sessions_scheduled') * 100
),
'signed_count': queryset.filter(signed_by__isnull=False).count(),
'unsigned_count': queryset.filter(signed_by__isnull=True).count(),
}
return Response(stats)