""" Intake & Screening — Pre-enrollment intake records, assessments, safety screening. """ import uuid from django.db import models from access_core.fields import EncryptedDateField class RawIngestionRecord(models.Model): SOURCE_CHOICES = [ ("healthie", "Healthie"), ("lab_feed", "Lab Feed"), ("patient_upload", "Patient Upload"), ("prom_form", "PROM Form"), ("cms_api", "CMS API"), ("polling_reconciliation", "Polling Reconciliation"), ] PROCESSING_STATUS_CHOICES = [ ("received", "Received"), ("queued", "Queued"), ("processing", "Processing"), ("normalized", "Normalized"), ("failed", "Failed"), ("dead_letter", "Dead Letter"), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) source_system = models.TextField(choices=SOURCE_CHOICES) source_record_id = models.TextField() raw_payload = models.JSONField() intake_record = models.ForeignKey( "IntakeRecord", on_delete=models.SET_NULL, null=True, blank=True, related_name="raw_ingestions", ) beneficiary = models.ForeignKey( "identity.Beneficiary", on_delete=models.SET_NULL, null=True, blank=True, related_name="beneficiary_raw_ingestions", ) webhook_signature_valid = models.BooleanField(null=True, blank=True) processing_status = models.TextField( choices=PROCESSING_STATUS_CHOICES, default="received" ) form_version = models.TextField(null=True, blank=True) ingested_at = models.DateTimeField(auto_now_add=True) def __str__(self): return ( f"{self.source_system}:{self.source_record_id} ({self.processing_status})" ) class Meta: app_label = "intake" ordering = ["-ingested_at"] constraints = [ models.UniqueConstraint( fields=["source_system", "source_record_id"], name="unique_source_record_per_system", ) ] class IntakeRecord(models.Model): SEX_CHOICES = [ ("male", "Male"), ("female", "Female"), ("other", "Other"), ("unknown", "Unknown"), ] STATUS_CHOICES = [ ("prospective", "Prospective"), ("intake_in_progress", "Intake In Progress"), ("pending_clinical_review", "Pending Clinical Review"), ("pending_cms_eligibility", "Pending CMS Eligibility"), ("pending_consent", "Pending Consent"), ("pending_alignment", "Pending Alignment"), ("active_access_beneficiary", "Active ACCESS Beneficiary"), ("rejected", "Rejected"), ("withdrawn", "Withdrawn"), ("inactive", "Inactive"), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) external_form_id = models.TextField(unique=True) first_name = models.TextField() middle_name = models.TextField(null=True, blank=True) last_name = models.TextField() dob = EncryptedDateField(null=True, blank=True) sex = models.TextField(choices=SEX_CHOICES) is_synthetic = models.BooleanField(default=True) status = models.TextField(choices=STATUS_CHOICES, default="prospective") submitted_at = models.DateTimeField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"{self.first_name} {self.last_name} ({self.status})" class Meta: app_label = "intake" ordering = ["-created_at"] class IntakeIdentifier(models.Model): IDENTIFIER_TYPE_CHOICES = [ ("email", "Email"), ("phone", "Phone"), ("address", "Address"), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) intake_record = models.ForeignKey( IntakeRecord, on_delete=models.CASCADE, related_name="identifiers" ) identifier_type = models.TextField(choices=IDENTIFIER_TYPE_CHOICES) identifier_value = models.TextField() identifier_metadata = models.JSONField(null=True, blank=True) is_primary = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): from access_core.utils import mask_identifier_value # identifier_value is PHI (email/phone/address) — never render it raw. return ( f"{self.intake_record} - {self.identifier_type}: " f"{mask_identifier_value(self.identifier_value)}" ) class Meta: app_label = "intake" constraints = [ models.UniqueConstraint( fields=["intake_record", "identifier_type"], name="unique_intake_identifier_type", ) ] class IntakeAssessment(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) intake_record = models.ForeignKey( IntakeRecord, on_delete=models.CASCADE, related_name="assessments" ) raw_ingestion = models.ForeignKey( RawIngestionRecord, on_delete=models.PROTECT, null=True, blank=True, related_name="intake_assessments", ) primary_concerns = models.TextField(null=True, blank=True) other_concerns = models.TextField(null=True, blank=True) symptom_duration = models.TextField(null=True, blank=True) primary_symptoms = models.TextField(null=True, blank=True) medical_conditions = models.TextField(null=True, blank=True) infection_immune_conditions = models.TextField(null=True, blank=True) autoimmune_conditions = models.TextField(null=True, blank=True) conditions_active = models.BooleanField(null=True, blank=True) medications = models.TextField(null=True, blank=True) medication_details = models.TextField(null=True, blank=True) medications_list = models.TextField(null=True, blank=True) allergies = models.TextField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Assessment for {self.intake_record}" class Meta: app_label = "intake" class IntakeLifestyle(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) intake_record = models.ForeignKey( IntakeRecord, on_delete=models.CASCADE, related_name="lifestyle" ) raw_ingestion = models.ForeignKey( RawIngestionRecord, on_delete=models.PROTECT, null=True, blank=True, related_name="intake_lifestyle", ) weight_lbs = models.FloatField(null=True, blank=True) waist_circumference_inches = models.FloatField(null=True, blank=True) height_inches = models.FloatField(null=True, blank=True) bmi = models.FloatField(null=True, blank=True) weight_change_6mo = models.TextField(null=True, blank=True) weight_control_patterns = models.TextField(null=True, blank=True) activity_level = models.TextField(null=True, blank=True) activity_types = models.TextField(null=True, blank=True) post_activity_response = models.TextField(null=True, blank=True) digestive_patterns = models.TextField(null=True, blank=True) diet_patterns = models.TextField(null=True, blank=True) digestive_conditions = models.TextField(null=True, blank=True) bowel_patterns = models.TextField(null=True, blank=True) urination_patterns = models.TextField(null=True, blank=True) hemorrhoids = models.TextField(null=True, blank=True) sleep_quality = models.TextField(null=True, blank=True) stress_emotional_state = models.TextField(null=True, blank=True) sweating_patterns = models.TextField(null=True, blank=True) skin_patterns = models.TextField(null=True, blank=True) skin_longterm_meds = models.TextField(null=True, blank=True) mouth_throat_ear_eye_symptoms = models.JSONField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Lifestyle for {self.intake_record}" class Meta: app_label = "intake" class IntakeFemaleHealth(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) intake_record = models.ForeignKey( IntakeRecord, on_delete=models.CASCADE, related_name="female_health" ) raw_ingestion = models.ForeignKey( RawIngestionRecord, on_delete=models.PROTECT, null=True, blank=True, related_name="female_health", ) menstrual_status = models.TextField(null=True, blank=True) menstrual_flow = models.TextField(null=True, blank=True) menstrual_blood_color = models.TextField(null=True, blank=True) menstrual_clots_cramps = models.TextField(null=True, blank=True) discharge_discomfort = models.TextField(null=True, blank=True) diagnosed_conditions = models.TextField(null=True, blank=True) free_text = models.TextField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Female health for {self.intake_record}" class Meta: app_label = "intake" class IntakeMaleHealth(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) intake_record = models.ForeignKey( IntakeRecord, on_delete=models.CASCADE, related_name="male_health" ) raw_ingestion = models.ForeignKey( RawIngestionRecord, on_delete=models.PROTECT, null=True, blank=True, related_name="male_health", ) prostate_conditions = models.TextField(null=True, blank=True) sexual_function = models.TextField(null=True, blank=True) ejaculation_concerns = models.TextField(null=True, blank=True) perineal_testicular_symptoms = models.TextField(null=True, blank=True) pelvic_surgery = models.TextField(null=True, blank=True) fertility_status = models.TextField(null=True, blank=True) free_text = models.TextField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Male health for {self.intake_record}" class Meta: app_label = "intake" class IntakeMSK(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) intake_record = models.ForeignKey( IntakeRecord, on_delete=models.CASCADE, related_name="msk" ) raw_ingestion = models.ForeignKey( RawIngestionRecord, on_delete=models.PROTECT, null=True, blank=True, related_name="msk", ) pain_locations = models.TextField(null=True, blank=True) msk_diagnoses = models.TextField(null=True, blank=True) injury_history = models.TextField(null=True, blank=True) functional_impact = models.TextField(null=True, blank=True) pain_quality = models.TextField(null=True, blank=True) pain_duration = models.TextField(null=True, blank=True) pain_severity = models.FloatField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"MSK intake for {self.intake_record}" class Meta: app_label = "intake" class SafetyScreening(models.Model): SCREENING_STATUS_CHOICES = [ ("passed", "Passed"), ("failed", "Failed"), ("flagged", "Flagged"), ("needs_review", "Needs Review"), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) intake_record = models.ForeignKey( IntakeRecord, on_delete=models.CASCADE, related_name="safety_screening" ) raw_ingestion = models.ForeignKey( RawIngestionRecord, on_delete=models.PROTECT, null=True, blank=True, related_name="safety_screening", ) safety_stop_applies = models.BooleanField(default=False) exclusion_flags = models.TextField(null=True, blank=True) screening_status = models.TextField( choices=SCREENING_STATUS_CHOICES, default="needs_review" ) free_text = models.TextField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Safety screening for {self.intake_record} ({self.screening_status})" class Meta: app_label = "intake" class ParticipationReadiness(models.Model): STATUS_CHOICES = [ ("acknowledged", "Acknowledged"), ("pending", "Pending"), ("declined", "Declined"), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) intake_record = models.OneToOneField( IntakeRecord, on_delete=models.CASCADE, related_name="participation_readiness" ) acknowledged = models.BooleanField(default=False) status = models.TextField(choices=STATUS_CHOICES, default="pending") created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Readiness for {self.intake_record} ({self.status})" class Meta: app_label = "intake" class IntakeReviewStatus(models.Model): STATUS_CHOICES = [ ("new", "New"), ("under_review", "Under Review"), ("approved", "Approved"), ("rejected", "Rejected"), ("needs_more_info", "Needs More Info"), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) intake_record = models.ForeignKey( IntakeRecord, on_delete=models.CASCADE, related_name="review_statuses" ) status = models.TextField(choices=STATUS_CHOICES, default="new") reviewed_by = models.ForeignKey( "identity.User", on_delete=models.SET_NULL, null=True, blank=True ) reviewed_at = models.DateTimeField(null=True, blank=True) notes = models.TextField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Review: {self.intake_record} ({self.status})" class Meta: app_label = "intake" class FormSubmissionEvent(models.Model): SOURCE_CHOICES = [ ("healthie", "Healthie"), ("manual", "Manual"), ] STATUS_CHOICES = [ ("submitted", "Submitted"), ("processing", "Processing"), ("normalized", "Normalized"), ("failed", "Failed"), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) intake_record = models.ForeignKey( IntakeRecord, on_delete=models.CASCADE, related_name="form_submission_events" ) raw_ingestion = models.ForeignKey( RawIngestionRecord, on_delete=models.PROTECT, null=True, blank=True ) submitted_at = models.DateTimeField(null=True, blank=True) form_version = models.TextField(null=True, blank=True) source_system = models.TextField(choices=SOURCE_CHOICES) status = models.TextField(choices=STATUS_CHOICES, default="submitted") created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Form submission: {self.intake_record} ({self.source_system})" class Meta: app_label = "intake"