2025-12-24 12:42:31 +03:00

267 lines
8.9 KiB
Python

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