HH/apps/journeys/views.py

248 lines
8.8 KiB
Python

"""
Journeys views and viewsets
"""
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from apps.accounts.permissions import IsPXAdminOrHospitalAdmin
from apps.core.services import AuditService
from .models import (
PatientJourneyInstance,
PatientJourneyStageInstance,
PatientJourneyStageTemplate,
PatientJourneyTemplate,
)
from .serializers import (
PatientJourneyInstanceListSerializer,
PatientJourneyInstanceSerializer,
PatientJourneyStageInstanceSerializer,
PatientJourneyStageTemplateSerializer,
PatientJourneyTemplateSerializer,
)
class PatientJourneyTemplateViewSet(viewsets.ModelViewSet):
"""
ViewSet for Journey Templates.
Permissions:
- PX Admins and Hospital Admins can manage templates
- Others can view templates
"""
queryset = PatientJourneyTemplate.objects.all()
serializer_class = PatientJourneyTemplateSerializer
permission_classes = [IsAuthenticated]
filterset_fields = ['journey_type', 'hospital', 'is_active', 'is_default', 'hospital__organization']
search_fields = ['name', 'name_ar', 'description']
ordering_fields = ['name', 'created_at']
ordering = ['hospital', 'journey_type', 'name']
def get_queryset(self):
"""Filter templates based on user role"""
queryset = super().get_queryset().select_related('hospital').prefetch_related('stages')
user = self.request.user
# PX Admins see all templates
if user.is_px_admin():
return queryset
# Hospital Admins see templates for their hospital
if user.is_hospital_admin() and user.hospital:
return queryset.filter(hospital=user.hospital)
# Others see templates for their hospital
if user.hospital:
return queryset.filter(hospital=user.hospital)
return queryset.none()
class PatientJourneyStageTemplateViewSet(viewsets.ModelViewSet):
"""
ViewSet for Journey Stage Templates.
Permissions:
- PX Admins and Hospital Admins can manage stage templates
"""
queryset = PatientJourneyStageTemplate.objects.all()
serializer_class = PatientJourneyStageTemplateSerializer
permission_classes = [IsAuthenticated, IsPXAdminOrHospitalAdmin]
filterset_fields = ['journey_template', 'is_active', 'auto_send_survey']
search_fields = ['name', 'name_ar', 'code', 'trigger_event_code']
ordering_fields = ['order', 'name']
ordering = ['journey_template', 'order']
def get_queryset(self):
queryset = super().get_queryset().select_related('journey_template', 'survey_template')
user = self.request.user
# PX Admins see all stage templates
if user.is_px_admin():
return queryset
# Hospital Admins see stage templates for their hospital
if user.is_hospital_admin() and user.hospital:
return queryset.filter(journey_template__hospital=user.hospital)
return queryset.none()
class PatientJourneyInstanceViewSet(viewsets.ModelViewSet):
"""
ViewSet for Journey Instances.
Permissions:
- All authenticated users can view journey instances
- PX Admins and Hospital Admins can create/manage instances
"""
queryset = PatientJourneyInstance.objects.all()
permission_classes = [IsAuthenticated]
filterset_fields = [
'journey_template', 'journey_template__journey_type',
'patient', 'hospital', 'department', 'status',
'hospital__organization'
]
search_fields = ['encounter_id', 'patient__mrn', 'patient__first_name', 'patient__last_name']
ordering_fields = ['started_at', 'completed_at']
ordering = ['-started_at']
def get_serializer_class(self):
"""Use simplified serializer for list view"""
if self.action == 'list':
return PatientJourneyInstanceListSerializer
return PatientJourneyInstanceSerializer
def get_queryset(self):
"""Filter journey instances based on user role"""
queryset = super().get_queryset().select_related(
'journey_template', 'patient', 'hospital', 'department'
).prefetch_related('stage_instances__stage_template')
user = self.request.user
# PX Admins see all journey instances
if user.is_px_admin():
return queryset
# Hospital Admins see instances for their hospital
if user.is_hospital_admin() and user.hospital:
return queryset.filter(hospital=user.hospital)
# Department Managers see instances for their department
if user.is_department_manager() and user.department:
return queryset.filter(department=user.department)
# Others see instances for their hospital
if user.hospital:
return queryset.filter(hospital=user.hospital)
return queryset.none()
def perform_create(self, serializer):
"""
Create journey instance and initialize stage instances.
When a journey instance is created, automatically create
stage instances for all stages in the template.
"""
journey_instance = serializer.save()
# Create stage instances for all stages in the template
for stage_template in journey_instance.journey_template.stages.filter(is_active=True):
PatientJourneyStageInstance.objects.create(
journey_instance=journey_instance,
stage_template=stage_template
)
# Log journey creation
AuditService.log_from_request(
event_type='journey_started',
description=f"Journey started for encounter {journey_instance.encounter_id}",
request=self.request,
content_object=journey_instance,
metadata={
'journey_type': journey_instance.journey_template.journey_type,
'patient_mrn': journey_instance.patient.mrn
}
)
@action(detail=True, methods=['get'])
def progress(self, request, pk=None):
"""Get journey progress summary"""
journey = self.get_object()
stages = journey.stage_instances.select_related('stage_template').order_by('stage_template__order')
progress_data = {
'journey_id': str(journey.id),
'encounter_id': journey.encounter_id,
'patient': journey.patient.get_full_name(),
'journey_type': journey.journey_template.journey_type,
'status': journey.status,
'completion_percentage': journey.get_completion_percentage(),
'is_complete': journey.is_complete(),
'started_at': journey.started_at,
'completed_at': journey.completed_at,
'stages': [
{
'name': stage.stage_template.name,
'order': stage.stage_template.order,
'status': stage.status,
'completed_at': stage.completed_at,
'survey_sent': stage.survey_sent_at is not None,
}
for stage in stages
]
}
return Response(progress_data)
class PatientJourneyStageInstanceViewSet(viewsets.ReadOnlyModelViewSet):
"""
ViewSet for Journey Stage Instances (read-only).
Stage instances are created automatically and updated via event processing.
Manual updates should be done through the admin interface.
"""
queryset = PatientJourneyStageInstance.objects.all()
serializer_class = PatientJourneyStageInstanceSerializer
permission_classes = [IsAuthenticated]
filterset_fields = ['journey_instance', 'stage_template', 'status']
search_fields = ['journey_instance__encounter_id', 'stage_template__name']
ordering_fields = ['completed_at', 'created_at']
ordering = ['journey_instance', 'stage_template__order']
def get_queryset(self):
"""Filter stage instances based on user role"""
queryset = super().get_queryset().select_related(
'journey_instance',
'stage_template',
'physician',
'department',
'survey_instance'
)
user = self.request.user
# PX Admins see all stage instances
if user.is_px_admin():
return queryset
# Hospital Admins see instances for their hospital
if user.is_hospital_admin() and user.hospital:
return queryset.filter(journey_instance__hospital=user.hospital)
# Department Managers see instances for their department
if user.is_department_manager() and user.department:
return queryset.filter(journey_instance__department=user.department)
# Others see instances for their hospital
if user.hospital:
return queryset.filter(journey_instance__hospital=user.hospital)
return queryset.none()