326 lines
12 KiB
Python
326 lines
12 KiB
Python
"""
|
|
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)
|