1373 lines
51 KiB
Python
1373 lines
51 KiB
Python
# Generated by Django 5.2.4 on 2025-08-04 04:41
|
|
|
|
import django.core.validators
|
|
import django.db.models.deletion
|
|
import django.utils.timezone
|
|
import uuid
|
|
from django.conf import settings
|
|
from django.db import migrations, models
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
initial = True
|
|
|
|
dependencies = [
|
|
("core", "0001_initial"),
|
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
]
|
|
|
|
operations = [
|
|
migrations.CreateModel(
|
|
name="ConsentTemplate",
|
|
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
|
|
),
|
|
),
|
|
(
|
|
"category",
|
|
models.CharField(
|
|
choices=[
|
|
("TREATMENT", "Treatment Consent"),
|
|
("PROCEDURE", "Procedure Consent"),
|
|
("SURGERY", "Surgical Consent"),
|
|
("ANESTHESIA", "Anesthesia Consent"),
|
|
("RESEARCH", "Research Consent"),
|
|
("PRIVACY", "Privacy Consent"),
|
|
("FINANCIAL", "Financial Consent"),
|
|
("DISCHARGE", "Discharge Consent"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Consent category",
|
|
max_length=50,
|
|
),
|
|
),
|
|
("content", models.TextField(help_text="Consent form content")),
|
|
(
|
|
"requires_signature",
|
|
models.BooleanField(
|
|
default=True, help_text="Requires patient signature"
|
|
),
|
|
),
|
|
(
|
|
"requires_witness",
|
|
models.BooleanField(
|
|
default=False, help_text="Requires witness signature"
|
|
),
|
|
),
|
|
(
|
|
"requires_guardian",
|
|
models.BooleanField(
|
|
default=False,
|
|
help_text="Requires guardian signature for minors",
|
|
),
|
|
),
|
|
(
|
|
"is_active",
|
|
models.BooleanField(default=True, help_text="Template is active"),
|
|
),
|
|
(
|
|
"version",
|
|
models.CharField(
|
|
default="1.0", help_text="Template version", max_length=20
|
|
),
|
|
),
|
|
(
|
|
"effective_date",
|
|
models.DateField(
|
|
default=django.utils.timezone.now,
|
|
help_text="Template effective date",
|
|
),
|
|
),
|
|
(
|
|
"expiry_date",
|
|
models.DateField(
|
|
blank=True, help_text="Template expiry date", null=True
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
(
|
|
"created_by",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="User who created the template",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="created_consent_templates",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"tenant",
|
|
models.ForeignKey(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="consent_templates",
|
|
to="core.tenant",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Consent Template",
|
|
"verbose_name_plural": "Consent Templates",
|
|
"db_table": "patients_consent_template",
|
|
"ordering": ["category", "name"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="PatientProfile",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"patient_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique patient identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
(
|
|
"mrn",
|
|
models.CharField(
|
|
help_text="Medical Record Number", max_length=50, unique=True
|
|
),
|
|
),
|
|
(
|
|
"first_name",
|
|
models.CharField(help_text="First name", max_length=150),
|
|
),
|
|
("last_name", models.CharField(help_text="Last name", max_length=150)),
|
|
(
|
|
"middle_name",
|
|
models.CharField(
|
|
blank=True, help_text="Middle name", max_length=150, null=True
|
|
),
|
|
),
|
|
(
|
|
"preferred_name",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Preferred name",
|
|
max_length=150,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"suffix",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Name suffix (Jr., Sr., III, etc.)",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
("date_of_birth", models.DateField(help_text="Date of birth")),
|
|
(
|
|
"gender",
|
|
models.CharField(
|
|
choices=[
|
|
("MALE", "Male"),
|
|
("FEMALE", "Female"),
|
|
("OTHER", "Other"),
|
|
("UNKNOWN", "Unknown"),
|
|
("PREFER_NOT_TO_SAY", "Prefer not to say"),
|
|
],
|
|
help_text="Gender",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"sex_assigned_at_birth",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("MALE", "Male"),
|
|
("FEMALE", "Female"),
|
|
("INTERSEX", "Intersex"),
|
|
("UNKNOWN", "Unknown"),
|
|
],
|
|
help_text="Sex assigned at birth",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"race",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("AMERICAN_INDIAN", "American Indian or Alaska Native"),
|
|
("ASIAN", "Asian"),
|
|
("BLACK", "Black or African American"),
|
|
(
|
|
"PACIFIC_ISLANDER",
|
|
"Native Hawaiian or Other Pacific Islander",
|
|
),
|
|
("WHITE", "White"),
|
|
("OTHER", "Other"),
|
|
("UNKNOWN", "Unknown"),
|
|
("DECLINED", "Patient Declined"),
|
|
],
|
|
help_text="Race",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"ethnicity",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("HISPANIC", "Hispanic or Latino"),
|
|
("NON_HISPANIC", "Not Hispanic or Latino"),
|
|
("UNKNOWN", "Unknown"),
|
|
("DECLINED", "Patient Declined"),
|
|
],
|
|
help_text="Ethnicity",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"email",
|
|
models.EmailField(
|
|
blank=True, help_text="Email address", max_length=254, null=True
|
|
),
|
|
),
|
|
(
|
|
"phone_number",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Primary phone number",
|
|
max_length=20,
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.RegexValidator(
|
|
message='Phone number must be entered in the format: "+999999999". Up to 15 digits allowed.',
|
|
regex="^\\+?1?\\d{9,15}$",
|
|
)
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"mobile_number",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Mobile phone number",
|
|
max_length=20,
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.RegexValidator(
|
|
message='Phone number must be entered in the format: "+999999999". Up to 15 digits allowed.',
|
|
regex="^\\+?1?\\d{9,15}$",
|
|
)
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"address_line_1",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Address line 1",
|
|
max_length=255,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"address_line_2",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Address line 2",
|
|
max_length=255,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"city",
|
|
models.CharField(
|
|
blank=True, help_text="City", max_length=100, null=True
|
|
),
|
|
),
|
|
(
|
|
"state",
|
|
models.CharField(
|
|
blank=True, help_text="State/Province", max_length=50, null=True
|
|
),
|
|
),
|
|
(
|
|
"zip_code",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="ZIP/Postal code",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"country",
|
|
models.CharField(
|
|
default="United States", help_text="Country", max_length=100
|
|
),
|
|
),
|
|
(
|
|
"ssn",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Social Security Number",
|
|
max_length=11,
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.RegexValidator(
|
|
message="SSN must be in format: 123-45-6789",
|
|
regex="^\\d{3}-\\d{2}-\\d{4}$",
|
|
)
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"drivers_license",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Driver's license number",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"drivers_license_state",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Driver's license state",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"marital_status",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("SINGLE", "Single"),
|
|
("MARRIED", "Married"),
|
|
("DIVORCED", "Divorced"),
|
|
("WIDOWED", "Widowed"),
|
|
("SEPARATED", "Separated"),
|
|
("DOMESTIC_PARTNER", "Domestic Partner"),
|
|
("OTHER", "Other"),
|
|
("UNKNOWN", "Unknown"),
|
|
],
|
|
help_text="Marital status",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"primary_language",
|
|
models.CharField(
|
|
default="English", help_text="Primary language", max_length=50
|
|
),
|
|
),
|
|
(
|
|
"interpreter_needed",
|
|
models.BooleanField(
|
|
default=False, help_text="Interpreter services needed"
|
|
),
|
|
),
|
|
(
|
|
"communication_preference",
|
|
models.CharField(
|
|
choices=[
|
|
("PHONE", "Phone"),
|
|
("EMAIL", "Email"),
|
|
("SMS", "SMS"),
|
|
("MAIL", "Mail"),
|
|
("PORTAL", "Patient Portal"),
|
|
],
|
|
default="PHONE",
|
|
help_text="Preferred communication method",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"employer",
|
|
models.CharField(
|
|
blank=True, help_text="Employer", max_length=200, null=True
|
|
),
|
|
),
|
|
(
|
|
"occupation",
|
|
models.CharField(
|
|
blank=True, help_text="Occupation", max_length=100, null=True
|
|
),
|
|
),
|
|
(
|
|
"primary_care_physician",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Primary care physician",
|
|
max_length=200,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"referring_physician",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Referring physician",
|
|
max_length=200,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"allergies",
|
|
models.TextField(
|
|
blank=True, help_text="Known allergies", null=True
|
|
),
|
|
),
|
|
(
|
|
"medical_alerts",
|
|
models.TextField(
|
|
blank=True, help_text="Medical alerts and warnings", null=True
|
|
),
|
|
),
|
|
(
|
|
"has_advance_directive",
|
|
models.BooleanField(
|
|
default=False, help_text="Has advance directive on file"
|
|
),
|
|
),
|
|
(
|
|
"advance_directive_type",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("LIVING_WILL", "Living Will"),
|
|
("HEALTHCARE_PROXY", "Healthcare Proxy"),
|
|
("DNR", "Do Not Resuscitate"),
|
|
("POLST", "POLST"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Type of advance directive",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"is_active",
|
|
models.BooleanField(default=True, help_text="Patient is active"),
|
|
),
|
|
(
|
|
"is_deceased",
|
|
models.BooleanField(default=False, help_text="Patient is deceased"),
|
|
),
|
|
(
|
|
"date_of_death",
|
|
models.DateField(blank=True, help_text="Date of death", null=True),
|
|
),
|
|
(
|
|
"is_vip",
|
|
models.BooleanField(
|
|
default=False,
|
|
help_text="VIP patient requiring special handling",
|
|
),
|
|
),
|
|
(
|
|
"confidential_patient",
|
|
models.BooleanField(
|
|
default=False,
|
|
help_text="Confidential patient with restricted access",
|
|
),
|
|
),
|
|
(
|
|
"registration_date",
|
|
models.DateTimeField(
|
|
auto_now_add=True, help_text="Initial registration date"
|
|
),
|
|
),
|
|
(
|
|
"photo",
|
|
models.ImageField(
|
|
blank=True,
|
|
help_text="Patient photo",
|
|
null=True,
|
|
upload_to="patient_photos/",
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
(
|
|
"last_visit_date",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Last visit date", null=True
|
|
),
|
|
),
|
|
(
|
|
"registered_by",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="User who registered the patient",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="registered_patients",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"tenant",
|
|
models.ForeignKey(
|
|
help_text="Organization tenant",
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="patients",
|
|
to="core.tenant",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Patient Profile",
|
|
"verbose_name_plural": "Patient Profiles",
|
|
"db_table": "patients_patient_profile",
|
|
"ordering": ["last_name", "first_name"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="PatientNote",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"note_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique note identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
("title", models.CharField(help_text="Note title", max_length=200)),
|
|
("content", models.TextField(help_text="Note content")),
|
|
(
|
|
"category",
|
|
models.CharField(
|
|
choices=[
|
|
("GENERAL", "General"),
|
|
("ADMINISTRATIVE", "Administrative"),
|
|
("CLINICAL", "Clinical"),
|
|
("BILLING", "Billing"),
|
|
("INSURANCE", "Insurance"),
|
|
("SOCIAL", "Social"),
|
|
("DISCHARGE", "Discharge Planning"),
|
|
("FOLLOW_UP", "Follow-up"),
|
|
("ALERT", "Alert"),
|
|
("OTHER", "Other"),
|
|
],
|
|
default="GENERAL",
|
|
help_text="Note category",
|
|
max_length=50,
|
|
),
|
|
),
|
|
(
|
|
"priority",
|
|
models.CharField(
|
|
choices=[
|
|
("LOW", "Low"),
|
|
("NORMAL", "Normal"),
|
|
("HIGH", "High"),
|
|
("URGENT", "Urgent"),
|
|
],
|
|
default="NORMAL",
|
|
help_text="Note priority",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"is_confidential",
|
|
models.BooleanField(
|
|
default=False, help_text="Note is confidential"
|
|
),
|
|
),
|
|
(
|
|
"is_alert",
|
|
models.BooleanField(default=False, help_text="Note is an alert"),
|
|
),
|
|
(
|
|
"is_active",
|
|
models.BooleanField(default=True, help_text="Note is active"),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
(
|
|
"created_by",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="User who created the note",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="created_patient_notes",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"patient",
|
|
models.ForeignKey(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="patient_notes",
|
|
to="patients.patientprofile",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Patient Note",
|
|
"verbose_name_plural": "Patient Notes",
|
|
"db_table": "patients_patient_note",
|
|
"ordering": ["-created_at"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="InsuranceInfo",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"insurance_type",
|
|
models.CharField(
|
|
choices=[
|
|
("PRIMARY", "Primary"),
|
|
("SECONDARY", "Secondary"),
|
|
("TERTIARY", "Tertiary"),
|
|
],
|
|
default="PRIMARY",
|
|
help_text="Insurance type",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"insurance_company",
|
|
models.CharField(
|
|
help_text="Insurance company name", max_length=200
|
|
),
|
|
),
|
|
(
|
|
"plan_name",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Insurance plan name",
|
|
max_length=200,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"plan_type",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("HMO", "Health Maintenance Organization"),
|
|
("PPO", "Preferred Provider Organization"),
|
|
("EPO", "Exclusive Provider Organization"),
|
|
("POS", "Point of Service"),
|
|
("HDHP", "High Deductible Health Plan"),
|
|
("MEDICARE", "Medicare"),
|
|
("MEDICAID", "Medicaid"),
|
|
("TRICARE", "TRICARE"),
|
|
("WORKERS_COMP", "Workers Compensation"),
|
|
("AUTO", "Auto Insurance"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Plan type",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"policy_number",
|
|
models.CharField(
|
|
help_text="Policy/Member ID number", max_length=100
|
|
),
|
|
),
|
|
(
|
|
"group_number",
|
|
models.CharField(
|
|
blank=True, help_text="Group number", max_length=100, null=True
|
|
),
|
|
),
|
|
(
|
|
"subscriber_name",
|
|
models.CharField(help_text="Subscriber name", max_length=200),
|
|
),
|
|
(
|
|
"subscriber_relationship",
|
|
models.CharField(
|
|
choices=[
|
|
("SELF", "Self"),
|
|
("SPOUSE", "Spouse"),
|
|
("CHILD", "Child"),
|
|
("PARENT", "Parent"),
|
|
("OTHER", "Other"),
|
|
],
|
|
default="SELF",
|
|
help_text="Relationship to subscriber",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"subscriber_dob",
|
|
models.DateField(
|
|
blank=True, help_text="Subscriber date of birth", null=True
|
|
),
|
|
),
|
|
(
|
|
"subscriber_ssn",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Subscriber Social Security Number",
|
|
max_length=11,
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.RegexValidator(
|
|
message="SSN must be in format: 123-45-6789",
|
|
regex="^\\d{3}-\\d{2}-\\d{4}$",
|
|
)
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"effective_date",
|
|
models.DateField(help_text="Coverage effective date"),
|
|
),
|
|
(
|
|
"termination_date",
|
|
models.DateField(
|
|
blank=True, help_text="Coverage termination date", null=True
|
|
),
|
|
),
|
|
(
|
|
"copay_amount",
|
|
models.DecimalField(
|
|
blank=True,
|
|
decimal_places=2,
|
|
help_text="Copay amount",
|
|
max_digits=10,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"deductible_amount",
|
|
models.DecimalField(
|
|
blank=True,
|
|
decimal_places=2,
|
|
help_text="Deductible amount",
|
|
max_digits=10,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"out_of_pocket_max",
|
|
models.DecimalField(
|
|
blank=True,
|
|
decimal_places=2,
|
|
help_text="Out of pocket maximum",
|
|
max_digits=10,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"is_verified",
|
|
models.BooleanField(
|
|
default=False, help_text="Insurance has been verified"
|
|
),
|
|
),
|
|
(
|
|
"verification_date",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Date insurance was verified", null=True
|
|
),
|
|
),
|
|
(
|
|
"requires_authorization",
|
|
models.BooleanField(
|
|
default=False, help_text="Requires prior authorization"
|
|
),
|
|
),
|
|
(
|
|
"authorization_number",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Authorization number",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"authorization_expiry",
|
|
models.DateField(
|
|
blank=True, help_text="Authorization expiry date", null=True
|
|
),
|
|
),
|
|
(
|
|
"is_active",
|
|
models.BooleanField(default=True, help_text="Insurance is active"),
|
|
),
|
|
(
|
|
"notes",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Additional notes about this insurance",
|
|
null=True,
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
(
|
|
"verified_by",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="User who verified insurance",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="verified_insurance",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"patient",
|
|
models.ForeignKey(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="insurance_info",
|
|
to="patients.patientprofile",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Insurance Information",
|
|
"verbose_name_plural": "Insurance Information",
|
|
"db_table": "patients_insurance_info",
|
|
"ordering": ["insurance_type", "insurance_company"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="EmergencyContact",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"first_name",
|
|
models.CharField(help_text="First name", max_length=150),
|
|
),
|
|
("last_name", models.CharField(help_text="Last name", max_length=150)),
|
|
(
|
|
"relationship",
|
|
models.CharField(
|
|
choices=[
|
|
("SPOUSE", "Spouse"),
|
|
("PARENT", "Parent"),
|
|
("CHILD", "Child"),
|
|
("SIBLING", "Sibling"),
|
|
("GRANDPARENT", "Grandparent"),
|
|
("GRANDCHILD", "Grandchild"),
|
|
("AUNT_UNCLE", "Aunt/Uncle"),
|
|
("COUSIN", "Cousin"),
|
|
("FRIEND", "Friend"),
|
|
("NEIGHBOR", "Neighbor"),
|
|
("CAREGIVER", "Caregiver"),
|
|
("GUARDIAN", "Guardian"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Relationship to patient",
|
|
max_length=50,
|
|
),
|
|
),
|
|
(
|
|
"phone_number",
|
|
models.CharField(
|
|
help_text="Primary phone number",
|
|
max_length=20,
|
|
validators=[
|
|
django.core.validators.RegexValidator(
|
|
message='Phone number must be entered in the format: "+999999999". Up to 15 digits allowed.',
|
|
regex="^\\+?1?\\d{9,15}$",
|
|
)
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"mobile_number",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Mobile phone number",
|
|
max_length=20,
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.RegexValidator(
|
|
message='Phone number must be entered in the format: "+999999999". Up to 15 digits allowed.',
|
|
regex="^\\+?1?\\d{9,15}$",
|
|
)
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"email",
|
|
models.EmailField(
|
|
blank=True, help_text="Email address", max_length=254, null=True
|
|
),
|
|
),
|
|
(
|
|
"address_line_1",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Address line 1",
|
|
max_length=255,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"address_line_2",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Address line 2",
|
|
max_length=255,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"city",
|
|
models.CharField(
|
|
blank=True, help_text="City", max_length=100, null=True
|
|
),
|
|
),
|
|
(
|
|
"state",
|
|
models.CharField(
|
|
blank=True, help_text="State/Province", max_length=50, null=True
|
|
),
|
|
),
|
|
(
|
|
"zip_code",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="ZIP/Postal code",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"priority",
|
|
models.PositiveIntegerField(
|
|
default=1, help_text="Contact priority (1 = highest)"
|
|
),
|
|
),
|
|
(
|
|
"is_authorized_for_medical_decisions",
|
|
models.BooleanField(
|
|
default=False, help_text="Authorized to make medical decisions"
|
|
),
|
|
),
|
|
(
|
|
"is_authorized_for_financial_decisions",
|
|
models.BooleanField(
|
|
default=False,
|
|
help_text="Authorized to make financial decisions",
|
|
),
|
|
),
|
|
(
|
|
"is_authorized_for_information",
|
|
models.BooleanField(
|
|
default=True,
|
|
help_text="Authorized to receive medical information",
|
|
),
|
|
),
|
|
(
|
|
"is_active",
|
|
models.BooleanField(default=True, help_text="Contact is active"),
|
|
),
|
|
(
|
|
"notes",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Additional notes about this contact",
|
|
null=True,
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
(
|
|
"patient",
|
|
models.ForeignKey(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="emergency_contacts",
|
|
to="patients.patientprofile",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Emergency Contact",
|
|
"verbose_name_plural": "Emergency Contacts",
|
|
"db_table": "patients_emergency_contact",
|
|
"ordering": ["priority", "last_name", "first_name"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="ConsentForm",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"consent_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique consent identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
(
|
|
"status",
|
|
models.CharField(
|
|
choices=[
|
|
("PENDING", "Pending"),
|
|
("SIGNED", "Signed"),
|
|
("DECLINED", "Declined"),
|
|
("EXPIRED", "Expired"),
|
|
("REVOKED", "Revoked"),
|
|
],
|
|
default="PENDING",
|
|
help_text="Consent status",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"patient_signature",
|
|
models.TextField(
|
|
blank=True, help_text="Patient digital signature", null=True
|
|
),
|
|
),
|
|
(
|
|
"patient_signed_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Patient signature timestamp", null=True
|
|
),
|
|
),
|
|
(
|
|
"patient_ip_address",
|
|
models.GenericIPAddressField(
|
|
blank=True,
|
|
help_text="Patient IP address when signed",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"guardian_signature",
|
|
models.TextField(
|
|
blank=True, help_text="Guardian digital signature", null=True
|
|
),
|
|
),
|
|
(
|
|
"guardian_signed_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Guardian signature timestamp", null=True
|
|
),
|
|
),
|
|
(
|
|
"guardian_name",
|
|
models.CharField(
|
|
blank=True, help_text="Guardian name", max_length=200, null=True
|
|
),
|
|
),
|
|
(
|
|
"guardian_relationship",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Guardian relationship to patient",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"witness_signature",
|
|
models.TextField(
|
|
blank=True, help_text="Witness digital signature", null=True
|
|
),
|
|
),
|
|
(
|
|
"witness_signed_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Witness signature timestamp", null=True
|
|
),
|
|
),
|
|
(
|
|
"witness_name",
|
|
models.CharField(
|
|
blank=True, help_text="Witness name", max_length=200, null=True
|
|
),
|
|
),
|
|
(
|
|
"witness_title",
|
|
models.CharField(
|
|
blank=True, help_text="Witness title", max_length=100, null=True
|
|
),
|
|
),
|
|
(
|
|
"provider_name",
|
|
models.CharField(
|
|
blank=True, help_text="Provider name", max_length=200, null=True
|
|
),
|
|
),
|
|
(
|
|
"provider_signature",
|
|
models.TextField(
|
|
blank=True, help_text="Provider digital signature", null=True
|
|
),
|
|
),
|
|
(
|
|
"provider_signed_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Provider signature timestamp", null=True
|
|
),
|
|
),
|
|
(
|
|
"effective_date",
|
|
models.DateTimeField(
|
|
default=django.utils.timezone.now,
|
|
help_text="Consent effective date",
|
|
),
|
|
),
|
|
(
|
|
"expiry_date",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Consent expiry date", null=True
|
|
),
|
|
),
|
|
(
|
|
"revoked_at",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Consent revocation timestamp", null=True
|
|
),
|
|
),
|
|
(
|
|
"revocation_reason",
|
|
models.TextField(
|
|
blank=True, help_text="Reason for revocation", null=True
|
|
),
|
|
),
|
|
(
|
|
"notes",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Additional notes about this consent",
|
|
null=True,
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
(
|
|
"created_by",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="User who created the consent form",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="created_consent_forms",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"revoked_by",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="User who revoked the consent",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="revoked_consents",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"template",
|
|
models.ForeignKey(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="consent_forms",
|
|
to="patients.consenttemplate",
|
|
),
|
|
),
|
|
(
|
|
"patient",
|
|
models.ForeignKey(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="consent_forms",
|
|
to="patients.patientprofile",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Consent Form",
|
|
"verbose_name_plural": "Consent Forms",
|
|
"db_table": "patients_consent_form",
|
|
"ordering": ["-created_at"],
|
|
},
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="consenttemplate",
|
|
index=models.Index(
|
|
fields=["tenant", "category"], name="patients_co_tenant__4ccb5c_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="consenttemplate",
|
|
index=models.Index(
|
|
fields=["is_active"], name="patients_co_is_acti_e0ed6d_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="patientprofile",
|
|
index=models.Index(
|
|
fields=["tenant", "mrn"], name="patients_pa_tenant__6d5dc5_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="patientprofile",
|
|
index=models.Index(
|
|
fields=["last_name", "first_name"],
|
|
name="patients_pa_last_na_64c318_idx",
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="patientprofile",
|
|
index=models.Index(
|
|
fields=["date_of_birth"], name="patients_pa_date_of_3c830c_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="patientprofile",
|
|
index=models.Index(fields=["ssn"], name="patients_pa_ssn_07bec5_idx"),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="patientprofile",
|
|
index=models.Index(
|
|
fields=["phone_number"], name="patients_pa_phone_n_223ced_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="patientprofile",
|
|
index=models.Index(fields=["email"], name="patients_pa_email_1660f1_idx"),
|
|
),
|
|
migrations.AlterUniqueTogether(
|
|
name="patientprofile",
|
|
unique_together={("tenant", "mrn")},
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="patientnote",
|
|
index=models.Index(
|
|
fields=["patient", "category"], name="patients_pa_patient_7df519_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="patientnote",
|
|
index=models.Index(
|
|
fields=["priority"], name="patients_pa_priorit_f3d3a2_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="patientnote",
|
|
index=models.Index(
|
|
fields=["is_alert"], name="patients_pa_is_aler_c82cb5_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="insuranceinfo",
|
|
index=models.Index(
|
|
fields=["patient", "insurance_type"],
|
|
name="patients_in_patient_9447df_idx",
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="insuranceinfo",
|
|
index=models.Index(
|
|
fields=["policy_number"], name="patients_in_policy__6f8287_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="insuranceinfo",
|
|
index=models.Index(
|
|
fields=["is_verified"], name="patients_in_is_veri_d53f1a_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="emergencycontact",
|
|
index=models.Index(
|
|
fields=["patient", "priority"], name="patients_em_patient_6496bc_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="emergencycontact",
|
|
index=models.Index(
|
|
fields=["phone_number"], name="patients_em_phone_n_8dce36_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="consentform",
|
|
index=models.Index(
|
|
fields=["patient", "status"], name="patients_co_patient_3ce0cf_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="consentform",
|
|
index=models.Index(
|
|
fields=["template"], name="patients_co_templat_af89d3_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="consentform",
|
|
index=models.Index(
|
|
fields=["consent_id"], name="patients_co_consent_4c355d_idx"
|
|
),
|
|
),
|
|
]
|