1568 lines
59 KiB
Python
1568 lines
59 KiB
Python
# Generated by Django 5.2.6 on 2025-09-19 10:58
|
|
|
|
import django.core.validators
|
|
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 = [
|
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
]
|
|
|
|
operations = [
|
|
migrations.CreateModel(
|
|
name="AppointmentTemplate",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
("name", models.CharField(help_text="Template name", max_length=200)),
|
|
(
|
|
"description",
|
|
models.TextField(
|
|
blank=True, help_text="Template description", null=True
|
|
),
|
|
),
|
|
(
|
|
"appointment_type",
|
|
models.CharField(
|
|
help_text="Default appointment type", max_length=50
|
|
),
|
|
),
|
|
(
|
|
"specialty",
|
|
models.CharField(help_text="Medical specialty", max_length=100),
|
|
),
|
|
(
|
|
"duration_minutes",
|
|
models.PositiveIntegerField(
|
|
help_text="Default duration in minutes"
|
|
),
|
|
),
|
|
(
|
|
"advance_booking_days",
|
|
models.PositiveIntegerField(
|
|
default=30, help_text="Maximum advance booking days"
|
|
),
|
|
),
|
|
(
|
|
"minimum_notice_hours",
|
|
models.PositiveIntegerField(
|
|
default=24, help_text="Minimum notice required in hours"
|
|
),
|
|
),
|
|
(
|
|
"insurance_verification_required",
|
|
models.BooleanField(
|
|
default=False, help_text="Insurance verification required"
|
|
),
|
|
),
|
|
(
|
|
"authorization_required",
|
|
models.BooleanField(
|
|
default=False, help_text="Prior authorization required"
|
|
),
|
|
),
|
|
(
|
|
"pre_appointment_instructions",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Pre-appointment instructions for patient",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"post_appointment_instructions",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Post-appointment instructions template",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"required_forms",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=list,
|
|
help_text="Required forms for this appointment type",
|
|
),
|
|
),
|
|
(
|
|
"is_active",
|
|
models.BooleanField(default=True, help_text="Template is active"),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
],
|
|
options={
|
|
"verbose_name": "Appointment Template",
|
|
"verbose_name_plural": "Appointment Templates",
|
|
"db_table": "appointments_appointment_template",
|
|
"ordering": ["specialty", "name"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="QueueEntry",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"entry_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique entry identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
(
|
|
"queue_position",
|
|
models.PositiveIntegerField(help_text="Position in queue"),
|
|
),
|
|
(
|
|
"priority_score",
|
|
models.FloatField(
|
|
default=1.0, help_text="Priority score for queue ordering"
|
|
),
|
|
),
|
|
(
|
|
"joined_at",
|
|
models.DateTimeField(
|
|
auto_now_add=True, help_text="Time patient joined queue"
|
|
),
|
|
),
|
|
(
|
|
"estimated_service_time",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Estimated service time", null=True
|
|
),
|
|
),
|
|
(
|
|
"called_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Time patient was called", null=True
|
|
),
|
|
),
|
|
(
|
|
"served_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Time patient was served", null=True
|
|
),
|
|
),
|
|
(
|
|
"status",
|
|
models.CharField(
|
|
choices=[
|
|
("WAITING", "Waiting"),
|
|
("CALLED", "Called"),
|
|
("IN_SERVICE", "In Service"),
|
|
("COMPLETED", "Completed"),
|
|
("LEFT", "Left Queue"),
|
|
("NO_SHOW", "No Show"),
|
|
],
|
|
default="WAITING",
|
|
help_text="Queue entry status",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"notification_sent",
|
|
models.BooleanField(
|
|
default=False, help_text="Notification sent to patient"
|
|
),
|
|
),
|
|
(
|
|
"notification_method",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("SMS", "SMS"),
|
|
("EMAIL", "Email"),
|
|
("PHONE", "Phone Call"),
|
|
("PAGER", "Pager"),
|
|
("APP", "Mobile App"),
|
|
],
|
|
help_text="Notification method used",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"notes",
|
|
models.TextField(
|
|
blank=True, help_text="Additional notes", null=True
|
|
),
|
|
),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
],
|
|
options={
|
|
"verbose_name": "Queue Entry",
|
|
"verbose_name_plural": "Queue Entries",
|
|
"db_table": "appointments_queue_entry",
|
|
"ordering": ["queue", "priority_score", "joined_at"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="SlotAvailability",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"slot_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique slot identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
("date", models.DateField(help_text="Availability date")),
|
|
("start_time", models.TimeField(help_text="Slot start time")),
|
|
("end_time", models.TimeField(help_text="Slot end time")),
|
|
(
|
|
"duration_minutes",
|
|
models.PositiveIntegerField(help_text="Slot duration in minutes"),
|
|
),
|
|
(
|
|
"availability_type",
|
|
models.CharField(
|
|
choices=[
|
|
("REGULAR", "Regular Hours"),
|
|
("EXTENDED", "Extended Hours"),
|
|
("EMERGENCY", "Emergency"),
|
|
("ON_CALL", "On Call"),
|
|
("TELEMEDICINE", "Telemedicine Only"),
|
|
],
|
|
default="REGULAR",
|
|
help_text="Type of availability",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"max_appointments",
|
|
models.PositiveIntegerField(
|
|
default=1, help_text="Maximum appointments for this slot"
|
|
),
|
|
),
|
|
(
|
|
"booked_appointments",
|
|
models.PositiveIntegerField(
|
|
default=0, help_text="Number of booked appointments"
|
|
),
|
|
),
|
|
(
|
|
"location",
|
|
models.CharField(help_text="Appointment location", max_length=200),
|
|
),
|
|
(
|
|
"room_number",
|
|
models.CharField(
|
|
blank=True, help_text="Room number", max_length=50, null=True
|
|
),
|
|
),
|
|
(
|
|
"specialty",
|
|
models.CharField(
|
|
help_text="Medical specialty for this slot", max_length=100
|
|
),
|
|
),
|
|
(
|
|
"appointment_types",
|
|
models.JSONField(
|
|
default=list,
|
|
help_text="Allowed appointment types for this slot",
|
|
),
|
|
),
|
|
(
|
|
"patient_restrictions",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=dict,
|
|
help_text="Patient restrictions (age, gender, etc.)",
|
|
),
|
|
),
|
|
(
|
|
"insurance_restrictions",
|
|
models.JSONField(
|
|
blank=True, default=list, help_text="Accepted insurance types"
|
|
),
|
|
),
|
|
(
|
|
"supports_telemedicine",
|
|
models.BooleanField(
|
|
default=False,
|
|
help_text="Slot supports telemedicine appointments",
|
|
),
|
|
),
|
|
(
|
|
"telemedicine_only",
|
|
models.BooleanField(
|
|
default=False, help_text="Telemedicine only slot"
|
|
),
|
|
),
|
|
(
|
|
"is_active",
|
|
models.BooleanField(
|
|
default=True, help_text="Slot is active and bookable"
|
|
),
|
|
),
|
|
(
|
|
"is_blocked",
|
|
models.BooleanField(
|
|
default=False, help_text="Slot is temporarily blocked"
|
|
),
|
|
),
|
|
(
|
|
"block_reason",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Reason for blocking slot",
|
|
max_length=200,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"is_recurring",
|
|
models.BooleanField(
|
|
default=False, help_text="Slot is part of recurring pattern"
|
|
),
|
|
),
|
|
(
|
|
"recurrence_pattern",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=dict,
|
|
help_text="Recurrence pattern configuration",
|
|
),
|
|
),
|
|
(
|
|
"recurrence_end_date",
|
|
models.DateField(
|
|
blank=True,
|
|
help_text="End date for recurring pattern",
|
|
null=True,
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
],
|
|
options={
|
|
"verbose_name": "Slot Availability",
|
|
"verbose_name_plural": "Slot Availability",
|
|
"db_table": "appointments_slot_availability",
|
|
"ordering": ["date", "start_time"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="TelemedicineSession",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"session_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique session identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
(
|
|
"platform",
|
|
models.CharField(
|
|
choices=[
|
|
("ZOOM", "Zoom"),
|
|
("TEAMS", "Microsoft Teams"),
|
|
("WEBEX", "Cisco Webex"),
|
|
("DOXY", "Doxy.me"),
|
|
("CUSTOM", "Custom Platform"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Telemedicine platform",
|
|
max_length=50,
|
|
),
|
|
),
|
|
("meeting_url", models.URLField(help_text="Meeting URL")),
|
|
(
|
|
"meeting_id",
|
|
models.CharField(
|
|
help_text="Meeting ID or room number", max_length=100
|
|
),
|
|
),
|
|
(
|
|
"meeting_password",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Meeting password",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"waiting_room_enabled",
|
|
models.BooleanField(default=True, help_text="Waiting room enabled"),
|
|
),
|
|
(
|
|
"recording_enabled",
|
|
models.BooleanField(
|
|
default=False, help_text="Session recording enabled"
|
|
),
|
|
),
|
|
(
|
|
"recording_consent",
|
|
models.BooleanField(
|
|
default=False, help_text="Patient consent for recording"
|
|
),
|
|
),
|
|
(
|
|
"encryption_enabled",
|
|
models.BooleanField(
|
|
default=True, help_text="End-to-end encryption enabled"
|
|
),
|
|
),
|
|
(
|
|
"password_required",
|
|
models.BooleanField(
|
|
default=True, help_text="Password required to join"
|
|
),
|
|
),
|
|
(
|
|
"status",
|
|
models.CharField(
|
|
choices=[
|
|
("SCHEDULED", "Scheduled"),
|
|
("READY", "Ready to Start"),
|
|
("IN_PROGRESS", "In Progress"),
|
|
("COMPLETED", "Completed"),
|
|
("CANCELLED", "Cancelled"),
|
|
("FAILED", "Failed"),
|
|
],
|
|
default="SCHEDULED",
|
|
help_text="Session status",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"scheduled_start",
|
|
models.DateTimeField(help_text="Scheduled start time"),
|
|
),
|
|
("scheduled_end", models.DateTimeField(help_text="Scheduled end time")),
|
|
(
|
|
"actual_start",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Actual start time", null=True
|
|
),
|
|
),
|
|
(
|
|
"actual_end",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Actual end time", null=True
|
|
),
|
|
),
|
|
(
|
|
"provider_joined_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Provider join time", null=True
|
|
),
|
|
),
|
|
(
|
|
"patient_joined_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Patient join time", null=True
|
|
),
|
|
),
|
|
(
|
|
"connection_quality",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("EXCELLENT", "Excellent"),
|
|
("GOOD", "Good"),
|
|
("FAIR", "Fair"),
|
|
("POOR", "Poor"),
|
|
],
|
|
help_text="Connection quality",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"technical_issues",
|
|
models.TextField(
|
|
blank=True, help_text="Technical issues encountered", null=True
|
|
),
|
|
),
|
|
(
|
|
"recording_url",
|
|
models.URLField(blank=True, help_text="Recording URL", null=True),
|
|
),
|
|
(
|
|
"recording_duration_minutes",
|
|
models.PositiveIntegerField(
|
|
blank=True, help_text="Recording duration in minutes", null=True
|
|
),
|
|
),
|
|
(
|
|
"session_notes",
|
|
models.TextField(blank=True, help_text="Session notes", null=True),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
],
|
|
options={
|
|
"verbose_name": "Telemedicine Session",
|
|
"verbose_name_plural": "Telemedicine Sessions",
|
|
"db_table": "appointments_telemedicine_session",
|
|
"ordering": ["-scheduled_start"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="WaitingList",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"waiting_list_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique waiting list entry identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
(
|
|
"appointment_type",
|
|
models.CharField(
|
|
choices=[
|
|
("CONSULTATION", "Consultation"),
|
|
("FOLLOW_UP", "Follow-up"),
|
|
("PROCEDURE", "Procedure"),
|
|
("SURGERY", "Surgery"),
|
|
("DIAGNOSTIC", "Diagnostic"),
|
|
("THERAPY", "Therapy"),
|
|
("VACCINATION", "Vaccination"),
|
|
("SCREENING", "Screening"),
|
|
("EMERGENCY", "Emergency"),
|
|
("TELEMEDICINE", "Telemedicine"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Type of appointment requested",
|
|
max_length=50,
|
|
),
|
|
),
|
|
(
|
|
"specialty",
|
|
models.CharField(
|
|
choices=[
|
|
("FAMILY_MEDICINE", "Family Medicine"),
|
|
("INTERNAL_MEDICINE", "Internal Medicine"),
|
|
("PEDIATRICS", "Pediatrics"),
|
|
("CARDIOLOGY", "Cardiology"),
|
|
("DERMATOLOGY", "Dermatology"),
|
|
("ENDOCRINOLOGY", "Endocrinology"),
|
|
("GASTROENTEROLOGY", "Gastroenterology"),
|
|
("NEUROLOGY", "Neurology"),
|
|
("ONCOLOGY", "Oncology"),
|
|
("ORTHOPEDICS", "Orthopedics"),
|
|
("PSYCHIATRY", "Psychiatry"),
|
|
("RADIOLOGY", "Radiology"),
|
|
("SURGERY", "Surgery"),
|
|
("UROLOGY", "Urology"),
|
|
("GYNECOLOGY", "Gynecology"),
|
|
("OPHTHALMOLOGY", "Ophthalmology"),
|
|
("ENT", "Ear, Nose & Throat"),
|
|
("EMERGENCY", "Emergency Medicine"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Medical specialty required",
|
|
max_length=100,
|
|
),
|
|
),
|
|
(
|
|
"priority",
|
|
models.CharField(
|
|
choices=[
|
|
("ROUTINE", "Routine"),
|
|
("URGENT", "Urgent"),
|
|
("STAT", "STAT"),
|
|
("EMERGENCY", "Emergency"),
|
|
],
|
|
default="ROUTINE",
|
|
help_text="Clinical priority level",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"urgency_score",
|
|
models.PositiveIntegerField(
|
|
default=1,
|
|
help_text="Clinical urgency score (1-10, 10 being most urgent)",
|
|
validators=[
|
|
django.core.validators.MinValueValidator(1),
|
|
django.core.validators.MaxValueValidator(10),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"clinical_indication",
|
|
models.TextField(
|
|
help_text="Clinical reason for appointment request"
|
|
),
|
|
),
|
|
(
|
|
"diagnosis_codes",
|
|
models.JSONField(
|
|
blank=True, default=list, help_text="ICD-10 diagnosis codes"
|
|
),
|
|
),
|
|
(
|
|
"preferred_date",
|
|
models.DateField(
|
|
blank=True,
|
|
help_text="Patient preferred appointment date",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"preferred_time",
|
|
models.TimeField(
|
|
blank=True,
|
|
help_text="Patient preferred appointment time",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"flexible_scheduling",
|
|
models.BooleanField(
|
|
default=True,
|
|
help_text="Patient accepts alternative dates/times",
|
|
),
|
|
),
|
|
(
|
|
"earliest_acceptable_date",
|
|
models.DateField(
|
|
blank=True,
|
|
help_text="Earliest acceptable appointment date",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"latest_acceptable_date",
|
|
models.DateField(
|
|
blank=True,
|
|
help_text="Latest acceptable appointment date",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"acceptable_days",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=list,
|
|
help_text="Acceptable days of week (0=Monday, 6=Sunday)",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"acceptable_times",
|
|
models.JSONField(
|
|
blank=True, default=list, help_text="Acceptable time ranges"
|
|
),
|
|
),
|
|
(
|
|
"contact_method",
|
|
models.CharField(
|
|
choices=[
|
|
("PHONE", "Phone"),
|
|
("EMAIL", "Email"),
|
|
("SMS", "SMS"),
|
|
("PORTAL", "Patient Portal"),
|
|
("MAIL", "Mail"),
|
|
],
|
|
default="PHONE",
|
|
help_text="Preferred contact method",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"contact_phone",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Contact phone number",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"contact_email",
|
|
models.EmailField(
|
|
blank=True,
|
|
help_text="Contact email address",
|
|
max_length=254,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"status",
|
|
models.CharField(
|
|
choices=[
|
|
("ACTIVE", "Active"),
|
|
("CONTACTED", "Contacted"),
|
|
("OFFERED", "Appointment Offered"),
|
|
("SCHEDULED", "Scheduled"),
|
|
("CANCELLED", "Cancelled"),
|
|
("EXPIRED", "Expired"),
|
|
("TRANSFERRED", "Transferred"),
|
|
],
|
|
default="ACTIVE",
|
|
help_text="Waiting list status",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"position",
|
|
models.PositiveIntegerField(
|
|
blank=True,
|
|
help_text="Position in waiting list queue",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"estimated_wait_time",
|
|
models.PositiveIntegerField(
|
|
blank=True, help_text="Estimated wait time in days", null=True
|
|
),
|
|
),
|
|
(
|
|
"last_contacted",
|
|
models.DateTimeField(
|
|
blank=True,
|
|
help_text="Last contact attempt date/time",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"contact_attempts",
|
|
models.PositiveIntegerField(
|
|
default=0, help_text="Number of contact attempts made"
|
|
),
|
|
),
|
|
(
|
|
"max_contact_attempts",
|
|
models.PositiveIntegerField(
|
|
default=3, help_text="Maximum contact attempts before expiring"
|
|
),
|
|
),
|
|
(
|
|
"appointments_offered",
|
|
models.PositiveIntegerField(
|
|
default=0, help_text="Number of appointments offered"
|
|
),
|
|
),
|
|
(
|
|
"appointments_declined",
|
|
models.PositiveIntegerField(
|
|
default=0, help_text="Number of appointments declined"
|
|
),
|
|
),
|
|
(
|
|
"last_offer_date",
|
|
models.DateTimeField(
|
|
blank=True,
|
|
help_text="Date of last appointment offer",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"requires_interpreter",
|
|
models.BooleanField(
|
|
default=False, help_text="Patient requires interpreter services"
|
|
),
|
|
),
|
|
(
|
|
"interpreter_language",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Required interpreter language",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"accessibility_requirements",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Special accessibility requirements",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"transportation_needed",
|
|
models.BooleanField(
|
|
default=False,
|
|
help_text="Patient needs transportation assistance",
|
|
),
|
|
),
|
|
(
|
|
"insurance_verified",
|
|
models.BooleanField(
|
|
default=False, help_text="Insurance coverage verified"
|
|
),
|
|
),
|
|
(
|
|
"authorization_required",
|
|
models.BooleanField(
|
|
default=False, help_text="Prior authorization required"
|
|
),
|
|
),
|
|
(
|
|
"authorization_status",
|
|
models.CharField(
|
|
choices=[
|
|
("NOT_REQUIRED", "Not Required"),
|
|
("PENDING", "Pending"),
|
|
("APPROVED", "Approved"),
|
|
("DENIED", "Denied"),
|
|
("EXPIRED", "Expired"),
|
|
],
|
|
default="NOT_REQUIRED",
|
|
help_text="Authorization status",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"authorization_number",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Authorization number",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"referring_provider",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Referring provider name",
|
|
max_length=200,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"referral_date",
|
|
models.DateField(
|
|
blank=True, help_text="Date of referral", null=True
|
|
),
|
|
),
|
|
(
|
|
"referral_urgency",
|
|
models.CharField(
|
|
choices=[
|
|
("ROUTINE", "Routine"),
|
|
("URGENT", "Urgent"),
|
|
("STAT", "STAT"),
|
|
],
|
|
default="ROUTINE",
|
|
help_text="Referral urgency level",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"removal_reason",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("SCHEDULED", "Appointment Scheduled"),
|
|
("PATIENT_CANCELLED", "Patient Cancelled"),
|
|
("PROVIDER_CANCELLED", "Provider Cancelled"),
|
|
("NO_RESPONSE", "No Response to Contact"),
|
|
("INSURANCE_ISSUE", "Insurance Issue"),
|
|
("TRANSFERRED", "Transferred to Another Provider"),
|
|
("EXPIRED", "Entry Expired"),
|
|
("DUPLICATE", "Duplicate Entry"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Reason for removal from waiting list",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"removal_notes",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Additional notes about removal",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"removed_at",
|
|
models.DateTimeField(
|
|
blank=True,
|
|
help_text="Date/time removed from waiting list",
|
|
null=True,
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
(
|
|
"notes",
|
|
models.TextField(
|
|
blank=True, help_text="Additional notes and comments", null=True
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Waiting List Entry",
|
|
"verbose_name_plural": "Waiting List Entries",
|
|
"db_table": "appointments_waiting_list",
|
|
"ordering": ["priority", "urgency_score", "created_at"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="WaitingListContactLog",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"contact_date",
|
|
models.DateTimeField(
|
|
auto_now_add=True, help_text="Date and time of contact attempt"
|
|
),
|
|
),
|
|
(
|
|
"contact_method",
|
|
models.CharField(
|
|
choices=[
|
|
("PHONE", "Phone Call"),
|
|
("EMAIL", "Email"),
|
|
("SMS", "SMS"),
|
|
("PORTAL", "Patient Portal Message"),
|
|
("MAIL", "Mail"),
|
|
("IN_PERSON", "In Person"),
|
|
],
|
|
help_text="Method of contact used",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"contact_outcome",
|
|
models.CharField(
|
|
choices=[
|
|
("SUCCESSFUL", "Successful Contact"),
|
|
("NO_ANSWER", "No Answer"),
|
|
("BUSY", "Line Busy"),
|
|
("VOICEMAIL", "Left Voicemail"),
|
|
("EMAIL_SENT", "Email Sent"),
|
|
("EMAIL_BOUNCED", "Email Bounced"),
|
|
("SMS_SENT", "SMS Sent"),
|
|
("SMS_FAILED", "SMS Failed"),
|
|
("WRONG_NUMBER", "Wrong Number"),
|
|
("DECLINED", "Patient Declined"),
|
|
],
|
|
help_text="Outcome of contact attempt",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"appointment_offered",
|
|
models.BooleanField(
|
|
default=False,
|
|
help_text="Appointment was offered during contact",
|
|
),
|
|
),
|
|
(
|
|
"offered_date",
|
|
models.DateField(
|
|
blank=True, help_text="Date of offered appointment", null=True
|
|
),
|
|
),
|
|
(
|
|
"offered_time",
|
|
models.TimeField(
|
|
blank=True, help_text="Time of offered appointment", null=True
|
|
),
|
|
),
|
|
(
|
|
"patient_response",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("ACCEPTED", "Accepted Appointment"),
|
|
("DECLINED", "Declined Appointment"),
|
|
("REQUESTED_DIFFERENT", "Requested Different Time"),
|
|
("WILL_CALL_BACK", "Will Call Back"),
|
|
("NO_LONGER_NEEDED", "No Longer Needed"),
|
|
("INSURANCE_ISSUE", "Insurance Issue"),
|
|
("NO_RESPONSE", "No Response"),
|
|
],
|
|
help_text="Patient response to contact",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"notes",
|
|
models.TextField(
|
|
blank=True, help_text="Notes from contact attempt", null=True
|
|
),
|
|
),
|
|
(
|
|
"next_contact_date",
|
|
models.DateField(
|
|
blank=True,
|
|
help_text="Scheduled date for next contact attempt",
|
|
null=True,
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Waiting List Contact Log",
|
|
"verbose_name_plural": "Waiting List Contact Logs",
|
|
"db_table": "appointments_waiting_list_contact_log",
|
|
"ordering": ["-contact_date"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="WaitingQueue",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"queue_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique queue identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
("name", models.CharField(help_text="Queue name", max_length=200)),
|
|
(
|
|
"description",
|
|
models.TextField(
|
|
blank=True, help_text="Queue description", null=True
|
|
),
|
|
),
|
|
(
|
|
"queue_type",
|
|
models.CharField(
|
|
choices=[
|
|
("PROVIDER", "Provider Queue"),
|
|
("SPECIALTY", "Specialty Queue"),
|
|
("LOCATION", "Location Queue"),
|
|
("PROCEDURE", "Procedure Queue"),
|
|
("EMERGENCY", "Emergency Queue"),
|
|
],
|
|
help_text="Type of queue",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"specialty",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Medical specialty",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"location",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Queue location",
|
|
max_length=200,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"max_queue_size",
|
|
models.PositiveIntegerField(
|
|
default=50, help_text="Maximum queue size"
|
|
),
|
|
),
|
|
(
|
|
"average_service_time_minutes",
|
|
models.PositiveIntegerField(
|
|
default=30, help_text="Average service time in minutes"
|
|
),
|
|
),
|
|
(
|
|
"priority_weights",
|
|
models.JSONField(
|
|
default=dict, help_text="Priority weights for queue ordering"
|
|
),
|
|
),
|
|
(
|
|
"is_active",
|
|
models.BooleanField(default=True, help_text="Queue is active"),
|
|
),
|
|
(
|
|
"is_accepting_patients",
|
|
models.BooleanField(
|
|
default=True, help_text="Queue is accepting new patients"
|
|
),
|
|
),
|
|
(
|
|
"operating_hours",
|
|
models.JSONField(
|
|
default=dict, help_text="Queue operating hours by day"
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
],
|
|
options={
|
|
"verbose_name": "Waiting Queue",
|
|
"verbose_name_plural": "Waiting Queues",
|
|
"db_table": "appointments_waiting_queue",
|
|
"ordering": ["name"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="AppointmentRequest",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"request_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique appointment request identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
(
|
|
"appointment_type",
|
|
models.CharField(
|
|
choices=[
|
|
("CONSULTATION", "Consultation"),
|
|
("FOLLOW_UP", "Follow-up"),
|
|
("PROCEDURE", "Procedure"),
|
|
("SURGERY", "Surgery"),
|
|
("DIAGNOSTIC", "Diagnostic"),
|
|
("THERAPY", "Therapy"),
|
|
("VACCINATION", "Vaccination"),
|
|
("SCREENING", "Screening"),
|
|
("EMERGENCY", "Emergency"),
|
|
("TELEMEDICINE", "Telemedicine"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Type of appointment",
|
|
max_length=50,
|
|
),
|
|
),
|
|
(
|
|
"specialty",
|
|
models.CharField(
|
|
choices=[
|
|
("FAMILY_MEDICINE", "Family Medicine"),
|
|
("INTERNAL_MEDICINE", "Internal Medicine"),
|
|
("PEDIATRICS", "Pediatrics"),
|
|
("CARDIOLOGY", "Cardiology"),
|
|
("DERMATOLOGY", "Dermatology"),
|
|
("ENDOCRINOLOGY", "Endocrinology"),
|
|
("GASTROENTEROLOGY", "Gastroenterology"),
|
|
("NEUROLOGY", "Neurology"),
|
|
("ONCOLOGY", "Oncology"),
|
|
("ORTHOPEDICS", "Orthopedics"),
|
|
("PSYCHIATRY", "Psychiatry"),
|
|
("RADIOLOGY", "Radiology"),
|
|
("SURGERY", "Surgery"),
|
|
("UROLOGY", "Urology"),
|
|
("GYNECOLOGY", "Gynecology"),
|
|
("OPHTHALMOLOGY", "Ophthalmology"),
|
|
("ENT", "Ear, Nose & Throat"),
|
|
("EMERGENCY", "Emergency Medicine"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Medical specialty",
|
|
max_length=100,
|
|
),
|
|
),
|
|
(
|
|
"preferred_date",
|
|
models.DateField(help_text="Patient preferred appointment date"),
|
|
),
|
|
(
|
|
"preferred_time",
|
|
models.TimeField(
|
|
blank=True,
|
|
help_text="Patient preferred appointment time",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"duration_minutes",
|
|
models.PositiveIntegerField(
|
|
default=30,
|
|
help_text="Appointment duration in minutes",
|
|
validators=[
|
|
django.core.validators.MinValueValidator(15),
|
|
django.core.validators.MaxValueValidator(480),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"flexible_scheduling",
|
|
models.BooleanField(
|
|
default=True, help_text="Patient accepts alternative times"
|
|
),
|
|
),
|
|
(
|
|
"earliest_acceptable_date",
|
|
models.DateField(
|
|
blank=True,
|
|
help_text="Earliest acceptable appointment date",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"latest_acceptable_date",
|
|
models.DateField(
|
|
blank=True,
|
|
help_text="Latest acceptable appointment date",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"acceptable_times",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=list,
|
|
help_text="Acceptable time slots (JSON array)",
|
|
),
|
|
),
|
|
(
|
|
"priority",
|
|
models.CharField(
|
|
choices=[
|
|
("ROUTINE", "Routine"),
|
|
("URGENT", "Urgent"),
|
|
("STAT", "STAT"),
|
|
("EMERGENCY", "Emergency"),
|
|
],
|
|
default="ROUTINE",
|
|
help_text="Appointment priority",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"urgency_score",
|
|
models.PositiveIntegerField(
|
|
default=1,
|
|
help_text="Urgency score (1-10, 10 being most urgent)",
|
|
validators=[
|
|
django.core.validators.MinValueValidator(1),
|
|
django.core.validators.MaxValueValidator(10),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"chief_complaint",
|
|
models.TextField(
|
|
help_text="Patient chief complaint or reason for visit"
|
|
),
|
|
),
|
|
(
|
|
"clinical_notes",
|
|
models.TextField(
|
|
blank=True, help_text="Additional clinical notes", null=True
|
|
),
|
|
),
|
|
(
|
|
"referring_provider",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Referring provider name",
|
|
max_length=200,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"insurance_verified",
|
|
models.BooleanField(
|
|
default=False, help_text="Insurance coverage verified"
|
|
),
|
|
),
|
|
(
|
|
"authorization_required",
|
|
models.BooleanField(
|
|
default=False, help_text="Prior authorization required"
|
|
),
|
|
),
|
|
(
|
|
"authorization_number",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Authorization number",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"status",
|
|
models.CharField(
|
|
choices=[
|
|
("PENDING", "Pending"),
|
|
("SCHEDULED", "Scheduled"),
|
|
("CONFIRMED", "Confirmed"),
|
|
("CHECKED_IN", "Checked In"),
|
|
("IN_PROGRESS", "In Progress"),
|
|
("COMPLETED", "Completed"),
|
|
("CANCELLED", "Cancelled"),
|
|
("NO_SHOW", "No Show"),
|
|
("RESCHEDULED", "Rescheduled"),
|
|
],
|
|
default="PENDING",
|
|
help_text="Appointment status",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"scheduled_datetime",
|
|
models.DateTimeField(
|
|
blank=True,
|
|
help_text="Scheduled appointment date and time",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"scheduled_end_datetime",
|
|
models.DateTimeField(
|
|
blank=True,
|
|
help_text="Scheduled appointment end time",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"location",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Appointment location",
|
|
max_length=200,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"room_number",
|
|
models.CharField(
|
|
blank=True, help_text="Room number", max_length=50, null=True
|
|
),
|
|
),
|
|
(
|
|
"is_telemedicine",
|
|
models.BooleanField(
|
|
default=False, help_text="Telemedicine appointment"
|
|
),
|
|
),
|
|
(
|
|
"telemedicine_platform",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("ZOOM", "Zoom"),
|
|
("TEAMS", "Microsoft Teams"),
|
|
("WEBEX", "Cisco Webex"),
|
|
("DOXY", "Doxy.me"),
|
|
("CUSTOM", "Custom Platform"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Telemedicine platform",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"meeting_url",
|
|
models.URLField(
|
|
blank=True, help_text="Telemedicine meeting URL", null=True
|
|
),
|
|
),
|
|
(
|
|
"meeting_id",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Meeting ID or room number",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"meeting_password",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Meeting password",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"checked_in_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Patient check-in time", null=True
|
|
),
|
|
),
|
|
(
|
|
"completed_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Appointment completion time", null=True
|
|
),
|
|
),
|
|
(
|
|
"actual_duration_minutes",
|
|
models.PositiveIntegerField(
|
|
blank=True, help_text="Actual appointment duration", null=True
|
|
),
|
|
),
|
|
(
|
|
"cancelled_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Cancellation timestamp", null=True
|
|
),
|
|
),
|
|
(
|
|
"cancellation_reason",
|
|
models.TextField(
|
|
blank=True, help_text="Reason for cancellation", null=True
|
|
),
|
|
),
|
|
(
|
|
"reminder_preferences",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=dict,
|
|
help_text="Reminder preferences (email, SMS, phone)",
|
|
),
|
|
),
|
|
(
|
|
"special_requirements",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Special requirements or accommodations",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"interpreter_needed",
|
|
models.BooleanField(
|
|
default=False, help_text="Interpreter services needed"
|
|
),
|
|
),
|
|
(
|
|
"interpreter_language",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Required interpreter language",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
(
|
|
"cancelled_by",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="User who cancelled appointment",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="cancelled_appointments",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"checked_in_by",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="Staff member who checked in patient",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="checked_in_appointments",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"created_by",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="User who created the appointment request",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="created_appointments",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Appointment Request",
|
|
"verbose_name_plural": "Appointment Requests",
|
|
"db_table": "appointments_appointment_request",
|
|
"ordering": ["-created_at"],
|
|
},
|
|
),
|
|
]
|