254 lines
9.4 KiB
Python
254 lines
9.4 KiB
Python
"""
|
|
Management command to seed default complaint configurations
|
|
"""
|
|
from django.core.management.base import BaseCommand
|
|
from django.db import transaction
|
|
|
|
from apps.complaints.models import (
|
|
ComplaintCategory,
|
|
ComplaintSLAConfig,
|
|
ComplaintThreshold,
|
|
EscalationRule,
|
|
)
|
|
from apps.organizations.models import Hospital
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Seed default complaint configurations (categories, SLA configs, thresholds, escalation rules)'
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
'--hospital-id',
|
|
type=str,
|
|
help='Specific hospital ID to seed configs for',
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
hospital_id = options.get('hospital_id')
|
|
|
|
if hospital_id:
|
|
try:
|
|
hospitals = [Hospital.objects.get(id=hospital_id)]
|
|
self.stdout.write(f"Seeding configs for hospital: {hospitals[0].name_en}")
|
|
except Hospital.DoesNotExist:
|
|
self.stdout.write(self.style.ERROR(f"Hospital with ID {hospital_id} not found"))
|
|
return
|
|
else:
|
|
hospitals = Hospital.objects.filter(status='active')
|
|
self.stdout.write(f"Seeding configs for {hospitals.count()} active hospitals")
|
|
|
|
with transaction.atomic():
|
|
# Seed system-wide categories first
|
|
self.seed_system_categories()
|
|
|
|
# Seed per-hospital configurations
|
|
for hospital in hospitals:
|
|
self.stdout.write(f"\nProcessing hospital: {hospital.name_en}")
|
|
self.seed_sla_configs(hospital)
|
|
self.seed_thresholds(hospital)
|
|
self.seed_escalation_rules(hospital)
|
|
|
|
self.stdout.write(self.style.SUCCESS('\nSuccessfully seeded complaint configurations!'))
|
|
|
|
def seed_system_categories(self):
|
|
"""Seed system-wide complaint categories"""
|
|
self.stdout.write("Seeding system-wide categories...")
|
|
|
|
categories = [
|
|
{
|
|
'code': 'clinical_care',
|
|
'name_en': 'Clinical Care',
|
|
'name_ar': 'الرعاية السريرية',
|
|
'description_en': 'Issues related to medical treatment and clinical services',
|
|
'order': 1
|
|
},
|
|
{
|
|
'code': 'staff_behavior',
|
|
'name_en': 'Staff Behavior',
|
|
'name_ar': 'سلوك الموظفين',
|
|
'description_en': 'Issues related to staff conduct and professionalism',
|
|
'order': 2
|
|
},
|
|
{
|
|
'code': 'facility',
|
|
'name_en': 'Facility & Environment',
|
|
'name_ar': 'المرافق والبيئة',
|
|
'description_en': 'Issues related to hospital facilities and cleanliness',
|
|
'order': 3
|
|
},
|
|
{
|
|
'code': 'wait_time',
|
|
'name_en': 'Wait Time',
|
|
'name_ar': 'وقت الانتظار',
|
|
'description_en': 'Issues related to waiting times and delays',
|
|
'order': 4
|
|
},
|
|
{
|
|
'code': 'billing',
|
|
'name_en': 'Billing',
|
|
'name_ar': 'الفواتير',
|
|
'description_en': 'Issues related to billing and payments',
|
|
'order': 5
|
|
},
|
|
{
|
|
'code': 'communication',
|
|
'name_en': 'Communication',
|
|
'name_ar': 'التواصل',
|
|
'description_en': 'Issues related to communication with staff',
|
|
'order': 6
|
|
},
|
|
{
|
|
'code': 'other',
|
|
'name_en': 'Other',
|
|
'name_ar': 'أخرى',
|
|
'description_en': 'Other complaints not covered by above categories',
|
|
'order': 7
|
|
},
|
|
]
|
|
|
|
created_count = 0
|
|
for cat_data in categories:
|
|
category, created = ComplaintCategory.objects.get_or_create(
|
|
hospital=None, # System-wide
|
|
code=cat_data['code'],
|
|
defaults={
|
|
'name_en': cat_data['name_en'],
|
|
'name_ar': cat_data['name_ar'],
|
|
'description_en': cat_data['description_en'],
|
|
'order': cat_data['order'],
|
|
'is_active': True
|
|
}
|
|
)
|
|
if created:
|
|
created_count += 1
|
|
self.stdout.write(f" Created category: {category.name_en}")
|
|
|
|
self.stdout.write(self.style.SUCCESS(f" Created {created_count} system categories"))
|
|
|
|
def seed_sla_configs(self, hospital):
|
|
"""Seed SLA configurations for a hospital"""
|
|
self.stdout.write(f" Seeding SLA configs...")
|
|
|
|
# Define SLA hours based on severity and priority
|
|
sla_matrix = [
|
|
# (severity, priority, sla_hours, reminder_hours)
|
|
('critical', 'urgent', 4, 2),
|
|
('critical', 'high', 8, 4),
|
|
('critical', 'medium', 12, 6),
|
|
('critical', 'low', 24, 12),
|
|
|
|
('high', 'urgent', 8, 4),
|
|
('high', 'high', 12, 6),
|
|
('high', 'medium', 24, 12),
|
|
('high', 'low', 48, 24),
|
|
|
|
('medium', 'urgent', 12, 6),
|
|
('medium', 'high', 24, 12),
|
|
('medium', 'medium', 48, 24),
|
|
('medium', 'low', 72, 36),
|
|
|
|
('low', 'urgent', 24, 12),
|
|
('low', 'high', 48, 24),
|
|
('low', 'medium', 72, 36),
|
|
('low', 'low', 120, 48),
|
|
]
|
|
|
|
created_count = 0
|
|
for severity, priority, sla_hours, reminder_hours in sla_matrix:
|
|
config, created = ComplaintSLAConfig.objects.get_or_create(
|
|
hospital=hospital,
|
|
severity=severity,
|
|
priority=priority,
|
|
defaults={
|
|
'sla_hours': sla_hours,
|
|
'reminder_hours_before': reminder_hours,
|
|
'is_active': True
|
|
}
|
|
)
|
|
if created:
|
|
created_count += 1
|
|
|
|
self.stdout.write(f" Created {created_count} SLA configs")
|
|
|
|
def seed_thresholds(self, hospital):
|
|
"""Seed complaint thresholds for a hospital"""
|
|
self.stdout.write(f" Seeding thresholds...")
|
|
|
|
thresholds = [
|
|
{
|
|
'threshold_type': 'resolution_survey_score',
|
|
'threshold_value': 50.0,
|
|
'comparison_operator': 'lt',
|
|
'action_type': 'create_px_action',
|
|
},
|
|
]
|
|
|
|
created_count = 0
|
|
for threshold_data in thresholds:
|
|
threshold, created = ComplaintThreshold.objects.get_or_create(
|
|
hospital=hospital,
|
|
threshold_type=threshold_data['threshold_type'],
|
|
defaults={
|
|
'threshold_value': threshold_data['threshold_value'],
|
|
'comparison_operator': threshold_data['comparison_operator'],
|
|
'action_type': threshold_data['action_type'],
|
|
'is_active': True
|
|
}
|
|
)
|
|
if created:
|
|
created_count += 1
|
|
|
|
self.stdout.write(f" Created {created_count} thresholds")
|
|
|
|
def seed_escalation_rules(self, hospital):
|
|
"""Seed escalation rules for a hospital"""
|
|
self.stdout.write(f" Seeding escalation rules...")
|
|
|
|
rules = [
|
|
{
|
|
'name': 'Default Escalation to Department Manager',
|
|
'description': 'Escalate overdue complaints to department manager',
|
|
'trigger_on_overdue': True,
|
|
'trigger_hours_overdue': 0,
|
|
'escalate_to_role': 'department_manager',
|
|
'order': 1,
|
|
},
|
|
{
|
|
'name': 'Critical Escalation to Hospital Admin',
|
|
'description': 'Escalate critical complaints to hospital admin after 4 hours overdue',
|
|
'trigger_on_overdue': True,
|
|
'trigger_hours_overdue': 4,
|
|
'escalate_to_role': 'hospital_admin',
|
|
'severity_filter': 'critical',
|
|
'order': 2,
|
|
},
|
|
{
|
|
'name': 'Final Escalation to PX Admin',
|
|
'description': 'Escalate to PX Admin after 24 hours overdue',
|
|
'trigger_on_overdue': True,
|
|
'trigger_hours_overdue': 24,
|
|
'escalate_to_role': 'px_admin',
|
|
'order': 3,
|
|
},
|
|
]
|
|
|
|
created_count = 0
|
|
for rule_data in rules:
|
|
rule, created = EscalationRule.objects.get_or_create(
|
|
hospital=hospital,
|
|
name=rule_data['name'],
|
|
defaults={
|
|
'description': rule_data['description'],
|
|
'trigger_on_overdue': rule_data['trigger_on_overdue'],
|
|
'trigger_hours_overdue': rule_data['trigger_hours_overdue'],
|
|
'escalate_to_role': rule_data['escalate_to_role'],
|
|
'severity_filter': rule_data.get('severity_filter', ''),
|
|
'order': rule_data['order'],
|
|
'is_active': True
|
|
}
|
|
)
|
|
if created:
|
|
created_count += 1
|
|
|
|
self.stdout.write(f" Created {created_count} escalation rules")
|