84 lines
3.1 KiB
Python
84 lines
3.1 KiB
Python
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
|