626 lines
17 KiB
Markdown
626 lines
17 KiB
Markdown
# SLA System Setup and Testing Guide
|
|
|
|
## Overview
|
|
|
|
This guide covers the complete SLA (Service Level Agreement) system for complaints, including setup, configuration, testing, and monitoring.
|
|
|
|
## Table of Contents
|
|
|
|
1. [System Architecture](#system-architecture)
|
|
2. [Model Structure](#model-structure)
|
|
3. [SLA Configuration](#sla-configuration)
|
|
4. [Escalation Rules](#escalation-rules)
|
|
5. [Testing the System](#testing-the-system)
|
|
6. [Monitoring and Troubleshooting](#monitoring-and-troubleshooting)
|
|
7. [Production Setup](#production-setup)
|
|
|
|
---
|
|
|
|
## System Architecture
|
|
|
|
### Components
|
|
|
|
The SLA system consists of the following key components:
|
|
|
|
1. **Complaint Model** - Stores complaint details and SLA tracking
|
|
2. **SLA Configuration** - Defines time limits for response/resolution
|
|
3. **Escalation Rules** - Defines when and how to escalate complaints
|
|
4. **Complaint Updates** - Timeline of all complaint activities
|
|
5. **Celery Tasks** - Background jobs for SLA reminders and checks
|
|
6. **Signals** - Automatic triggers on complaint creation and updates
|
|
|
|
### Workflow
|
|
|
|
```
|
|
Complaint Created
|
|
↓
|
|
Calculate Due Date (based on SLA config)
|
|
↓
|
|
Set First/Second Reminder Times
|
|
↓
|
|
Celery Beat Checks Every 15 Minutes
|
|
↓
|
|
Send First Reminder (if enabled and time reached)
|
|
↓
|
|
Send Second Reminder (if enabled and time reached)
|
|
↓
|
|
Escalate (if overdue and escalation rules match)
|
|
↓
|
|
Update Complaint Timeline
|
|
```
|
|
|
|
---
|
|
|
|
## Model Structure
|
|
|
|
### Complaint Model
|
|
|
|
Located in: `apps/complaints/models.py`
|
|
|
|
Key SLA-related fields:
|
|
|
|
```python
|
|
class Complaint(models.Model):
|
|
# Basic fields
|
|
reference_number = models.CharField(max_length=50, unique=True)
|
|
hospital = models.ForeignKey(Hospital, on_delete=models.PROTECT)
|
|
department = models.ForeignKey(Department, null=True, on_delete=models.PROTECT)
|
|
category = models.ForeignKey(ComplaintCategory, on_delete=models.PROTECT)
|
|
staff = models.ForeignKey(Staff, null=True, on_delete=models.PROTECT)
|
|
|
|
# Priority and severity
|
|
priority = models.CharField(choices=PRIORITY_CHOICES, default='medium')
|
|
severity = models.CharField(choices=SEVERITY_CHOICES, default='medium')
|
|
|
|
# Status and SLA tracking
|
|
status = models.CharField(choices=STATUS_CHOICES, default='open')
|
|
|
|
# SLA deadlines
|
|
due_at = models.DateTimeField(null=True, blank=True)
|
|
|
|
# SLA reminder tracking
|
|
first_reminder_sent_at = models.DateTimeField(null=True, blank=True)
|
|
second_reminder_sent_at = models.DateTimeField(null=True, blank=True)
|
|
|
|
# Escalation tracking
|
|
escalation_level = models.IntegerField(default=0)
|
|
escalated_at = models.DateTimeField(null=True, blank=True)
|
|
escalated_to = models.ForeignKey(
|
|
User,
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL,
|
|
related_name='escalated_complaints'
|
|
)
|
|
```
|
|
|
|
### SLA Configuration Model
|
|
|
|
```python
|
|
class SLAConfig(models.Model):
|
|
hospital = models.ForeignKey(Hospital, on_delete=models.CASCADE)
|
|
department = models.ForeignKey(Department, null=True, on_delete=models.CASCADE)
|
|
category = models.ForeignKey(ComplaintCategory, on_delete=models.CASCADE)
|
|
|
|
# Time limits (in hours)
|
|
response_time_hours = models.IntegerField()
|
|
resolution_time_hours = models.IntegerField()
|
|
|
|
# First reminder
|
|
enable_first_reminder = models.BooleanField(default=True)
|
|
first_reminder_hours_before = models.IntegerField(default=24)
|
|
|
|
# Second reminder
|
|
enable_second_reminder = models.BooleanField(default=True)
|
|
second_reminder_hours_before = models.IntegerField(default=12)
|
|
|
|
is_active = models.BooleanField(default=True)
|
|
```
|
|
|
|
### Escalation Rule Model
|
|
|
|
```python
|
|
class EscalationRule(models.Model):
|
|
hospital = models.ForeignKey(Hospital, on_delete=models.CASCADE)
|
|
level = models.IntegerField()
|
|
name = models.CharField(max_length=200)
|
|
|
|
# Trigger conditions
|
|
trigger_type = models.CharField(
|
|
choices=[
|
|
('overdue', 'Overdue'),
|
|
('after_reminder', 'After Reminder Sent'),
|
|
],
|
|
default='overdue'
|
|
)
|
|
hours_overdue = models.IntegerField(null=True, blank=True)
|
|
hours_after_reminder = models.IntegerField(null=True, blank=True)
|
|
|
|
# Escalation target
|
|
escalate_to = models.CharField(
|
|
choices=[
|
|
('department_manager', 'Department Manager'),
|
|
('hospital_admin', 'Hospital Administrator'),
|
|
('regional_admin', 'Regional Administrator'),
|
|
],
|
|
default='department_manager'
|
|
)
|
|
|
|
# Priority/severity filters
|
|
applicable_priorities = models.JSONField(default=list)
|
|
applicable_severities = models.JSONField(default=list)
|
|
|
|
is_active = models.BooleanField(default=True)
|
|
```
|
|
|
|
### Complaint Update Model
|
|
|
|
```python
|
|
class ComplaintUpdate(models.Model):
|
|
complaint = models.ForeignKey(Complaint, on_delete=models.CASCADE)
|
|
|
|
update_type = models.CharField(
|
|
choices=[
|
|
('status_change', 'Status Change'),
|
|
('comment', 'Comment'),
|
|
('escalation', 'Escalation'),
|
|
('reminder_sent', 'Reminder Sent'),
|
|
('sla_breach', 'SLA Breach'),
|
|
]
|
|
)
|
|
|
|
old_status = models.CharField(max_length=50, blank=True)
|
|
new_status = models.CharField(max_length=50, blank=True)
|
|
message = models.TextField()
|
|
created_by = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
|
|
```
|
|
|
|
---
|
|
|
|
## SLA Configuration
|
|
|
|
### Setting Up SLA Configurations
|
|
|
|
SLA configurations define time limits for responding to and resolving complaints based on:
|
|
- Hospital
|
|
- Department (optional - applies to all departments if null)
|
|
- Complaint Category
|
|
|
|
### Configuration Steps
|
|
|
|
1. **Access Admin Panel**
|
|
```
|
|
http://localhost:8000/admin/complaints/slaconfig/
|
|
```
|
|
|
|
2. **Create SLA Configuration**
|
|
- Select Hospital
|
|
- Select Category (required)
|
|
- Select Department (optional)
|
|
- Set Response Time (hours)
|
|
- Set Resolution Time (hours)
|
|
- Configure First Reminder
|
|
- Configure Second Reminder
|
|
- Mark as Active
|
|
|
|
3. **Example Configuration**
|
|
|
|
For critical complaints:
|
|
- Response Time: 4 hours
|
|
- Resolution Time: 24 hours
|
|
- First Reminder: 2 hours before due
|
|
- Second Reminder: 1 hour before due
|
|
|
|
For medium complaints:
|
|
- Response Time: 24 hours
|
|
- Resolution Time: 72 hours
|
|
- First Reminder: 24 hours before due
|
|
- Second Reminder: 12 hours before due
|
|
|
|
### Default Configurations
|
|
|
|
The system includes default SLA configurations for all complaint categories:
|
|
|
|
| Category | Response Time | Resolution Time | First Reminder | Second Reminder |
|
|
|----------|--------------|-----------------|---------------|-----------------|
|
|
| Clinical Care | 24 hours | 72 hours | 24 hours | 12 hours |
|
|
| Staff Behavior | 12 hours | 48 hours | 12 hours | 6 hours |
|
|
| Facility | 24 hours | 72 hours | 24 hours | 12 hours |
|
|
| Wait Time | 4 hours | 24 hours | 4 hours | 2 hours |
|
|
| Billing | 24 hours | 72 hours | 24 hours | 12 hours |
|
|
| Communication | 12 hours | 48 hours | 12 hours | 6 hours |
|
|
| Other | 24 hours | 72 hours | 24 hours | 12 hours |
|
|
|
|
---
|
|
|
|
## Escalation Rules
|
|
|
|
### Understanding Escalation
|
|
|
|
Escalation automatically assigns complaints to higher-level staff when:
|
|
1. Complaint becomes overdue
|
|
2. Specified time after reminder has passed
|
|
|
|
### Setting Up Escalation Rules
|
|
|
|
1. **Access Admin Panel**
|
|
```
|
|
http://localhost:8000/admin/complaints/escalationrule/
|
|
```
|
|
|
|
2. **Create Escalation Rule**
|
|
- Select Hospital
|
|
- Set Escalation Level (1, 2, 3, etc.)
|
|
- Name the rule
|
|
- Choose Trigger Type (Overdue or After Reminder)
|
|
- Set Hours parameter
|
|
- Select Escalation Target
|
|
- Filter by Priority/Severity (optional)
|
|
- Mark as Active
|
|
|
|
### Example Escalation Rules
|
|
|
|
**Level 1: Department Manager**
|
|
- Trigger: Overdue
|
|
- Hours overdue: 0 (immediately when due time passes)
|
|
- Escalate to: Department Manager
|
|
|
|
**Level 2: Hospital Admin**
|
|
- Trigger: After Reminder
|
|
- Hours after reminder: 12
|
|
- Escalate to: Hospital Administrator
|
|
- Only for: Critical and High priority
|
|
|
|
**Level 3: Regional Admin**
|
|
- Trigger: Overdue
|
|
- Hours overdue: 48
|
|
- Escalate to: Regional Administrator
|
|
- Only for: Critical severity
|
|
|
|
---
|
|
|
|
## Testing the System
|
|
|
|
### Automated Testing
|
|
|
|
Run the automated SLA test suite:
|
|
|
|
```bash
|
|
python test_sla_functionality.py
|
|
```
|
|
|
|
This test verifies:
|
|
- ✓ SLA configuration retrieval
|
|
- ✓ Due date calculation
|
|
- ✓ First reminder logic
|
|
- ✓ Second reminder logic
|
|
- ✓ Escalation eligibility
|
|
- ✓ Timeline tracking
|
|
|
|
### Manual Testing
|
|
|
|
#### Test 1: Complaint Creation and SLA Calculation
|
|
|
|
1. Create a complaint via admin panel or API
|
|
2. Verify:
|
|
- `due_at` field is populated
|
|
- `first_reminder_sent_at` and `second_reminder_sent_at` are null
|
|
- `escalation_level` is 0
|
|
- Timeline entry shows "Complaint created and registered"
|
|
|
|
```bash
|
|
# View complaint details
|
|
python manage.py shell -c "
|
|
from apps.complaints.models import Complaint
|
|
c = Complaint.objects.first()
|
|
print(f'ID: {c.id}')
|
|
print(f'Title: {c.title}')
|
|
print(f'Status: {c.status}')
|
|
print(f'Due At: {c.due_at}')
|
|
print(f'Escalation Level: {c.escalation_level}')
|
|
print(f'First Reminder Sent: {c.first_reminder_sent_at}')
|
|
print(f'Second Reminder Sent: {c.second_reminder_sent_at}')
|
|
"
|
|
```
|
|
|
|
#### Test 2: First Reminder
|
|
|
|
1. Create a complaint with SLA config
|
|
2. Wait for first reminder time or modify `due_at` to trigger
|
|
3. Check complaint for:
|
|
- `first_reminder_sent_at` is populated
|
|
- Timeline entry shows "First SLA reminder sent"
|
|
|
|
```bash
|
|
# Check reminder status
|
|
python manage.py shell -c "
|
|
from apps.complaints.models import Complaint
|
|
from django.utils import timezone
|
|
import logging
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
complaint = Complaint.objects.first()
|
|
if complaint:
|
|
from apps.complaints.tasks import check_and_send_sla_reminders
|
|
result = check_and_send_sla_reminders()
|
|
print(f'Result: {result}')
|
|
|
|
# Refresh complaint
|
|
complaint.refresh_from_db()
|
|
print(f'First Reminder Sent At: {complaint.first_reminder_sent_at}')
|
|
print(f'Second Reminder Sent At: {complaint.second_reminder_sent_at}')
|
|
"
|
|
```
|
|
|
|
#### Test 3: Second Reminder
|
|
|
|
1. Ensure complaint has first reminder sent
|
|
2. Wait for second reminder time or modify timestamps
|
|
3. Verify:
|
|
- `second_reminder_sent_at` is populated
|
|
- Timeline entry shows "Second SLA reminder sent"
|
|
|
|
#### Test 4: Escalation
|
|
|
|
1. Create overdue complaint (set `due_at` in the past)
|
|
2. Ensure escalation rules exist
|
|
3. Run escalation check:
|
|
|
|
```bash
|
|
python manage.py shell -c "
|
|
from apps.complaints.models import Complaint
|
|
from django.utils import timezone
|
|
import logging
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
complaint = Complaint.objects.first()
|
|
if complaint:
|
|
# Make it overdue
|
|
complaint.due_at = timezone.now() - timezone.timedelta(hours=2)
|
|
complaint.save()
|
|
|
|
from apps.complaints.tasks import check_and_escalate_overdue_complaints
|
|
result = check_and_escalate_overdue_complaints()
|
|
print(f'Result: {result}')
|
|
|
|
# Refresh complaint
|
|
complaint.refresh_from_db()
|
|
print(f'Escalation Level: {complaint.escalation_level}')
|
|
print(f'Escalated To: {complaint.escalated_to}')
|
|
print(f'Escalated At: {complaint.escalated_at}')
|
|
"
|
|
```
|
|
|
|
#### Test 5: Seeding Test Data
|
|
|
|
Generate test complaints for SLA testing:
|
|
|
|
```bash
|
|
# Seed 10 complaints (7 Arabic, 3 English)
|
|
python manage.py seed_complaints --count 10
|
|
|
|
# Seed 50 complaints with different distribution
|
|
python manage.py seed_complaints --count 50 --arabic-percent 50 --staff-mention-percent 70
|
|
|
|
# Dry run to preview
|
|
python manage.py seed_complaints --count 20 --dry-run
|
|
|
|
# Clear existing and seed fresh
|
|
python manage.py seed_complaints --count 10 --clear
|
|
```
|
|
|
|
---
|
|
|
|
## Monitoring and Troubleshooting
|
|
|
|
### Checking SLA Status
|
|
|
|
View all complaints with SLA information:
|
|
|
|
```bash
|
|
python manage.py shell -c "
|
|
from apps.complaints.models import Complaint
|
|
from django.utils import timezone
|
|
from django.db.models import Q
|
|
|
|
now = timezone.now()
|
|
|
|
# All open complaints
|
|
open_complaints = Complaint.objects.filter(status='open')
|
|
print(f'Total Open Complaints: {open_complaints.count()}')
|
|
|
|
# Overdue complaints
|
|
overdue = open_complaints.filter(due_at__lt=now)
|
|
print(f'Overdue: {overdue.count()}')
|
|
|
|
# Due within 24 hours
|
|
soon = open_complaints.filter(due_at__gte=now, due_at__lte=now + timezone.timedelta(hours=24))
|
|
print(f'Due within 24h: {soon.count()}')
|
|
|
|
# First reminder sent but not second
|
|
first_only = open_complaints.filter(first_reminder_sent_at__isnull=False, second_reminder_sent_at__isnull=True)
|
|
print(f'First reminder only: {first_only.count()}')
|
|
|
|
# Escalated complaints
|
|
escalated = open_complaints.filter(escalation_level__gt=0)
|
|
print(f'Escalated: {escalated.count()}')
|
|
"
|
|
```
|
|
|
|
### Celery Task Monitoring
|
|
|
|
Check if Celery Beat is running:
|
|
|
|
```bash
|
|
# Check Celery status
|
|
celery -A config inspect active
|
|
|
|
# View scheduled tasks
|
|
celery -A config inspect scheduled
|
|
|
|
# View registered tasks
|
|
celery -A config inspect registered
|
|
```
|
|
|
|
### Email Configuration
|
|
|
|
Test email sending:
|
|
|
|
```bash
|
|
python test_email_sending.py
|
|
```
|
|
|
|
Ensure email settings in `.env`:
|
|
```env
|
|
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
|
|
EMAIL_HOST=smtp.gmail.com
|
|
EMAIL_PORT=587
|
|
EMAIL_USE_TLS=True
|
|
EMAIL_HOST_USER=your-email@gmail.com
|
|
EMAIL_HOST_PASSWORD=your-app-password
|
|
DEFAULT_FROM_EMAIL=your-email@gmail.com
|
|
```
|
|
|
|
### Common Issues
|
|
|
|
**Issue 1: Reminders not sending**
|
|
|
|
- Check Celery Beat is running
|
|
- Verify Celery logs: `tail -f logs/celery.log`
|
|
- Check email configuration
|
|
- Verify SLA config has reminders enabled
|
|
|
|
**Issue 2: Escalation not working**
|
|
|
|
- Verify escalation rules exist and are active
|
|
- Check complaint matches rule criteria (priority/severity)
|
|
- Ensure complaint is actually overdue
|
|
- Check Celery logs for errors
|
|
|
|
**Issue 3: Wrong due dates**
|
|
|
|
- Verify SLA configuration exists for complaint's category/hospital
|
|
- Check timezone settings in Django
|
|
- Review signal handlers in `apps/complaints/signals.py`
|
|
|
|
---
|
|
|
|
## Production Setup
|
|
|
|
### 1. Configure Celery Beat
|
|
|
|
Ensure Celery Beat is configured in `config/celery.py`:
|
|
|
|
```python
|
|
from celery.schedules import crontab
|
|
|
|
app.conf.beat_schedule = {
|
|
'check-sla-reminders-every-15-minutes': {
|
|
'task': 'apps.complaints.tasks.check_and_send_sla_reminders',
|
|
'schedule': crontab(minute='*/15'),
|
|
},
|
|
'check-overdue-complaints-every-30-minutes': {
|
|
'task': 'apps.complaints.tasks.check_and_escalate_overdue_complaints',
|
|
'schedule': crontab(minute='*/30'),
|
|
},
|
|
}
|
|
```
|
|
|
|
### 2. Run Celery Workers
|
|
|
|
```bash
|
|
# Start Celery worker
|
|
celery -A config worker -l INFO
|
|
|
|
# Start Celery Beat scheduler
|
|
celery -A config beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler
|
|
```
|
|
|
|
### 3. Configure Production Email Settings
|
|
|
|
Use production email service (e.g., SendGrid, AWS SES):
|
|
|
|
```python
|
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
|
EMAIL_HOST = 'smtp.sendgrid.net'
|
|
EMAIL_PORT = 587
|
|
EMAIL_USE_TLS = True
|
|
EMAIL_HOST_USER = 'apikey'
|
|
EMAIL_HOST_PASSWORD = os.getenv('SENDGRID_API_KEY')
|
|
DEFAULT_FROM_EMAIL = 'noreply@alhammadi.com.sa'
|
|
```
|
|
|
|
### 4. Set Up Monitoring
|
|
|
|
- Monitor Celery task queue size
|
|
- Track SLA breach rate
|
|
- Alert on high escalation rates
|
|
- Monitor email delivery success rate
|
|
|
|
### 5. Database Indexes
|
|
|
|
Ensure database has proper indexes for SLA queries:
|
|
|
|
```python
|
|
class Complaint(models.Model):
|
|
class Meta:
|
|
indexes = [
|
|
models.Index(fields=['status', 'due_at']),
|
|
models.Index(fields=['status', 'created_at']),
|
|
models.Index(fields=['hospital', 'status']),
|
|
models.Index(fields=['escalation_level']),
|
|
]
|
|
```
|
|
|
|
### 6. Backup Strategy
|
|
|
|
- Regular database backups
|
|
- Backup SLA configurations
|
|
- Archive old complaints
|
|
- Keep escalation rule history
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
The SLA system provides:
|
|
|
|
✓ **Automated Time Tracking** - Automatically calculates and tracks due dates
|
|
✓ **Double Reminder System** - First and second reminders configurable per SLA
|
|
✓ **Smart Escalation** - Automatic escalation based on rules
|
|
✓ **Complete Audit Trail** - Full timeline of all activities
|
|
✓ **Multi-level Configuration** - Different SLAs by hospital, department, and category
|
|
✓ **Bilingual Support** - Full Arabic/English support for emails and notifications
|
|
✓ **Flexible Rules** - Configure different priorities and severities
|
|
✓ **Background Processing** - Non-blocking Celery tasks
|
|
✓ **Production Ready** - Tested and ready for deployment
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. **Configure SLA Settings** - Set appropriate time limits for your organization
|
|
2. **Test with Real Data** - Use production-like data for testing
|
|
3. **Monitor Initial Period** - Closely monitor SLA performance for first week
|
|
4. **Adjust Rules** - Fine-tune escalation rules based on observed patterns
|
|
5. **Train Staff** - Educate staff on SLA system and their responsibilities
|
|
6. **Set Up Dashboards** - Create monitoring dashboards for SLA metrics
|
|
|
|
---
|
|
|
|
## Additional Resources
|
|
|
|
- **SLA Testing Guide**: `docs/SLA_TESTING_GUIDE.md`
|
|
- **SLA System Overview**: `docs/SLA_SYSTEM_OVERVIEW.md`
|
|
- **SLA Testing Plan**: `docs/SLA_TESTING_PLAN.md`
|
|
- **Complaint Seeding Guide**: `docs/COMPLAINT_SEEDING_GUIDE.md`
|
|
- **Email Templates**: `templates/complaints/emails/`
|
|
|
|
---
|
|
|
|
*Last Updated: January 14, 2026*
|