240 lines
7.8 KiB
Python
240 lines
7.8 KiB
Python
"""
|
|
DRF API ViewSets for Core 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
|
|
|
|
from .models import Patient, Clinic, File, SubFile, Consent, Attachment, AuditLog
|
|
from .serializers import (
|
|
PatientListSerializer, PatientDetailSerializer, PatientCreateUpdateSerializer,
|
|
ClinicSerializer, FileSerializer, SubFileSerializer,
|
|
ConsentSerializer, AttachmentSerializer, AuditLogSerializer
|
|
)
|
|
|
|
|
|
class PatientViewSet(viewsets.ModelViewSet):
|
|
"""
|
|
API endpoint for Patient CRUD operations.
|
|
|
|
list: Get list of patients (with search and filters)
|
|
retrieve: Get patient details
|
|
create: Create new patient
|
|
update: Update patient
|
|
partial_update: Partially update patient
|
|
destroy: Soft delete patient
|
|
"""
|
|
|
|
permission_classes = [IsAuthenticated]
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
|
|
filterset_fields = ['gender', 'is_active']
|
|
search_fields = ['mrn', 'first_name_en', 'last_name_en', 'first_name_ar', 'last_name_ar', 'phone']
|
|
ordering_fields = ['created_at', 'mrn', 'first_name_en']
|
|
ordering = ['-created_at']
|
|
|
|
def get_queryset(self):
|
|
"""Filter by tenant."""
|
|
return Patient.objects.filter(tenant=self.request.user.tenant)
|
|
|
|
def get_serializer_class(self):
|
|
"""Return appropriate serializer based on action."""
|
|
if self.action == 'list':
|
|
return PatientListSerializer
|
|
elif self.action in ['create', 'update', 'partial_update']:
|
|
return PatientCreateUpdateSerializer
|
|
return PatientDetailSerializer
|
|
|
|
def perform_create(self, serializer):
|
|
"""Set tenant on create."""
|
|
serializer.save(tenant=self.request.user.tenant)
|
|
|
|
def perform_destroy(self, instance):
|
|
"""Soft delete instead of hard delete."""
|
|
instance.is_active = False
|
|
instance.save()
|
|
|
|
@action(detail=True, methods=['get'])
|
|
def files(self, request, pk=None):
|
|
"""Get patient's files."""
|
|
patient = self.get_object()
|
|
files = File.objects.filter(patient=patient)
|
|
serializer = FileSerializer(files, many=True)
|
|
return Response(serializer.data)
|
|
|
|
@action(detail=True, methods=['get'])
|
|
def consents(self, request, pk=None):
|
|
"""Get patient's consents."""
|
|
patient = self.get_object()
|
|
consents = Consent.objects.filter(patient=patient)
|
|
serializer = ConsentSerializer(consents, many=True)
|
|
return Response(serializer.data)
|
|
|
|
@action(detail=True, methods=['get'])
|
|
def audit_trail(self, request, pk=None):
|
|
"""Get patient's audit trail."""
|
|
patient = self.get_object()
|
|
logs = AuditLog.objects.filter(
|
|
model_name='Patient',
|
|
object_id=str(patient.id)
|
|
).order_by('-timestamp')
|
|
serializer = AuditLogSerializer(logs, many=True)
|
|
return Response(serializer.data)
|
|
|
|
|
|
class ClinicViewSet(viewsets.ReadOnlyModelViewSet):
|
|
"""
|
|
API endpoint for Clinic (read-only).
|
|
|
|
list: Get list of clinics
|
|
retrieve: Get clinic details
|
|
"""
|
|
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = ClinicSerializer
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
|
|
filterset_fields = ['specialty', 'is_active']
|
|
search_fields = ['name_en', 'name_ar']
|
|
|
|
def get_queryset(self):
|
|
"""Filter by tenant."""
|
|
return Clinic.objects.filter(tenant=self.request.user.tenant, is_active=True)
|
|
|
|
|
|
class FileViewSet(viewsets.ReadOnlyModelViewSet):
|
|
"""
|
|
API endpoint for File (read-only).
|
|
|
|
list: Get list of files
|
|
retrieve: Get file details
|
|
"""
|
|
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = FileSerializer
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
|
|
filterset_fields = ['patient', 'is_active']
|
|
search_fields = ['file_number', 'patient__mrn']
|
|
|
|
def get_queryset(self):
|
|
"""Filter by tenant."""
|
|
return File.objects.filter(tenant=self.request.user.tenant)
|
|
|
|
@action(detail=True, methods=['get'])
|
|
def subfiles(self, request, pk=None):
|
|
"""Get file's subfiles."""
|
|
file = self.get_object()
|
|
subfiles = SubFile.objects.filter(file=file)
|
|
serializer = SubFileSerializer(subfiles, many=True)
|
|
return Response(serializer.data)
|
|
|
|
|
|
class SubFileViewSet(viewsets.ReadOnlyModelViewSet):
|
|
"""
|
|
API endpoint for SubFile (read-only).
|
|
|
|
list: Get list of subfiles
|
|
retrieve: Get subfile details
|
|
"""
|
|
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = SubFileSerializer
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
|
|
filterset_fields = ['file', 'clinic', 'is_active']
|
|
search_fields = ['subfile_number']
|
|
|
|
def get_queryset(self):
|
|
"""Filter by tenant."""
|
|
return SubFile.objects.filter(tenant=self.request.user.tenant)
|
|
|
|
|
|
class ConsentViewSet(viewsets.ModelViewSet):
|
|
"""
|
|
API endpoint for Consent CRUD operations.
|
|
|
|
list: Get list of consents
|
|
retrieve: Get consent details
|
|
create: Create new consent
|
|
update: Update consent
|
|
destroy: Delete consent
|
|
"""
|
|
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = ConsentSerializer
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
|
|
filterset_fields = ['patient', 'consent_type', 'is_valid']
|
|
search_fields = ['patient__mrn', 'patient__first_name_en']
|
|
|
|
def get_queryset(self):
|
|
"""Filter by tenant."""
|
|
return Consent.objects.filter(tenant=self.request.user.tenant)
|
|
|
|
def perform_create(self, serializer):
|
|
"""Set tenant and signed_by on create."""
|
|
serializer.save(
|
|
tenant=self.request.user.tenant,
|
|
signed_by=self.request.user
|
|
)
|
|
|
|
@action(detail=True, methods=['post'])
|
|
def verify(self, request, pk=None):
|
|
"""Verify consent signature."""
|
|
consent = self.get_object()
|
|
# Add signature verification logic here
|
|
return Response({
|
|
'verified': True,
|
|
'signed_by': consent.signed_by.get_full_name(),
|
|
'signed_at': consent.signed_at
|
|
})
|
|
|
|
|
|
class AttachmentViewSet(viewsets.ModelViewSet):
|
|
"""
|
|
API endpoint for Attachment CRUD operations.
|
|
|
|
list: Get list of attachments
|
|
retrieve: Get attachment details
|
|
create: Upload new attachment
|
|
destroy: Delete attachment
|
|
"""
|
|
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = AttachmentSerializer
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
|
|
filterset_fields = ['category']
|
|
search_fields = ['title', 'description']
|
|
|
|
def get_queryset(self):
|
|
"""Filter by tenant."""
|
|
return Attachment.objects.filter(tenant=self.request.user.tenant)
|
|
|
|
def perform_create(self, serializer):
|
|
"""Set tenant and uploaded_by on create."""
|
|
serializer.save(
|
|
tenant=self.request.user.tenant,
|
|
uploaded_by=self.request.user
|
|
)
|
|
|
|
|
|
class AuditLogViewSet(viewsets.ReadOnlyModelViewSet):
|
|
"""
|
|
API endpoint for AuditLog (read-only).
|
|
|
|
list: Get list of audit logs
|
|
retrieve: Get audit log details
|
|
"""
|
|
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = AuditLogSerializer
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
|
|
filterset_fields = ['user', 'action', 'model_name']
|
|
search_fields = ['object_repr', 'model_name']
|
|
ordering_fields = ['timestamp']
|
|
ordering = ['-timestamp']
|
|
|
|
def get_queryset(self):
|
|
"""Filter by tenant."""
|
|
return AuditLog.objects.filter(tenant=self.request.user.tenant)
|