217 lines
7.7 KiB
Python
217 lines
7.7 KiB
Python
"""
|
|
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)
|