# 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*
