import logging from django.conf import settings from django.utils import timezone from datetime import timedelta from apps.organizations.models import Department logger = logging.getLogger(__name__) class RoutingRuleEvaluationService: CATEGORY_DEPARTMENT_MAP = { "clinical_quality": ["Quality", "Clinical Quality"], "patient_safety": ["Patient Safety", "Quality"], "staff_behavior": ["Human Resources", "HR"], "facility": ["Facility Management", "Operations"], "service_quality": ["Customer Service", "Patient Experience"], } @staticmethod def evaluate_and_route(action): decisions = {} RoutingRuleEvaluationService._assign_department(action, decisions) RoutingRuleEvaluationService._adjust_priority_severity(action, decisions) RoutingRuleEvaluationService._calculate_due_at(action, decisions) action.save() logger.info("Routing decisions for action %s: %s", action.pk, decisions) return decisions @staticmethod def _assign_department(action, decisions): if action.department_id: return category = action.category dept_names = RoutingRuleEvaluationService.CATEGORY_DEPARTMENT_MAP.get(category, []) for name in dept_names: dept = Department.objects.filter(name__iexact=name).first() if dept: action.department = dept decisions["auto_assigned_department"] = dept.name return @staticmethod def _adjust_priority_severity(action, decisions): if action.category == "patient_safety": action.severity = "critical" decisions["severity_override"] = "critical (patient_safety)" if action.source_type == "complaint": if action.priority in ("low", ""): action.priority = "medium" decisions["priority_override"] = "medium (complaint)" if action.source_type == "social_media": metadata = action.metadata or {} sentiment = metadata.get("sentiment", "") if sentiment == "negative": if action.priority in ("low", "medium", ""): action.priority = "high" decisions["priority_override"] = "high (social_media negative)" if action.source_type == "survey": metadata = action.metadata or {} rating = metadata.get("rating") if rating is not None and isinstance(rating, (int, float)) and rating <= 2: if action.severity in ("low", "medium", ""): action.severity = "high" decisions["severity_override"] = decisions.get("severity_override", "high (survey low rating)") @staticmethod def _calculate_due_at(action, decisions): if action.due_at: return sla_hours = getattr(settings, "SLA_DEFAULTS", {}).get("action", {}).get(action.severity, 48) action.due_at = timezone.now() + timedelta(hours=sla_hours) decisions["auto_calculated_due_at"] = action.due_at.isoformat() decisions["sla_hours"] = sla_hours