""" DRF API ViewSets for Referrals 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.utils import timezone from django.db.models import Q, Count from .models import Referral from .serializers import ( ReferralListSerializer, ReferralDetailSerializer, ReferralCreateSerializer, ReferralResponseSerializer, ) class ReferralViewSet(viewsets.ModelViewSet): """ API endpoint for Referral CRUD and workflow operations. list: Get list of referrals retrieve: Get referral details create: Create new referral update: Update referral destroy: Delete referral Custom actions: - accept: Accept referral - reject: Reject referral - complete: Complete referral - sent: Get sent referrals - received: Get received referrals """ permission_classes = [IsAuthenticated] filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] filterset_fields = ['patient', 'from_clinic', 'to_clinic', 'status', 'urgency', 'is_internal'] search_fields = ['patient__mrn', 'patient__first_name_en', 'reason'] ordering_fields = ['created_at', 'urgency'] ordering = ['-created_at'] def get_queryset(self): """Filter by tenant.""" return Referral.objects.filter( tenant=self.request.user.tenant ).select_related( 'patient', 'from_clinic', 'to_clinic', 'from_provider__user', 'to_provider__user' ) def get_serializer_class(self): """Return appropriate serializer based on action.""" if self.action == 'list': return ReferralListSerializer elif self.action == 'create': return ReferralCreateSerializer elif self.action in ['accept', 'reject']: return ReferralResponseSerializer return ReferralDetailSerializer def perform_create(self, serializer): """Set tenant and from_provider on create.""" serializer.save( tenant=self.request.user.tenant, from_provider=self.request.user, status='PENDING' ) @action(detail=True, methods=['post']) def accept(self, request, pk=None): """Accept a pending referral.""" referral = self.get_object() if referral.status != 'PENDING': return Response( {'error': 'Only pending referrals can be accepted'}, status=status.HTTP_400_BAD_REQUEST ) serializer = ReferralResponseSerializer(data=request.data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) referral.status = 'ACCEPTED' referral.response_notes = serializer.validated_data['response_notes'] referral.responded_at = timezone.now() referral.save() detail_serializer = ReferralDetailSerializer(referral) return Response(detail_serializer.data) @action(detail=True, methods=['post']) def reject(self, request, pk=None): """Reject a pending referral.""" referral = self.get_object() if referral.status != 'PENDING': return Response( {'error': 'Only pending referrals can be rejected'}, status=status.HTTP_400_BAD_REQUEST ) serializer = ReferralResponseSerializer(data=request.data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) referral.status = 'REJECTED' referral.response_notes = serializer.validated_data['response_notes'] referral.responded_at = timezone.now() referral.save() detail_serializer = ReferralDetailSerializer(referral) return Response(detail_serializer.data) @action(detail=True, methods=['post']) def complete(self, request, pk=None): """Complete an accepted referral.""" referral = self.get_object() if referral.status != 'ACCEPTED': return Response( {'error': 'Only accepted referrals can be completed'}, status=status.HTTP_400_BAD_REQUEST ) referral.status = 'COMPLETED' referral.completed_at = timezone.now() referral.save() serializer = ReferralDetailSerializer(referral) return Response(serializer.data) @action(detail=False, methods=['get']) def sent(self, request): """Get referrals sent by current user's clinic.""" # Get user's clinic(s) user_clinics = request.user.provider.specialties.all() if hasattr(request.user, 'provider') else [] referrals = self.get_queryset().filter( from_clinic__in=user_clinics ) serializer = ReferralListSerializer(referrals, many=True) return Response(serializer.data) @action(detail=False, methods=['get']) def received(self, request): """Get referrals received by current user's clinic.""" # Get user's clinic(s) user_clinics = request.user.provider.specialties.all() if hasattr(request.user, 'provider') else [] referrals = self.get_queryset().filter( to_clinic__in=user_clinics, is_internal=True ) serializer = ReferralListSerializer(referrals, many=True) return Response(serializer.data) @action(detail=False, methods=['get']) def pending(self, request): """Get pending referrals.""" referrals = self.get_queryset().filter(status='PENDING') serializer = ReferralListSerializer(referrals, many=True) return Response(serializer.data) @action(detail=False, methods=['get']) def urgent(self, request): """Get urgent referrals.""" referrals = self.get_queryset().filter( urgency__in=['URGENT', 'EMERGENCY'], status='PENDING' ) serializer = ReferralListSerializer(referrals, many=True) return Response(serializer.data) @action(detail=False, methods=['get']) def statistics(self, request): """Get referral statistics.""" queryset = self.get_queryset() stats = { 'total': queryset.count(), 'by_status': dict(queryset.values('status').annotate( count=Count('id') ).values_list('status', 'count')), 'by_urgency': dict(queryset.values('urgency').annotate( count=Count('id') ).values_list('urgency', 'count')), 'internal': queryset.filter(is_internal=True).count(), 'external': queryset.filter(is_internal=False).count(), 'pending': queryset.filter(status='PENDING').count(), 'urgent_pending': queryset.filter( urgency__in=['URGENT', 'EMERGENCY'], status='PENDING' ).count(), } return Response(stats) @action(detail=False, methods=['get']) def workflow(self, request): """Get referral workflow statistics.""" queryset = self.get_queryset() workflow_stats = { 'pending': queryset.filter(status='PENDING').count(), 'accepted': queryset.filter(status='ACCEPTED').count(), 'completed': queryset.filter(status='COMPLETED').count(), 'rejected': queryset.filter(status='REJECTED').count(), } return Response(workflow_stats)