""" 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()