2026-01-15 15:02:42 +03:00

164 lines
12 KiB
Python

# Generated by Django 6.0 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 = [
('contenttypes', '0002_remove_content_type_name'),
('organizations', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='PXAction',
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)),
('source_type', models.CharField(choices=[('survey', 'Negative Survey'), ('complaint', 'Complaint'), ('complaint_resolution', 'Negative Complaint Resolution'), ('social_media', 'Social Media'), ('call_center', 'Call Center'), ('kpi', 'KPI Decline'), ('manual', 'Manual')], db_index=True, max_length=50)),
('object_id', models.UUIDField(blank=True, null=True)),
('title', models.CharField(max_length=500)),
('description', models.TextField()),
('category', models.CharField(choices=[('clinical_quality', 'Clinical Quality'), ('patient_safety', 'Patient Safety'), ('service_quality', 'Service Quality'), ('staff_behavior', 'Staff Behavior'), ('facility', 'Facility & Environment'), ('process_improvement', 'Process Improvement'), ('other', 'Other')], db_index=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'), ('pending_approval', 'Pending Approval'), ('approved', 'Approved'), ('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, null=True)),
('escalated_at', models.DateTimeField(blank=True, null=True)),
('escalation_level', models.IntegerField(default=0, help_text='Number of times escalated')),
('requires_approval', models.BooleanField(default=True, help_text='Requires PX Admin approval before closure')),
('approved_at', models.DateTimeField(blank=True, null=True)),
('closed_at', models.DateTimeField(blank=True, null=True)),
('action_plan', models.TextField(blank=True)),
('outcome', models.TextField(blank=True)),
('metadata', models.JSONField(blank=True, default=dict)),
('approved_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='approved_actions', to=settings.AUTH_USER_MODEL)),
('assigned_to', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_actions', to=settings.AUTH_USER_MODEL)),
('closed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='closed_actions', to=settings.AUTH_USER_MODEL)),
('content_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
('department', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='px_actions', to='organizations.department')),
('hospital', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='px_actions', to='organizations.hospital')),
],
options={
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='PXActionAttachment',
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='actions/%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)),
('is_evidence', models.BooleanField(default=False, help_text='Mark as evidence for closure')),
('action', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attachments', to='px_action_center.pxaction')),
('uploaded_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='action_attachments', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='PXActionLog',
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)),
('log_type', models.CharField(choices=[('status_change', 'Status Change'), ('assignment', 'Assignment'), ('escalation', 'Escalation'), ('note', 'Note'), ('evidence', 'Evidence Added'), ('approval', 'Approval'), ('sla_reminder', 'SLA Reminder')], 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)),
('action', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='px_action_center.pxaction')),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='action_logs', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='PXActionSLAConfig',
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)),
('critical_hours', models.IntegerField(default=24)),
('high_hours', models.IntegerField(default=48)),
('medium_hours', models.IntegerField(default=72)),
('low_hours', models.IntegerField(default=120)),
('reminder_hours_before', models.IntegerField(default=4, help_text='Send reminder X hours before due')),
('auto_escalate', models.BooleanField(default=True, help_text='Automatically escalate when overdue')),
('escalation_delay_hours', models.IntegerField(default=2, help_text='Hours after overdue before escalation')),
('is_active', models.BooleanField(default=True)),
('department', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='action_sla_configs', to='organizations.department')),
('hospital', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='action_sla_configs', to='organizations.hospital')),
],
options={
'ordering': ['hospital', 'name'],
},
),
migrations.CreateModel(
name='RoutingRule',
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)),
('source_type', models.CharField(blank=True, choices=[('survey', 'Negative Survey'), ('complaint', 'Complaint'), ('complaint_resolution', 'Negative Complaint Resolution'), ('social_media', 'Social Media'), ('call_center', 'Call Center'), ('kpi', 'KPI Decline'), ('manual', 'Manual')], max_length=50)),
('category', models.CharField(blank=True, max_length=100)),
('severity', models.CharField(blank=True, choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High'), ('critical', 'Critical')], max_length=20)),
('assign_to_role', models.CharField(blank=True, help_text="Role to assign to (e.g., 'PX Coordinator')", max_length=50)),
('priority', models.IntegerField(default=0, help_text='Higher priority rules are evaluated first')),
('is_active', models.BooleanField(default=True)),
('assign_to_department', models.ForeignKey(blank=True, help_text='Department to assign to', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='routing_target_rules', to='organizations.department')),
('assign_to_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='routing_rules', to=settings.AUTH_USER_MODEL)),
('department', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='routing_rules', to='organizations.department')),
('hospital', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='routing_rules', to='organizations.hospital')),
],
options={
'ordering': ['-priority', 'name'],
},
),
migrations.AddIndex(
model_name='pxaction',
index=models.Index(fields=['status', '-created_at'], name='px_action_c_status_3bd857_idx'),
),
migrations.AddIndex(
model_name='pxaction',
index=models.Index(fields=['hospital', 'status', '-created_at'], name='px_action_c_hospita_6b2d44_idx'),
),
migrations.AddIndex(
model_name='pxaction',
index=models.Index(fields=['is_overdue', 'status'], name='px_action_c_is_over_e0d12c_idx'),
),
migrations.AddIndex(
model_name='pxaction',
index=models.Index(fields=['due_at', 'status'], name='px_action_c_due_at_947f38_idx'),
),
migrations.AddIndex(
model_name='pxaction',
index=models.Index(fields=['source_type', '-created_at'], name='px_action_c_source__3f0ae5_idx'),
),
migrations.AddIndex(
model_name='pxactionlog',
index=models.Index(fields=['action', '-created_at'], name='px_action_c_action__656e57_idx'),
),
]