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

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)