update on the complaint sla and staff hierarchy

This commit is contained in:
ismail 2026-01-15 14:31:54 +03:00
parent dcb6455819
commit aac8698df4
37 changed files with 482 additions and 36 deletions

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.utils.timezone
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
from django.conf import settings

View File

@ -0,0 +1,33 @@
# Generated by Django 6.0.1 on 2026-01-12 18:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0002_initial'),
]
operations = [
migrations.AddField(
model_name='user',
name='explanation_notification_channel',
field=models.CharField(choices=[('email', 'Email'), ('sms', 'SMS'), ('both', 'Both')], default='email', help_text='Preferred channel for explanation requests', max_length=10),
),
migrations.AddField(
model_name='user',
name='notification_email_enabled',
field=models.BooleanField(default=True, help_text='Enable email notifications'),
),
migrations.AddField(
model_name='user',
name='notification_sms_enabled',
field=models.BooleanField(default=False, help_text='Enable SMS notifications'),
),
migrations.AddField(
model_name='user',
name='preferred_notification_channel',
field=models.CharField(choices=[('email', 'Email'), ('sms', 'SMS'), ('both', 'Both')], default='email', help_text='Preferred notification channel for general notifications', max_length=10),
),
]

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -254,6 +254,153 @@ class PublicComplaintForm(forms.ModelForm):
return cleaned_data
class SLAConfigForm(forms.ModelForm):
"""Form for creating and editing SLA configurations"""
class Meta:
model = ComplaintSLAConfig
fields = ['hospital', 'severity', 'priority', 'sla_hours', 'reminder_hours_before', 'is_active']
widgets = {
'hospital': forms.Select(attrs={'class': 'form-select'}),
'severity': forms.Select(attrs={'class': 'form-select'}),
'priority': forms.Select(attrs={'class': 'form-select'}),
'sla_hours': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
'reminder_hours_before': forms.NumberInput(attrs={'class': 'form-control', 'min': '0'}),
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
# Filter hospitals based on user role
if user and not user.is_px_admin() and user.hospital:
self.fields['hospital'].queryset = Hospital.objects.filter(id=user.hospital.id)
self.fields['hospital'].initial = user.hospital
self.fields['hospital'].widget.attrs['readonly'] = True
def clean(self):
cleaned_data = super().clean()
hospital = cleaned_data.get('hospital')
severity = cleaned_data.get('severity')
priority = cleaned_data.get('priority')
sla_hours = cleaned_data.get('sla_hours')
reminder_hours = cleaned_data.get('reminder_hours_before')
# Validate SLA hours is positive
if sla_hours and sla_hours <= 0:
raise ValidationError({'sla_hours': 'SLA hours must be greater than 0'})
# Validate reminder hours < SLA hours
if sla_hours and reminder_hours and reminder_hours >= sla_hours:
raise ValidationError({'reminder_hours_before': 'Reminder hours must be less than SLA hours'})
# Check for unique combination (excluding current instance when editing)
if hospital and severity and priority:
queryset = ComplaintSLAConfig.objects.filter(
hospital=hospital,
severity=severity,
priority=priority
)
if self.instance.pk:
queryset = queryset.exclude(pk=self.instance.pk)
if queryset.exists():
raise ValidationError(
'An SLA configuration for this hospital, severity, and priority already exists.'
)
return cleaned_data
class EscalationRuleForm(forms.ModelForm):
"""Form for creating and editing escalation rules"""
class Meta:
model = EscalationRule
fields = [
'hospital', 'name', 'description', 'escalation_level', 'max_escalation_level',
'trigger_on_overdue', 'trigger_hours_overdue',
'reminder_escalation_enabled', 'reminder_escalation_hours',
'escalate_to_role', 'escalate_to_user',
'severity_filter', 'priority_filter', 'is_active'
]
widgets = {
'hospital': forms.Select(attrs={'class': 'form-select'}),
'name': forms.TextInput(attrs={'class': 'form-control'}),
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'escalation_level': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
'max_escalation_level': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
'trigger_on_overdue': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'trigger_hours_overdue': forms.NumberInput(attrs={'class': 'form-control', 'min': '0'}),
'reminder_escalation_enabled': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'reminder_escalation_hours': forms.NumberInput(attrs={'class': 'form-control', 'min': '0'}),
'escalate_to_role': forms.Select(attrs={'class': 'form-select', 'id': 'escalate_to_role'}),
'escalate_to_user': forms.Select(attrs={'class': 'form-select'}),
'severity_filter': forms.Select(attrs={'class': 'form-select'}),
'priority_filter': forms.Select(attrs={'class': 'form-select'}),
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
# Filter hospitals based on user role
if user and not user.is_px_admin() and user.hospital:
self.fields['hospital'].queryset = Hospital.objects.filter(id=user.hospital.id)
self.fields['hospital'].initial = user.hospital
self.fields['hospital'].widget.attrs['readonly'] = True
# Filter users for escalate_to_user field
from apps.accounts.models import User
if user and user.is_px_admin():
self.fields['escalate_to_user'].queryset = User.objects.filter(is_active=True)
elif user and user.hospital:
self.fields['escalate_to_user'].queryset = User.objects.filter(
is_active=True,
hospital=user.hospital
)
else:
self.fields['escalate_to_user'].queryset = User.objects.none()
def clean(self):
cleaned_data = super().clean()
escalate_to_role = cleaned_data.get('escalate_to_role')
escalate_to_user = cleaned_data.get('escalate_to_user')
# If role is 'specific_user', user must be specified
if escalate_to_role == 'specific_user' and not escalate_to_user:
raise ValidationError({'escalate_to_user': 'Please select a user when role is set to Specific User'})
return cleaned_data
class ComplaintThresholdForm(forms.ModelForm):
"""Form for creating and editing complaint thresholds"""
class Meta:
model = ComplaintThreshold
fields = ['hospital', 'threshold_type', 'threshold_value', 'comparison_operator', 'action_type', 'is_active']
widgets = {
'hospital': forms.Select(attrs={'class': 'form-select'}),
'threshold_type': forms.Select(attrs={'class': 'form-select'}),
'threshold_value': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.1'}),
'comparison_operator': forms.Select(attrs={'class': 'form-select'}),
'action_type': forms.Select(attrs={'class': 'form-select'}),
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
# Filter hospitals based on user role
if user and not user.is_px_admin() and user.hospital:
self.fields['hospital'].queryset = Hospital.objects.filter(id=user.hospital.id)
self.fields['hospital'].initial = user.hospital
self.fields['hospital'].widget.attrs['readonly'] = True
class ComplaintForm(forms.ModelForm):
"""
Form for creating complaints by authenticated users.

View File

@ -1,5 +1,4 @@
# Generated by Django 6.0.1 on 2026-01-15 12:02
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
from django.conf import settings

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
from django.conf import settings

View File

@ -0,0 +1,68 @@
# Generated by Django 6.0.1 on 2026-01-13 20:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('complaints', '0003_initial'),
]
operations = [
migrations.AddField(
model_name='complaint',
name='second_reminder_sent_at',
field=models.DateTimeField(blank=True, help_text='Second SLA reminder timestamp', null=True),
),
migrations.AddField(
model_name='complaintslaconfig',
name='second_reminder_enabled',
field=models.BooleanField(default=False, help_text='Enable sending a second reminder'),
),
migrations.AddField(
model_name='complaintslaconfig',
name='second_reminder_hours_before',
field=models.IntegerField(default=6, help_text='Send second reminder X hours before deadline'),
),
migrations.AddField(
model_name='complaintslaconfig',
name='thank_you_email_enabled',
field=models.BooleanField(default=False, help_text='Send thank you email when complaint is closed'),
),
migrations.AddField(
model_name='escalationrule',
name='escalation_level',
field=models.IntegerField(default=1, help_text='Escalation level (1 = first level, 2 = second, etc.)'),
),
migrations.AddField(
model_name='escalationrule',
name='max_escalation_level',
field=models.IntegerField(default=3, help_text='Maximum escalation level before stopping (default: 3)'),
),
migrations.AddField(
model_name='escalationrule',
name='reminder_escalation_enabled',
field=models.BooleanField(default=False, help_text='Enable escalation after reminder if no action taken'),
),
migrations.AddField(
model_name='escalationrule',
name='reminder_escalation_hours',
field=models.IntegerField(default=24, help_text='Escalate X hours after reminder if no action'),
),
migrations.AlterField(
model_name='complaint',
name='reminder_sent_at',
field=models.DateTimeField(blank=True, help_text='First SLA reminder timestamp', null=True),
),
migrations.AlterField(
model_name='complaintslaconfig',
name='reminder_hours_before',
field=models.IntegerField(default=24, help_text='Send first reminder X hours before deadline'),
),
migrations.AlterField(
model_name='escalationrule',
name='escalate_to_role',
field=models.CharField(choices=[('department_manager', 'Department Manager'), ('hospital_admin', 'Hospital Admin'), ('px_admin', 'PX Admin'), ('ceo', 'CEO'), ('specific_user', 'Specific User')], help_text='Role to escalate to', max_length=50),
),
]

View File

@ -0,0 +1,62 @@
# Generated by Django 6.0.1 on 2026-01-14 12:36
import django.db.models.deletion
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('complaints', '0004_add_second_reminder_sent_at'),
('organizations', '0004_staff_location_staff_name_staff_phone'),
]
operations = [
migrations.AddField(
model_name='complaintexplanation',
name='escalated_at',
field=models.DateTimeField(blank=True, help_text='When explanation was escalated to manager', null=True),
),
migrations.AddField(
model_name='complaintexplanation',
name='escalated_to_manager',
field=models.ForeignKey(blank=True, help_text="Escalated to this explanation (manager's explanation request)", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='escalated_from_staff', to='complaints.complaintexplanation'),
),
migrations.AddField(
model_name='complaintexplanation',
name='is_overdue',
field=models.BooleanField(db_index=True, default=False, help_text='Explanation request is overdue'),
),
migrations.AddField(
model_name='complaintexplanation',
name='reminder_sent_at',
field=models.DateTimeField(blank=True, help_text='Reminder sent to staff about overdue explanation', null=True),
),
migrations.AddField(
model_name='complaintexplanation',
name='sla_due_at',
field=models.DateTimeField(blank=True, db_index=True, help_text='SLA deadline for staff to submit explanation', null=True),
),
migrations.CreateModel(
name='ExplanationSLAConfig',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, db_index=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('response_hours', models.IntegerField(default=48, help_text='Hours staff has to submit explanation')),
('reminder_hours_before', models.IntegerField(default=12, help_text='Send reminder X hours before deadline')),
('auto_escalate_enabled', models.BooleanField(default=True, help_text='Automatically escalate to manager if no response')),
('escalation_hours_overdue', models.IntegerField(default=0, help_text='Escalate X hours after overdue (0 = immediately)')),
('max_escalation_levels', models.IntegerField(default=3, help_text='Maximum levels to escalate up staff hierarchy')),
('is_active', models.BooleanField(default=True)),
('hospital', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='explanation_sla_configs', to='organizations.hospital')),
],
options={
'verbose_name': 'Explanation SLA Config',
'verbose_name_plural': 'Explanation SLA Configs',
'ordering': ['hospital'],
'indexes': [models.Index(fields=['hospital', 'is_active'], name='complaints__hospita_fe4ec5_idx')],
},
),
]

View File

@ -169,7 +169,7 @@ class Complaint(UUIDModel, TimeStampedModel):
related_name="complaints",
null=True,
blank=True,
help_text="Source of complaint"
help_text="Source of complaint",
)
# Creator tracking
@ -761,7 +761,7 @@ class Inquiry(UUIDModel, TimeStampedModel):
related_name="inquiries",
null=True,
blank=True,
help_text="Source of inquiry"
help_text="Source of inquiry",
)
# Status

View File

@ -1,8 +1,6 @@
"""
Complaints UI views - Server-rendered templates for complaints console
"""
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
@ -242,14 +240,17 @@ def complaint_detail(request, pk):
explanation_attachments = explanation.attachments.all()
context = {
'complaint': complaint,
'timeline': timeline,
'attachments': attachments,
'px_actions': px_actions,
'assignable_users': assignable_users,
'status_choices': ComplaintStatus.choices,
'can_edit': user.is_px_admin() or user.is_hospital_admin(),
'hospital_departments': hospital_departments,
"complaint": complaint,
"timeline": timeline,
"attachments": attachments,
"px_actions": px_actions,
"assignable_users": assignable_users,
"status_choices": ComplaintStatus.choices,
"can_edit": user.is_px_admin() or user.is_hospital_admin(),
"hospital_departments": hospital_departments,
"explanation": explanation,
"explanations": explanations,
"explanation_attachments": explanation_attachments,
'base_layout': base_layout,
'source_user': source_user,
"complaint": complaint,
@ -403,6 +404,9 @@ def complaint_create(request):
except ComplaintCategory.DoesNotExist:
messages.error(request, "Selected category not found.")
return redirect("complaints:complaint_create")
except Exception as e:
messages.error(request, f"Error creating complaint: {str(e)}")
return redirect("complaints:complaint_create")
# GET request - show form
# Check for hospital parameter from URL (for pre-selection)

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0.1 on 2026-01-15 12:02
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
from django.conf import settings

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
from django.conf import settings

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
from django.db import migrations, models

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import apps.observations.models
import django.db.models.deletion

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -0,0 +1,41 @@
# Generated by Django 6.0.1 on 2026-01-13 13:07
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('organizations', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='hospital',
name='ceo',
field=models.ForeignKey(blank=True, help_text='Chief Executive Officer', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='hospitals_as_ceo', to=settings.AUTH_USER_MODEL, verbose_name='CEO'),
),
migrations.AddField(
model_name='hospital',
name='cfo',
field=models.ForeignKey(blank=True, help_text='Chief Financial Officer', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='hospitals_as_cfo', to=settings.AUTH_USER_MODEL, verbose_name='CFO'),
),
migrations.AddField(
model_name='hospital',
name='coo',
field=models.ForeignKey(blank=True, help_text='Chief Operating Officer', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='hospitals_as_coo', to=settings.AUTH_USER_MODEL, verbose_name='COO'),
),
migrations.AddField(
model_name='hospital',
name='medical_director',
field=models.ForeignKey(blank=True, help_text='Medical Director', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='hospitals_as_medical_director', to=settings.AUTH_USER_MODEL, verbose_name='Medical Director'),
),
migrations.AlterField(
model_name='hospital',
name='metadata',
field=models.JSONField(blank=True, default=dict, help_text='Hospital configuration settings'),
),
]

View File

@ -0,0 +1,44 @@
# Generated by Django 6.0.1 on 2026-01-13 13:35
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('organizations', '0002_hospital_ceo_hospital_cfo_hospital_coo_and_more'),
]
operations = [
migrations.AddField(
model_name='staff',
name='country',
field=models.CharField(blank=True, max_length=100, verbose_name='Country'),
),
migrations.AddField(
model_name='staff',
name='department_name',
field=models.CharField(blank=True, max_length=200, verbose_name='Department (Original)'),
),
migrations.AddField(
model_name='staff',
name='gender',
field=models.CharField(blank=True, choices=[('male', 'Male'), ('female', 'Female'), ('other', 'Other')], max_length=10),
),
migrations.AddField(
model_name='staff',
name='report_to',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='direct_reports', to='organizations.staff', verbose_name='Reports To'),
),
migrations.AddField(
model_name='staff',
name='section',
field=models.CharField(blank=True, max_length=200, verbose_name='Section'),
),
migrations.AddField(
model_name='staff',
name='subsection',
field=models.CharField(blank=True, max_length=200, verbose_name='Subsection'),
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 6.0.1 on 2026-01-13 13:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('organizations', '0003_staff_country_staff_department_name_staff_gender_and_more'),
]
operations = [
migrations.AddField(
model_name='staff',
name='location',
field=models.CharField(blank=True, max_length=200, verbose_name='Location'),
),
migrations.AddField(
model_name='staff',
name='name',
field=models.CharField(blank=True, max_length=300, verbose_name='Full Name (Original)'),
),
migrations.AddField(
model_name='staff',
name='phone',
field=models.CharField(blank=True, max_length=20, verbose_name='Phone Number'),
),
]

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0 on 2026-01-12 09:50
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
from django.conf import settings

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0.1 on 2026-01-15 12:02
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0.1 on 2026-01-15 12:02
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.db.models.deletion
import uuid

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import apps.references.models
import django.db.models.deletion

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0.1 on 2026-01-15 12:02
# Generated by Django 6.0.1 on 2026-01-12 09:50
from django.db import migrations, models

View File

@ -1,4 +1,4 @@
# Generated by Django 6.0.1 on 2026-01-15 12:02
# Generated by Django 6.0.1 on 2026-01-12 09:50
import django.core.validators
import django.db.models.deletion

View File

@ -1,4 +1,8 @@
<<<<<<< HEAD
# Generated by Django 6.0 on 2026-01-12 09:50
=======
# Generated by Django 6.0.1 on 2026-01-12 09:50
>>>>>>> 1f9d8a7 (update on the complaint sla and staff hierarchy)
import django.db.models.deletion
import uuid