# Generated by Django 6.0.1 on 2026-01-12 09:50 import django.db.models.deletion import uuid from django.conf import settings from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ('organizations', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name='ComplaintAttachment', 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)), ('file', models.FileField(upload_to='complaints/%Y/%m/%d/')), ('filename', models.CharField(max_length=500)), ('file_type', models.CharField(blank=True, max_length=100)), ('file_size', models.IntegerField(help_text='File size in bytes')), ('description', models.TextField(blank=True)), ], options={ 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='ComplaintCategory', 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)), ('code', models.CharField(help_text='Unique code for this category', max_length=50)), ('name_en', models.CharField(max_length=200)), ('name_ar', models.CharField(blank=True, max_length=200)), ('description_en', models.TextField(blank=True)), ('description_ar', models.TextField(blank=True)), ('order', models.IntegerField(default=0, help_text='Display order')), ('is_active', models.BooleanField(default=True)), ], options={ 'verbose_name_plural': 'Complaint Categories', 'ordering': ['order', 'name_en'], }, ), migrations.CreateModel( name='ComplaintExplanation', 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)), ('explanation', models.TextField(help_text="Staff's explanation about the complaint")), ('token', models.CharField(db_index=True, help_text='Unique access token for explanation submission', max_length=64, unique=True)), ('is_used', models.BooleanField(db_index=True, default=False, help_text='Token expiry tracking - becomes True after submission')), ('submitted_via', models.CharField(choices=[('email_link', 'Email Link'), ('direct', 'Direct Entry')], default='email_link', help_text='How the explanation was submitted', max_length=20)), ('email_sent_at', models.DateTimeField(blank=True, help_text='When the explanation request email was sent', null=True)), ('responded_at', models.DateTimeField(blank=True, help_text='When the explanation was submitted', null=True)), ('request_message', models.TextField(blank=True, help_text='Optional message sent with the explanation request')), ], options={ 'verbose_name': 'Complaint Explanation', 'verbose_name_plural': 'Complaint Explanations', 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='ComplaintSLAConfig', 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)), ('severity', models.CharField(choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High'), ('critical', 'Critical')], help_text='Severity level for this SLA', max_length=20)), ('priority', models.CharField(choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High'), ('critical', 'Critical')], help_text='Priority level for this SLA', max_length=20)), ('sla_hours', models.IntegerField(help_text='Number of hours until SLA deadline')), ('reminder_hours_before', models.IntegerField(default=24, help_text='Send first reminder X hours before deadline')), ('second_reminder_enabled', models.BooleanField(default=False, help_text='Enable sending a second reminder')), ('second_reminder_hours_before', models.IntegerField(default=6, help_text='Send second reminder X hours before deadline')), ('thank_you_email_enabled', models.BooleanField(default=False, help_text='Send thank you email when complaint is closed')), ('is_active', models.BooleanField(default=True)), ], options={ 'ordering': ['hospital', 'severity', 'priority'], }, ), migrations.CreateModel( name='ComplaintThreshold', 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)), ('threshold_type', models.CharField(choices=[('resolution_survey_score', 'Resolution Survey Score'), ('response_time', 'Response Time'), ('resolution_time', 'Resolution Time')], help_text='Type of threshold', max_length=50)), ('threshold_value', models.FloatField(help_text='Threshold value (e.g., 50 for 50% score)')), ('comparison_operator', models.CharField(choices=[('lt', 'Less Than'), ('lte', 'Less Than or Equal'), ('gt', 'Greater Than'), ('gte', 'Greater Than or Equal'), ('eq', 'Equal')], default='lt', help_text='How to compare against threshold', max_length=10)), ('action_type', models.CharField(choices=[('create_px_action', 'Create PX Action'), ('send_notification', 'Send Notification'), ('escalate', 'Escalate')], help_text='Action to take when threshold is breached', max_length=50)), ('is_active', models.BooleanField(default=True)), ], options={ 'ordering': ['hospital', 'threshold_type'], }, ), migrations.CreateModel( name='ComplaintUpdate', 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)), ('update_type', models.CharField(choices=[('status_change', 'Status Change'), ('assignment', 'Assignment'), ('note', 'Note'), ('resolution', 'Resolution'), ('escalation', 'Escalation'), ('communication', 'Communication')], db_index=True, max_length=50)), ('message', models.TextField()), ('old_status', models.CharField(blank=True, max_length=20)), ('new_status', models.CharField(blank=True, max_length=20)), ('metadata', models.JSONField(blank=True, default=dict)), ], options={ 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='EscalationRule', 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)), ('name', models.CharField(max_length=200)), ('description', models.TextField(blank=True)), ('escalation_level', models.IntegerField(default=1, help_text='Escalation level (1 = first level, 2 = second, etc.)')), ('max_escalation_level', models.IntegerField(default=3, help_text='Maximum escalation level before stopping (default: 3)')), ('trigger_on_overdue', models.BooleanField(default=True, help_text='Trigger when complaint is overdue')), ('trigger_hours_overdue', models.IntegerField(default=0, help_text='Trigger X hours after overdue (0 = immediately)')), ('reminder_escalation_enabled', models.BooleanField(default=False, help_text='Enable escalation after reminder if no action taken')), ('reminder_escalation_hours', models.IntegerField(default=24, help_text='Escalate X hours after reminder if no action')), ('escalate_to_role', 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)), ('severity_filter', models.CharField(blank=True, choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High'), ('critical', 'Critical')], help_text='Only escalate complaints with this severity (blank = all)', max_length=20)), ('priority_filter', models.CharField(blank=True, choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High'), ('critical', 'Critical')], help_text='Only escalate complaints with this priority (blank = all)', max_length=20)), ('order', models.IntegerField(default=0, help_text='Escalation order (lower = first)')), ('is_active', models.BooleanField(default=True)), ], options={ 'ordering': ['hospital', 'order'], }, ), migrations.CreateModel( name='ExplanationAttachment', 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)), ('file', models.FileField(upload_to='explanation_attachments/%Y/%m/%d/')), ('filename', models.CharField(max_length=500)), ('file_type', models.CharField(blank=True, max_length=100)), ('file_size', models.IntegerField(help_text='File size in bytes')), ('description', models.TextField(blank=True)), ], options={ 'verbose_name': 'Explanation Attachment', 'verbose_name_plural': 'Explanation Attachments', 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='Inquiry', 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)), ('contact_name', models.CharField(blank=True, max_length=200)), ('contact_phone', models.CharField(blank=True, max_length=20)), ('contact_email', models.EmailField(blank=True, max_length=254)), ('subject', models.CharField(max_length=500)), ('message', models.TextField()), ('category', models.CharField(choices=[('appointment', 'Appointment'), ('billing', 'Billing'), ('medical_records', 'Medical Records'), ('general', 'General Information'), ('other', 'Other')], max_length=100)), ('status', models.CharField(choices=[('open', 'Open'), ('in_progress', 'In Progress'), ('resolved', 'Resolved'), ('closed', 'Closed')], db_index=True, default='open', max_length=20)), ('response', models.TextField(blank=True)), ('responded_at', models.DateTimeField(blank=True, null=True)), ], options={ 'verbose_name_plural': 'Inquiries', 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='InquiryAttachment', 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)), ('file', models.FileField(upload_to='inquiries/%Y/%m/%d/')), ('filename', models.CharField(max_length=500)), ('file_type', models.CharField(blank=True, max_length=100)), ('file_size', models.IntegerField(help_text='File size in bytes')), ('description', models.TextField(blank=True)), ], options={ 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='InquiryUpdate', 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)), ('update_type', models.CharField(choices=[('status_change', 'Status Change'), ('assignment', 'Assignment'), ('note', 'Note'), ('response', 'Response'), ('communication', 'Communication')], db_index=True, max_length=50)), ('message', models.TextField()), ('old_status', models.CharField(blank=True, max_length=20)), ('new_status', models.CharField(blank=True, max_length=20)), ('metadata', models.JSONField(blank=True, default=dict)), ], options={ 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='Complaint', 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)), ('contact_name', models.CharField(blank=True, max_length=200)), ('contact_phone', models.CharField(blank=True, max_length=20)), ('contact_email', models.EmailField(blank=True, max_length=254)), ('reference_number', models.CharField(blank=True, db_index=True, help_text='Unique reference number for patient tracking', max_length=50, null=True, unique=True)), ('encounter_id', models.CharField(blank=True, db_index=True, help_text='Related encounter ID if applicable', max_length=100)), ('title', models.CharField(max_length=500)), ('description', models.TextField()), ('subcategory', models.CharField(blank=True, max_length=100)), ('priority', models.CharField(choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High'), ('critical', 'Critical')], db_index=True, default='medium', max_length=20)), ('severity', models.CharField(choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High'), ('critical', 'Critical')], db_index=True, default='medium', max_length=20)), ('status', models.CharField(choices=[('open', 'Open'), ('in_progress', 'In Progress'), ('resolved', 'Resolved'), ('closed', 'Closed'), ('cancelled', 'Cancelled')], db_index=True, default='open', max_length=20)), ('assigned_at', models.DateTimeField(blank=True, null=True)), ('due_at', models.DateTimeField(db_index=True, help_text='SLA deadline')), ('is_overdue', models.BooleanField(db_index=True, default=False)), ('reminder_sent_at', models.DateTimeField(blank=True, help_text='First SLA reminder timestamp', null=True)), ('second_reminder_sent_at', models.DateTimeField(blank=True, help_text='Second SLA reminder timestamp', null=True)), ('escalated_at', models.DateTimeField(blank=True, null=True)), ('resolution', models.TextField(blank=True)), ('resolved_at', models.DateTimeField(blank=True, null=True)), ('closed_at', models.DateTimeField(blank=True, null=True)), ('resolution_survey_sent_at', models.DateTimeField(blank=True, null=True)), ('metadata', models.JSONField(blank=True, default=dict)), ('assigned_to', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_complaints', to=settings.AUTH_USER_MODEL)), ('closed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='closed_complaints', to=settings.AUTH_USER_MODEL)), ('department', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='complaints', to='organizations.department')), ('hospital', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='complaints', to='organizations.hospital')), ('patient', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='complaints', to='organizations.patient')), ], options={ 'ordering': ['-created_at'], }, ), ]