""" Django REST Framework API views for MDT 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, Prefetch from django.utils import timezone from .models import ( MDTNote, MDTContribution, MDTApproval, MDTMention, MDTAttachment, ) from .serializers import ( MDTNoteSerializer, MDTNoteListSerializer, MDTContributionSerializer, MDTApprovalSerializer, MDTMentionSerializer, MDTAttachmentSerializer, ) class MDTNoteViewSet(viewsets.ModelViewSet): """ API endpoint for MDT notes. Provides CRUD operations and additional actions for multidisciplinary team notes. """ queryset = MDTNote.objects.all() permission_classes = [IsAuthenticated] filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] filterset_fields = ['patient', 'status', 'initiated_by', 'tenant'] search_fields = ['title', 'purpose', 'summary', 'recommendations', 'patient__mrn', 'patient__first_name_en', 'patient__last_name_en'] ordering_fields = ['created_at', 'finalized_at'] ordering = ['-created_at'] def get_serializer_class(self): """Use lightweight serializer for list view.""" if self.action == 'list': return MDTNoteListSerializer return MDTNoteSerializer def get_queryset(self): """Optimize queryset with prefetching.""" queryset = super().get_queryset() if self.action == 'retrieve': queryset = queryset.prefetch_related( Prefetch('contributions', queryset=MDTContribution.objects.select_related('contributor', 'clinic')), Prefetch('approvals', queryset=MDTApproval.objects.select_related('approver', 'clinic')), Prefetch('attachments', queryset=MDTAttachment.objects.select_related('uploaded_by')), ) return queryset.select_related('patient', 'initiated_by', 'tenant') @action(detail=False, methods=['get']) def my_notes(self, request): """Get MDT notes where user is a contributor.""" my_notes = self.get_queryset().filter( contributors=request.user ).distinct() page = self.paginate_queryset(my_notes) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(my_notes, many=True) return Response(serializer.data) @action(detail=False, methods=['get']) def pending_approval(self, request): """Get notes pending approval.""" pending_notes = self.get_queryset().filter( status=MDTNote.Status.PENDING_APPROVAL ) serializer = self.get_serializer(pending_notes, many=True) return Response(serializer.data) @action(detail=False, methods=['get']) def finalized(self, request): """Get finalized notes.""" finalized_notes = self.get_queryset().filter( status=MDTNote.Status.FINALIZED ) page = self.paginate_queryset(finalized_notes) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(finalized_notes, many=True) return Response(serializer.data) @action(detail=True, methods=['post']) def finalize(self, request, pk=None): """Finalize an MDT note.""" mdt_note = self.get_object() try: mdt_note.finalize() serializer = self.get_serializer(mdt_note) return Response(serializer.data) except ValueError as e: return Response( {'error': str(e)}, status=status.HTTP_400_BAD_REQUEST ) @action(detail=True, methods=['post']) def archive(self, request, pk=None): """Archive an MDT note.""" mdt_note = self.get_object() if mdt_note.status != MDTNote.Status.FINALIZED: return Response( {'error': 'Only finalized notes can be archived'}, status=status.HTTP_400_BAD_REQUEST ) mdt_note.status = MDTNote.Status.ARCHIVED mdt_note.save() serializer = self.get_serializer(mdt_note) return Response(serializer.data) @action(detail=False, methods=['get']) def statistics(self, request): """Get MDT note statistics.""" queryset = self.get_queryset() stats = { 'total_notes': queryset.count(), 'by_status': dict( queryset.values('status').annotate(count=Count('id')).values_list('status', 'count') ), 'draft_count': queryset.filter(status=MDTNote.Status.DRAFT).count(), 'pending_approval_count': queryset.filter(status=MDTNote.Status.PENDING_APPROVAL).count(), 'finalized_count': queryset.filter(status=MDTNote.Status.FINALIZED).count(), 'archived_count': queryset.filter(status=MDTNote.Status.ARCHIVED).count(), 'total_contributions': MDTContribution.objects.filter(mdt_note__in=queryset).count(), 'total_approvals': MDTApproval.objects.filter(mdt_note__in=queryset, approved=True).count(), } return Response(stats) class MDTContributionViewSet(viewsets.ModelViewSet): """ API endpoint for MDT contributions. """ queryset = MDTContribution.objects.all() serializer_class = MDTContributionSerializer permission_classes = [IsAuthenticated] filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] filterset_fields = ['mdt_note', 'contributor', 'clinic', 'is_final'] search_fields = ['content'] ordering_fields = ['created_at', 'edited_at'] ordering = ['created_at'] def get_queryset(self): """Optimize queryset.""" return super().get_queryset().select_related('mdt_note', 'contributor', 'clinic') @action(detail=False, methods=['get']) def my_contributions(self, request): """Get contributions by current user.""" my_contributions = self.get_queryset().filter(contributor=request.user) serializer = self.get_serializer(my_contributions, many=True) return Response(serializer.data) @action(detail=True, methods=['post']) def mark_final(self, request, pk=None): """Mark contribution as final.""" contribution = self.get_object() if contribution.contributor != request.user: return Response( {'error': 'Only the contributor can mark their contribution as final'}, status=status.HTTP_403_FORBIDDEN ) contribution.is_final = True contribution.save() serializer = self.get_serializer(contribution) return Response(serializer.data) class MDTApprovalViewSet(viewsets.ModelViewSet): """ API endpoint for MDT approvals. """ queryset = MDTApproval.objects.all() serializer_class = MDTApprovalSerializer permission_classes = [IsAuthenticated] filter_backends = [DjangoFilterBackend, filters.OrderingFilter] filterset_fields = ['mdt_note', 'approver', 'clinic', 'approved'] ordering_fields = ['approved_at', 'created_at'] ordering = ['-approved_at'] def get_queryset(self): """Optimize queryset.""" return super().get_queryset().select_related('mdt_note', 'approver', 'clinic') @action(detail=True, methods=['post']) def approve(self, request, pk=None): """Approve an MDT note.""" approval = self.get_object() if approval.approver != request.user: return Response( {'error': 'Only the assigned approver can approve'}, status=status.HTTP_403_FORBIDDEN ) comments = request.data.get('comments', '') approval.approve(comments=comments) serializer = self.get_serializer(approval) return Response(serializer.data) @action(detail=False, methods=['get']) def pending(self, request): """Get pending approvals for current user.""" pending_approvals = self.get_queryset().filter( approver=request.user, approved=False ) serializer = self.get_serializer(pending_approvals, many=True) return Response(serializer.data) class MDTMentionViewSet(viewsets.ReadOnlyModelViewSet): """ API endpoint for MDT mentions (read-only). """ queryset = MDTMention.objects.all() serializer_class = MDTMentionSerializer permission_classes = [IsAuthenticated] filter_backends = [DjangoFilterBackend, filters.OrderingFilter] filterset_fields = ['contribution', 'mentioned_user', 'viewed_at'] ordering_fields = ['created_at', 'viewed_at'] ordering = ['-created_at'] def get_queryset(self): """Optimize queryset.""" return super().get_queryset().select_related('contribution', 'mentioned_user') @action(detail=False, methods=['get']) def my_mentions(self, request): """Get mentions for current user.""" my_mentions = self.get_queryset().filter(mentioned_user=request.user) serializer = self.get_serializer(my_mentions, many=True) return Response(serializer.data) @action(detail=False, methods=['get']) def unread(self, request): """Get unread mentions for current user.""" unread_mentions = self.get_queryset().filter( mentioned_user=request.user, viewed_at__isnull=True ) serializer = self.get_serializer(unread_mentions, many=True) return Response(serializer.data) @action(detail=True, methods=['post']) def mark_viewed(self, request, pk=None): """Mark mention as viewed.""" mention = self.get_object() if mention.mentioned_user != request.user: return Response( {'error': 'Can only mark your own mentions as viewed'}, status=status.HTTP_403_FORBIDDEN ) mention.mark_as_viewed() serializer = self.get_serializer(mention) return Response(serializer.data) class MDTAttachmentViewSet(viewsets.ModelViewSet): """ API endpoint for MDT attachments. """ queryset = MDTAttachment.objects.all() serializer_class = MDTAttachmentSerializer permission_classes = [IsAuthenticated] filter_backends = [DjangoFilterBackend, filters.OrderingFilter] filterset_fields = ['mdt_note', 'file_type', 'uploaded_by'] ordering_fields = ['created_at'] ordering = ['-created_at'] def get_queryset(self): """Optimize queryset.""" return super().get_queryset().select_related('mdt_note', 'uploaded_by') @action(detail=False, methods=['get']) def by_note(self, request): """Get attachments for a specific MDT note.""" mdt_note_id = request.query_params.get('mdt_note_id') if not mdt_note_id: return Response( {'error': 'mdt_note_id parameter required'}, status=status.HTTP_400_BAD_REQUEST ) attachments = self.get_queryset().filter(mdt_note_id=mdt_note_id) serializer = self.get_serializer(attachments, many=True) return Response(serializer.data)