HH/apps/px_action_center/services.py
2026-04-08 17:13:35 +03:00

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