""" PX Action Center views and viewsets """ from django.utils import timezone 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 IsPXAdmin from apps.core.services import AuditService from .models import PXAction, PXActionAttachment, PXActionLog, PXActionSLAConfig, RoutingRule from .serializers import ( PXActionAttachmentSerializer, PXActionListSerializer, PXActionLogSerializer, PXActionSerializer, PXActionSLAConfigSerializer, RoutingRuleSerializer, ) class PXActionViewSet(viewsets.ModelViewSet): """ ViewSet for PX Actions with workflow actions. Permissions: - All authenticated users can view actions - PX Admins and PX Coordinators can create/manage actions """ queryset = PXAction.objects.all() permission_classes = [IsAuthenticated] filterset_fields = [ 'status', 'source_type', 'severity', 'priority', 'category', 'hospital', 'department', 'assigned_to', 'is_overdue', 'requires_approval' ] search_fields = ['title', 'description'] ordering_fields = ['created_at', 'due_at', 'severity', 'escalation_level'] ordering = ['-created_at'] def get_serializer_class(self): """Use simplified serializer for list view""" if self.action == 'list': return PXActionListSerializer return PXActionSerializer def get_queryset(self): """Filter actions based on user role""" queryset = super().get_queryset().select_related( 'hospital', 'department', 'assigned_to', 'approved_by', 'closed_by', 'content_type' ).prefetch_related('logs', 'attachments') user = self.request.user # PX Admins see all actions if user.is_px_admin(): return queryset # Hospital Admins see actions for their hospital if user.is_hospital_admin() and user.hospital: return queryset.filter(hospital=user.hospital) # Department Managers see actions for their department if user.is_department_manager() and user.department: return queryset.filter(department=user.department) # Others see actions for their hospital if user.hospital: return queryset.filter(hospital=user.hospital) return queryset.none() def perform_create(self, serializer): """Log action creation""" action = serializer.save() AuditService.log_from_request( event_type='action_created', description=f"PX Action created: {action.title}", request=self.request, content_object=action, metadata={ 'source_type': action.source_type, 'category': action.category, 'severity': action.severity } ) @action(detail=True, methods=['post']) def assign(self, request, pk=None): """Assign action to user""" action = self.get_object() user_id = request.data.get('user_id') if not user_id: return Response( {'error': 'user_id is required'}, status=status.HTTP_400_BAD_REQUEST ) from apps.accounts.models import User try: user = User.objects.get(id=user_id) action.assigned_to = user action.assigned_at = timezone.now() action.save(update_fields=['assigned_to', 'assigned_at']) # Create log PXActionLog.objects.create( action=action, log_type='assignment', message=f"Assigned to {user.get_full_name()}", created_by=request.user ) AuditService.log_from_request( event_type='assignment', description=f"Action assigned to {user.get_full_name()}", request=request, content_object=action ) return Response({'message': 'Action assigned successfully'}) except User.DoesNotExist: return Response( {'error': 'User not found'}, status=status.HTTP_404_NOT_FOUND ) @action(detail=True, methods=['post']) def change_status(self, request, pk=None): """Change action status""" action = self.get_object() new_status = request.data.get('status') note = request.data.get('note', '') if not new_status: return Response( {'error': 'status is required'}, status=status.HTTP_400_BAD_REQUEST ) old_status = action.status action.status = new_status # Handle status-specific logic if new_status == 'pending_approval': # Check if evidence is required if action.requires_approval: evidence_count = action.attachments.filter(is_evidence=True).count() if evidence_count == 0: return Response( {'error': 'Evidence is required before requesting approval'}, status=status.HTTP_400_BAD_REQUEST ) elif new_status == 'approved': # Only PX Admins can approve if not request.user.is_px_admin(): return Response( {'error': 'Only PX Admins can approve actions'}, status=status.HTTP_403_FORBIDDEN ) action.approved_by = request.user action.approved_at = timezone.now() elif new_status == 'closed': action.closed_at = timezone.now() action.closed_by = request.user action.save() # Create log PXActionLog.objects.create( action=action, log_type='status_change', message=note or f"Status changed from {old_status} to {new_status}", created_by=request.user, old_status=old_status, new_status=new_status ) AuditService.log_from_request( event_type='status_change', description=f"Action status changed from {old_status} to {new_status}", request=request, content_object=action, metadata={'old_status': old_status, 'new_status': new_status} ) return Response({'message': 'Status updated successfully'}) @action(detail=True, methods=['post']) def add_note(self, request, pk=None): """Add note to action""" action = self.get_object() note = request.data.get('note') if not note: return Response( {'error': 'note is required'}, status=status.HTTP_400_BAD_REQUEST ) # Create log log = PXActionLog.objects.create( action=action, log_type='note', message=note, created_by=request.user ) serializer = PXActionLogSerializer(log) return Response(serializer.data, status=status.HTTP_201_CREATED) @action(detail=True, methods=['post']) def escalate(self, request, pk=None): """Manually escalate action""" action = self.get_object() # Queue escalation task from apps.px_action_center.tasks import escalate_action escalate_action.delay(str(action.id)) return Response({'message': 'Action queued for escalation'}) class PXActionSLAConfigViewSet(viewsets.ModelViewSet): """ ViewSet for PX Action SLA Configurations. Permissions: - Only PX Admins can manage SLA configurations """ queryset = PXActionSLAConfig.objects.all() serializer_class = PXActionSLAConfigSerializer permission_classes = [IsPXAdmin] filterset_fields = ['hospital', 'department', 'is_active'] search_fields = ['name'] ordering = ['hospital', 'name'] def get_queryset(self): return super().get_queryset().select_related('hospital', 'department') class RoutingRuleViewSet(viewsets.ModelViewSet): """ ViewSet for Routing Rules. Permissions: - Only PX Admins can manage routing rules """ queryset = RoutingRule.objects.all() serializer_class = RoutingRuleSerializer permission_classes = [IsPXAdmin] filterset_fields = ['source_type', 'severity', 'hospital', 'is_active'] search_fields = ['name', 'description'] ordering = ['-priority', 'name'] def get_queryset(self): return super().get_queryset().select_related( 'hospital', 'department', 'assign_to_user', 'assign_to_department' )