예제 #1
0
class CareModelMixin(models.Model):
    care = models.CharField(
        verbose_name="Is the patient in care?",
        choices=YES_NO_UNKNOWN,
        max_length=25,
    )

    care_not_in_reason = models.CharField(verbose_name="If not in care, why?",
                                          max_length=25,
                                          null=True,
                                          blank=True)

    care_facility_location = models.CharField(
        verbose_name="Does the patient receive care in this facility",
        max_length=25,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
        help_text="Either integrated care or vertical care",
    )

    icc_since_mocca = models.CharField(
        verbose_name=("Has the patient received integrated care "
                      "since the leaving the MOCCA (orig) trial until now?"),
        max_length=25,
        choices=CARE_SINCE_MOCCA,
    )

    icc_since_mocca_comment = OtherCharField(
        verbose_name="If some interruption in integrated care, please explain")

    icc = models.CharField(
        verbose_name="Does the patient currently receive integrated care",
        max_length=25,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
        help_text="Either at this facility or elsewhere",
    )

    icc_not_in_reason = models.CharField(
        verbose_name="If not receiving integrated care, why not?",
        max_length=25,
        choices=NOT_ICC_REASONS,
        default=NOT_APPLICABLE,
    )

    care_comment = models.TextField(
        verbose_name="Additional comments relevant to this patient's care",
        null=True,
        blank=True,
    )

    class Meta:
        abstract = True
예제 #2
0
class InteDeathReportModelMixin(models.Model):

    death_location_type = models.CharField(
        verbose_name="Where did the participant die?",
        max_length=50,
        choices=DEATH_LOCATIONS,
    )

    death_location_name = models.CharField(
        verbose_name=(
            "If death occurred at hospital / clinic, please give name of the facility"
        ),
        max_length=150,
        null=True,
        blank=True,
    )

    informant_contacts = EncryptedTextField(null=True, blank=True)

    informant_relationship = models.CharField(
        max_length=50,
        choices=INFORMANT_RELATIONSHIP,
        verbose_name="Informants relationship to the participant?",
    )

    other_informant_relationship = OtherCharField()

    death_certificate = models.CharField(
        verbose_name="Is a death certificate is available?",
        max_length=15,
        choices=YES_NO,
    )

    secondary_cause_of_death = models.ForeignKey(
        CauseOfDeath,
        on_delete=models.PROTECT,
        related_name="secondary_cause_of_death",
        verbose_name="Secondary cause of death",
        help_text=(
            "Secondary cause of death in the opinion of the "
            "local study doctor and local PI"
        ),
    )

    secondary_cause_of_death_other = models.CharField(
        max_length=100,
        blank=True,
        null=True,
        verbose_name='If "Other" above, please specify',
    )

    class Meta:
        abstract = True
예제 #3
0
class OffstudyModelMixin(UniqueSubjectIdentifierFieldMixin, models.Model):
    """Model mixin for the Off-study model.

    Override in admin like this:

        def formfield_for_choice_field(self, db_field, request, **kwargs):
            if db_field.name == "offstudy_reason":
                kwargs['choices'] = OFF_STUDY_REASONS
            return super().formfield_for_choice_field(db_field, request, **kwargs)

    """

    offstudy_reason_choices = OFF_STUDY_REASONS

    offstudy_datetime = models.DateTimeField(
        verbose_name="Off-study date and time",
        validators=[datetime_not_before_study_start, datetime_not_future],
        default=get_utcnow,
    )

    offstudy_reason = models.CharField(
        verbose_name=
        "Please code the primary reason participant taken off-study",
        choices=offstudy_reason_choices,
        max_length=125,
    )

    offstudy_reason_other = OtherCharField()

    def __str__(self):
        local = timezone.localtime(self.offstudy_datetime)
        return f"{self.subject_identifier} {formatted_datetime(local)}"

    def save(self, *args, **kwargs):
        off_all_schedules_or_raise(
            subject_identifier=self.subject_identifier,
            offstudy_datetime=self.offstudy_datetime,
        )
        super().save(*args, **kwargs)

    def natural_key(self):
        return (self.subject_identifier, )

    @property
    def report_datetime(self):
        return self.offstudy_datetime

    class Meta:
        abstract = True
class MissedDosesModelMixin(models.Model):

    week2 = models.ForeignKey(Week2, on_delete=models.PROTECT)

    day_missed = models.IntegerField(verbose_name="Day missed:",
                                     choices=DAYS_MISSED)

    missed_reason = models.CharField(verbose_name="Reason:",
                                     max_length=25,
                                     blank=True,
                                     choices=REASON_DRUG_MISSED)

    missed_reason_other = OtherCharField()

    class Meta:
        abstract = True
예제 #5
0
class Week4(ClinicalAssessmentModelMixin, CrfModelMixin):

    fluconazole_dose = models.CharField(
        verbose_name="Fluconazole dose (day prior to visit)",
        max_length=25,
        choices=FLUCONAZOLE_DOSE,
    )

    fluconazole_dose_other = OtherCharField(max_length=25)

    rifampicin_started = models.CharField(
        verbose_name="Rifampicin started since last visit?",
        max_length=25,
        choices=YES_NO_ALREADY_ND,
    )

    rifampicin_start_date = models.DateField(
        verbose_name="Date Rifampicin started",
        validators=[date_not_future],
        null=True,
        blank=True,
    )

    lp_done = models.CharField(
        verbose_name="LP done?",
        max_length=5,
        choices=YES_NO,
        help_text="If yes, ensure LP CRF completed.",
    )

    other_significant_dx = models.CharField(
        verbose_name="Other significant diagnosis since last visit?",
        max_length=5,
        choices=YES_NO_NA,
    )

    on_site = CurrentSiteManager()

    objects = CrfModelManager()

    history = HistoricalRecords()

    class Meta(CrfModelMixin.Meta):
        verbose_name = "Week 4"
        verbose_name_plural = "Week 4"
예제 #6
0
class MissedDosesModelMixin(models.Model):

    study_termination_conclusion = models.ForeignKey(
        StudyTerminationConclusion, on_delete=models.PROTECT)

    day_missed = models.IntegerField(verbose_name="Day missed:",
                                     choices=DAYS_MISSED)

    missed_reason = models.CharField(verbose_name="Reason:",
                                     max_length=25,
                                     blank=True,
                                     choices=REASON_DRUG_MISSED)

    missed_reason_other = OtherCharField()

    def __str__(self):
        return (f"{self.study_termination_conclusion}: "
                f"Missed {self.get_day_missed_display()}")

    class Meta:
        abstract = True
예제 #7
0
class Microbiology(CrfModelMixin):

    urine_culture_performed = models.CharField(
        max_length=5,
        choices=YES_NO,
        help_text="only for patients with >50 white cells in urine",
    )

    urine_taken_date = models.DateField(
        validators=[date_not_before_study_start, date_not_future],
        null=True,
        blank=True)

    urine_culture_results = models.CharField(
        verbose_name="Urine culture results, if completed",
        max_length=10,
        choices=CULTURE_RESULTS,
        default=NOT_APPLICABLE,
    )

    urine_culture_organism = models.CharField(
        verbose_name="If positive, organism",
        max_length=25,
        choices=URINE_CULTURE_RESULTS_ORGANISM,
        default=NOT_APPLICABLE,
    )

    urine_culture_organism_other = OtherCharField(max_length=50,
                                                  null=True,
                                                  blank=True)

    blood_culture_performed = models.CharField(max_length=5, choices=YES_NO)

    blood_culture_results = models.CharField(
        verbose_name="Blood culture results, if completed",
        max_length=10,
        choices=CULTURE_RESULTS,
        default=NOT_APPLICABLE,
    )

    blood_taken_date = models.DateField(
        validators=[date_not_before_study_start, date_not_future],
        null=True,
        blank=True)

    day_blood_taken = models.IntegerField(
        verbose_name="If positive, study day positive culture sample taken",
        validators=[MinValueValidator(1)],
        null=True,
        blank=True,
    )

    blood_culture_organism = models.CharField(
        verbose_name="If growth positive, organism",
        max_length=50,
        choices=BLOOD_CULTURE_RESULTS_ORGANISM,
        default=NOT_APPLICABLE,
    )

    blood_culture_organism_other = OtherCharField(max_length=50,
                                                  null=True,
                                                  blank=True)

    bacteria_identified = models.CharField(
        verbose_name="If bacteria, type",
        max_length=50,
        choices=BACTERIA_TYPE,
        default=NOT_APPLICABLE,
    )

    bacteria_identified_other = OtherCharField(max_length=100,
                                               null=True,
                                               blank=True)

    sputum_afb_performed = models.CharField(
        verbose_name="AFB microscopy performed?",
        max_length=5,
        choices=YES_NO,
        help_text="Was sputum AFB done?",
    )

    sputum_afb_date = models.DateField(
        validators=[date_not_before_study_start, date_not_future],
        null=True,
        blank=True)

    sputum_results_afb = models.CharField(
        verbose_name="AFB results",
        max_length=10,
        choices=POS_NEG_NA,
        default=NOT_APPLICABLE,
    )

    sputum_performed = models.CharField(
        verbose_name="Culture performed?",
        max_length=15,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    sputum_taken_date = models.DateField(
        validators=[date_not_before_study_start, date_not_future],
        null=True,
        blank=True)

    sputum_results_culture = models.CharField(
        verbose_name="Culture results",
        max_length=10,
        choices=POS_NEG_NA,
        default=NOT_APPLICABLE,
    )

    sputum_results_positive = models.CharField(
        verbose_name="If culture is positive, please specify:",
        max_length=50,
        null=True,
        blank=True,
    )

    sputum_genexpert_performed = models.CharField(
        verbose_name="Sputum Gene-Xpert performed?",
        max_length=15,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    sputum_genexpert_date = models.DateField(
        verbose_name="Date sputum Gene-Xpert taken",
        validators=[date_not_before_study_start, date_not_future],
        null=True,
        blank=True,
    )

    sputum_result_genexpert = models.CharField(
        verbose_name="Sputum Gene-Xpert results",
        max_length=45,
        choices=SPUTUM_GENEXPERT,
        default=NOT_APPLICABLE,
    )

    tissue_biopsy_taken = models.CharField(max_length=5, choices=YES_NO)

    tissue_biopsy_results = models.CharField(
        verbose_name="If YES, results",
        max_length=10,
        choices=CULTURE_RESULTS,
        default=NOT_APPLICABLE,
    )

    biopsy_date = models.DateField(
        validators=[date_not_before_study_start, date_not_future],
        null=True,
        blank=True)

    day_biopsy_taken = models.IntegerField(
        verbose_name="If positive, Study day positive culture sample taken",
        validators=[MinValueValidator(1)],
        null=True,
        blank=True,
    )

    tissue_biopsy_organism = models.CharField(
        verbose_name="If growth positive, organism",
        max_length=50,
        choices=BIOPSY_RESULTS_ORGANISM,
        default=NOT_APPLICABLE,
    )

    tissue_biopsy_organism_other = OtherCharField(max_length=50,
                                                  null=True,
                                                  blank=True)

    histopathology_report = models.TextField(null=True, blank=True)

    csf_genexpert_performed = models.CharField(
        verbose_name="CSF Gene-Xpert performed?",
        max_length=15,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    csf_genexpert_date = models.DateField(
        verbose_name="Date CSF Gene-Xpert taken",
        validators=[date_not_before_study_start, date_not_future],
        null=True,
        blank=True,
    )

    csf_result_genexpert = models.CharField(
        verbose_name="CSF Gene-Xpert results",
        max_length=45,
        choices=SPUTUM_GENEXPERT,
        default=NOT_APPLICABLE,
    )

    on_site = CurrentSiteManager()

    objects = CrfModelManager()

    history = HistoricalRecords()

    class Meta(CrfModelMixin.Meta):
        verbose_name = "Microbiology"
        verbose_name_plural = "Microbiology"
예제 #8
0
class PatientHistory(CrfModelMixin, BaseUuidModel):

    symptoms = models.ManyToManyField(
        Symptoms, verbose_name="Do you have any of the following symptoms?"
    )

    other_symptoms = OtherCharField(null=True, blank=True)

    hiv_diagnosis_date = models.DateField(
        verbose_name="When was the diagnosis of HIV made?", null=True, blank=True
    )

    arv_initiation_date = models.DateField(
        verbose_name="Date of start of antiretroviral therapy (ART)",
        null=True,
        blank=True,
    )

    viral_load = models.IntegerField(
        verbose_name="Last viral load",
        validators=[MinValueValidator(0), MaxValueValidator(999999)],
        null=True,
        blank=True,
        help_text=COPIES_PER_MILLILITER,
    )

    viral_load_date = models.DateField(
        verbose_name="Date of last viral load", null=True, blank=True
    )

    cd4 = models.IntegerField(
        verbose_name="Last CD4",
        validators=[MinValueValidator(0), MaxValueValidator(3000)],
        null=True,
        blank=True,
        help_text=CELLS_PER_MILLIMETER_CUBED_DISPLAY,
    )

    cd4_date = models.DateField(verbose_name="Date of last CD4", null=True, blank=True)

    current_arv_regimen = models.ForeignKey(
        ArvRegimens,
        on_delete=models.PROTECT,
        related_name="current_arv_regimen",
        verbose_name=(
            "Which antiretroviral therapy regimen is the patient currently on?"
        ),
        null=True,
        blank=False,
    )

    other_current_arv_regimen = OtherCharField(null=True, blank=True)

    current_arv_regimen_start_date = models.DateField(
        verbose_name=(
            "When did the patient start this current antiretroviral therapy regimen?"
        ),
        null=True,
        blank=True,
    )

    has_previous_arv_regimen = models.CharField(
        verbose_name="Has the patient been on any previous regimen?",
        max_length=15,
        choices=YES_NO,
    )

    previous_arv_regimen = models.ForeignKey(
        ArvRegimens,
        on_delete=models.PROTECT,
        related_name="previous_arv_regimen",
        verbose_name=(
            "Which antiretroviral therapy regimen was the patient previously on?"
        ),
        null=True,
        blank=True,
    )

    other_previous_arv_regimen = OtherCharField(null=True, blank=True)

    on_oi_prophylaxis = models.CharField(
        verbose_name=(
            "Is the patient on any prophylaxis against opportunistic infections?"
        ),
        max_length=15,
        choices=YES_NO,
    )

    oi_prophylaxis = models.ManyToManyField(
        OiProphylaxis,
        verbose_name="If YES, which prophylaxis is the patient on?",
        blank=True,
    )

    other_oi_prophylaxis = OtherCharField(null=True, blank=True)

    hypertension_diagnosis = models.CharField(
        verbose_name="Has the patient been diagnosed with hypertension?",
        max_length=15,
        choices=YES_NO,
    )

    on_hypertension_treatment = models.CharField(
        verbose_name="Is the patient on treatment for hypertension?",
        max_length=15,
        choices=YES_NO,
    )

    hypertension_treatment = models.ManyToManyField(
        HypertensionMedications,
        verbose_name=(
            "What medications is the patient currently taking for hypertension?"
        ),
        blank=True,
    )

    other_hypertension_treatment = OtherCharField(
        verbose_name=mark_safe("If other medication(s), please specify ..."),
        null=True,
        blank=True,
    )

    taking_statins = models.CharField(
        verbose_name="Is the patient currently taking any statins?",
        max_length=15,
        choices=YES_NO,
    )

    current_smoker = models.CharField(
        verbose_name=mark_safe("Is the patient a <u>current</u> smoker?"),
        max_length=15,
        choices=YES_NO,
    )

    former_smoker = models.CharField(
        verbose_name=mark_safe("Is the patient a <u>previous</u> smoker?"),
        max_length=15,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    diabetes_symptoms = models.ManyToManyField(
        DiabetesSymptoms,
        verbose_name=mark_safe(
            "In the <u>past year</u>, have you had any of the following symptoms?"
        ),
    )

    other_diabetes_symptoms = OtherCharField(
        verbose_name=mark_safe(
            "If other symptom in the <u>past year</u>, please specify ..."
        ),
        null=True,
        blank=True,
    )

    diabetes_in_family = models.CharField(
        verbose_name=(
            "Has anyone in your immediate family " "ever been diagnosed with diabetes?"
        ),
        max_length=15,
        choices=YES_NO,
        help_text="Immediate family is parents, siblings, and children",
    )

    class Meta(CrfModelMixin.Meta):
        verbose_name = "Patient History"
        verbose_name_plural = "Patient History"
예제 #9
0
class FollowupExamination(CrfStatusModelMixin, CrfWithActionModelMixin,
                          edc_models.BaseUuidModel):

    action_name = FOLLOWUP_EXAMINATION_ACTION

    tracking_identifier_prefix = "FU"

    action_identifier = models.CharField(max_length=50, unique=True, null=True)

    tracking_identifier = models.CharField(max_length=30,
                                           unique=True,
                                           null=True)

    # 4a
    symptoms = models.ManyToManyField(
        Symptoms,
        related_name="symptoms",
        verbose_name=(
            "Since the participant's last appointment have they experienced "
            "any of the following symptoms"),
        help_text="either at this hospital or at a different clinic",
    )

    # 4b
    symptoms_sought_care = models.ManyToManyField(
        Symptoms,
        related_name="symptoms_sought_care",
        verbose_name=
        "Did they seek care from any health worker for these symptoms",
    )

    # 4a
    symptoms_g3 = models.ManyToManyField(
        Symptoms,
        related_name="symptoms_g3",
        verbose_name="For these symptoms, were any grade 3 events",
        help_text=("Refer to DAIDS toxicity table. "
                   "Please complete Serious Adverse Event form"),
    )
    symptoms_g3_detail = models.TextField(
        verbose_name=
        "Please provide details on any of the Grade 3 symptoms above.",
        null=True,
        blank=True,
    )

    # 4a
    symptoms_g4 = models.ManyToManyField(
        Symptoms,
        related_name="symptoms_g4",
        verbose_name="For these symptoms, were any grade 4 events",
        help_text=("Refer to DAIDS toxicity table. "
                   "Please complete Serious Adverse Event form"),
    )
    symptoms_g4_detail = models.TextField(
        verbose_name=
        "Please provide details on any of the Grade 4 symptoms above.",
        null=True,
        blank=True,
    )

    # 4c
    symptoms_detail = models.TextField(
        verbose_name="Please provide details on any of the symptoms above.",
        null=True,
        blank=True,
    )

    # 5a
    attended_clinic = models.CharField(
        verbose_name=
        ("Since the participant's last visit did they attend any other clinic or hospital "
         "for care for any reason"),
        max_length=25,
        choices=YES_NO,
        help_text=
        ("Includes other routine appointments, e.g. BP check or family planning"
         ),
    )

    # 5b
    admitted_hospital = models.CharField(
        verbose_name="If YES, were they admitted to hospital?",
        max_length=25,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    # 5c
    attended_clinic_detail = models.TextField(
        verbose_name=("If YES, attend other clinic or hospital, "
                      "please provide details of this event"),
        help_text=("If the participant was given a referral letter or "
                   "discharge summary record details here"),
        null=True,
        blank=True,
    )

    attended_clinic_sae = models.CharField(
        verbose_name=mark_safe(
            "Does the event constitute a <u>Serious Adverse Event</u>"),
        max_length=25,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
        help_text="If YES, submit a <u>Serious Adverse Event</u> Form",
    )

    # 5d
    prescribed_medication = models.CharField(
        verbose_name=("Was the participant prescribed any other medication at "
                      "this clinic or hospital visit?"),
        max_length=25,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    # 5d
    prescribed_medication_detail = models.TextField(
        verbose_name=("If YES, prescribed any other medication, "
                      "please provide details of this visit"),
        null=True,
        blank=True,
    )

    # 6a
    any_other_problems = models.CharField(
        verbose_name=(
            "Since your last visit has the participant experienced any other "
            "medical or health problems NOT listed above"),
        max_length=25,
        choices=YES_NO,
    )

    # 6a
    any_other_problems_detail = models.TextField(
        verbose_name="If YES, please provide details of the event",
        null=True,
        blank=True,
    )

    any_other_problems_sae = models.CharField(
        verbose_name="Does this event constitute an Adverse Event?",
        max_length=25,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    any_other_problems_sae_grade = models.CharField(
        verbose_name="If YES, what grade?",
        choices=GRADE34_CHOICES,
        max_length=25,
        default=NOT_APPLICABLE,
        help_text="If YES, grade 3 or 4, submit Serious Adverse Event form",
    )

    # 7a
    art_change = models.CharField(
        verbose_name=("Since the participant's last visit has there "
                      "been any change in their HIV medication?"),
        max_length=25,
        choices=YES_NO,
    )

    # 7b
    art_change_reason = models.TextField(
        verbose_name="If YES, please provide reason for change",
        null=True,
        blank=True)

    # 7c
    art_new_regimen = models.ForeignKey(
        ArvRegimens,
        on_delete=PROTECT,
        verbose_name="Please indicate new regimen",
        related_name="art_new_regimen",
        null=True,
        blank=True,
    )

    art_new_regimen_other = OtherCharField()

    abdominal_tenderness = models.CharField(
        verbose_name="Abdominal tenderness", max_length=25, choices=YES_NO)

    enlarged_liver = models.CharField(verbose_name="Enlarged liver",
                                      max_length=25,
                                      choices=YES_NO)

    jaundice = models.CharField(verbose_name="Jaundice",
                                max_length=25,
                                choices=YES_NO)

    comment = models.TextField(verbose_name=(
        "Comment on the clinical course, any other symptoms present, "
        "assessment and management plan"))

    lactic_acidosis = models.CharField(
        verbose_name="Do you think the participant has lactic acidosis?",
        max_length=25,
        choices=YES_NO,
        help_text=
        ("Classical signs of lactic acidosis include: abdominal or stomach "
         "discomfort, decreased appetite, diarrhoea, fast or shallow breathing, "
         "a general feeling of discomfort, muscle pain or cramping; and "
         "unusual sleepiness, fatigue, or weakness."),
    )

    hepatomegaly = models.CharField(
        verbose_name=
        "Do you think the participant has hepatomegaly with steatosis?",
        max_length=25,
        choices=YES_NO,
        help_text=
        ("This condition often does not have any clinical signs and symptoms, "
         "it may present with an enlarge liver on examination, and symptoms "
         "of fatigue and right upper abdominal pain. The risk of developing "
         "this condition is higher in patients who are obese and who have "
         "type 2 diabetes or metabolic syndrome"),
    )

    referral = models.CharField(
        verbose_name="Is the participant being referred",
        max_length=25,
        choices=YES_NO)

    referral_reason = models.TextField(
        verbose_name="If YES, where are they being referred to",
        null=True,
        blank=True,
        help_text=(
            "Note: remind participant that admission or discharge information "
            "will be needed at the next follow up visit."),
    )

    class Meta(CrfWithActionModelMixin.Meta, edc_models.BaseUuidModel.Meta):
        verbose_name = "Clinic follow up: Examination"
        verbose_name_plural = "Clinic follow up: Examination"
예제 #10
0
class StudyTerminationConclusion(
        NonUniqueSubjectIdentifierFieldMixin,
        BaseStudyTerminationConclusion,
        OffScheduleModelMixin,
        StudyMedicationModelMixin,
        MedAndDrugInterventionModelMixin,
        BloodTransfusionModelMixin,
        ActionModelMixin,
        TrackingModelMixin,
        BaseUuidModel,
):

    action_name = STUDY_TERMINATION_CONCLUSION_ACTION

    tracking_identifier_prefix = "ST"

    subject_identifier = models.CharField(max_length=50, unique=True)

    discharged_after_initial_admission = models.CharField(
        verbose_name="Was the patient discharged after initial admission?",
        max_length=6,
        choices=YES_NO,
    )

    initial_discharge_date = models.DateField(
        verbose_name="Date of initial discharge",
        validators=[date_not_future],
        blank=True,
        null=True,
    )

    readmission_after_initial_discharge = models.CharField(
        verbose_name="Was the patient re-admitted following initial discharge?",
        max_length=7,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    readmission_date = models.DateField(
        verbose_name="Date of readmission",
        validators=[date_not_future],
        blank=True,
        null=True,
    )

    discharged_date = models.DateField(
        verbose_name="Date discharged",
        validators=[date_not_future],
        blank=True,
        null=True,
    )

    termination_reason = models.CharField(
        verbose_name="Reason for study termination",
        max_length=75,
        choices=REASON_STUDY_TERMINATED,
        help_text=(
            "If included in error, be sure to fill in protocol deviation form."
        ),
    )

    willing_to_complete_10w = models.CharField(
        verbose_name=("Is the patient willing to complete the W10 "
                      "and W16 FU visit only?"),
        max_length=12,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    willing_to_complete_centre = models.CharField(
        verbose_name=("Is the patient willing to complete the W10"
                      "and W16 FU visit only at their new care centre?"),
        max_length=17,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    willing_to_complete_date = models.DateField(
        verbose_name="Date the 10W FU due",
        validators=[date_not_future],
        editable=False,
        null=True,
        help_text="get value from Ambition visit schedule",
    )

    protocol_exclusion_criterion = models.CharField(
        verbose_name="Late protocol exclusion met?",
        max_length=12,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    included_in_error_date = models.DateField(
        verbose_name="If included in error, date",
        validators=[date_not_future],
        blank=True,
        null=True,
    )

    included_in_error = models.TextField(
        verbose_name="If included in error, narrative:",
        max_length=300,
        blank=True,
        null=True,
    )

    rifampicin_started = models.CharField(
        verbose_name="Rifampicin started since week 4?",
        max_length=30,
        choices=YES_NO_ALREADY,
    )

    first_line_regimen = models.CharField(
        verbose_name=("ART regimen started for naive patients (or regimen"
                      " switched for those already on ARVs)"),
        max_length=75,
        choices=FIRST_ARV_REGIMEN,
        default=NOT_APPLICABLE,
    )

    first_line_regimen_other = OtherCharField()

    second_line_regimen = models.CharField(
        verbose_name="Second line / second switch ARV regimen",
        max_length=50,
        choices=SECOND_ARV_REGIMEN,
        default=NOT_APPLICABLE,
    )

    second_line_regimen_other = OtherCharField()

    arvs_switch_date = models.DateField(
        verbose_name="ARV start/switch date",
        blank=True,
        null=True,
        validators=[date_not_future],
    )

    first_line_choice = models.CharField(
        verbose_name="If first line:",
        max_length=5,
        choices=FIRST_LINE_REGIMEN,
        default=NOT_APPLICABLE,
    )

    arvs_delay_reason = models.CharField(
        verbose_name="Reason ARVs not started",
        max_length=75,
        blank=True,
        null=True)

    medicines = models.ManyToManyField(
        Day14Medication, verbose_name="Medicines on study termination day:")

    on_study_drug = models.CharField(
        verbose_name="Has the patient started 'study' drug",
        max_length=25,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    def save(self, *args, **kwargs):
        if not self.last_study_fu_date:
            self.last_study_fu_date = self.offschedule_datetime.date()
        super().save(*args, **kwargs)

    class Meta(OffScheduleModelMixin.Meta):
        verbose_name = "Study Termination/Conclusion"
        verbose_name_plural = "Study Terminations/Conclusions"
예제 #11
0
class PatientHistory(CrfModelMixin):

    symptom = models.ManyToManyField(
        Symptom,
        blank=True,
        related_name="symptoms",
        verbose_name="What are your current symptoms?",
    )

    headache_duration = models.IntegerField(
        verbose_name="If headache, how many days did it last?",
        validators=[MinValueValidator(1)],
        null=True,
        blank=True,
    )

    visual_loss_duration = models.IntegerField(
        verbose_name="If visual loss, how many days did it last?",
        validators=[MinValueValidator(1)],
        null=True,
        blank=True,
    )

    tb_history = models.CharField(
        verbose_name="Previous medical history of Tuberculosis?",
        max_length=5,
        choices=YES_NO,
    )

    tb_site = models.CharField(
        verbose_name="If YES, site of TB?",
        max_length=15,
        choices=TB_SITE,
        default=NOT_APPLICABLE,
    )

    tb_treatment = models.CharField(
        verbose_name="Are you currently taking TB treatment?",
        max_length=5,
        choices=YES_NO,
    )

    taking_rifampicin = models.CharField(
        verbose_name="If YES, are you currently also taking Rifampicin?",
        max_length=5,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    rifampicin_started_date = models.DateField(
        verbose_name="If YES, when did you first start taking Rifampicin?",
        validators=[date_not_future],
        null=True,
        blank=True,
    )

    new_hiv_diagnosis = models.CharField(
        verbose_name="Is this a new HIV diagnosis?", max_length=5, choices=YES_NO
    )

    taking_arv = models.CharField(
        verbose_name="If NO, has the patient ever been on ART?",
        max_length=5,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    # retired
    first_arv_regimen = models.CharField(
        verbose_name="If YES, which drugs were prescribed for their first ART regimen?",
        max_length=50,
        choices=FIRST_ARV_REGIMEN_RETIRED,
        default=QUESTION_RETIRED,
        editable=False,
    )

    # retired
    first_arv_regimen_other = OtherCharField(editable=False)

    # retired
    first_line_choice = models.CharField(
        verbose_name="If first line:",
        max_length=25,
        choices=FIRST_LINE_REGIMEN_RETIRED,
        default=QUESTION_RETIRED,
        editable=False,
    )

    initial_arv_date = models.DateField(
        verbose_name=mark_safe(
            "If YES, when did the patient <u>start</u> ART for the first time."
        ),
        validators=[date_not_future],
        null=True,
        blank=True,
    )

    initial_arv_date_estimated = IsDateEstimatedFieldNa(
        verbose_name="If YES, is this ART date estimated?", default=NOT_APPLICABLE
    )

    initial_arv_regimen = models.ManyToManyField(
        ArvRegimens,
        verbose_name=mark_safe(
            "If YES, which drugs were prescribed for their first ART regimen?"
        ),
        related_name="initial_arv",
    )

    initial_arv_regimen_other = OtherCharField()

    has_switched_regimen = models.CharField(
        verbose_name="Has the patient ever switched ART regimen?",
        max_length=5,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    current_arv_date = models.DateField(
        verbose_name=mark_safe(
            "If YES, when was their <u>current or most recent</u> "
            "ART regimen started?"
        ),
        validators=[date_not_future],
        null=True,
        blank=True,
    )

    current_arv_date_estimated = IsDateEstimatedFieldNa(
        verbose_name="If YES, is this ART date estimated?", default=NOT_APPLICABLE
    )

    current_arv_regimen = models.ManyToManyField(
        ArvRegimens,
        verbose_name=mark_safe(
            "If YES, what is their current or most recent ART regimen?"
        ),
        related_name="current_arv",
    )

    current_arv_regimen_other = OtherCharField()

    current_arv_is_defaulted = models.CharField(
        verbose_name=mark_safe(
            "Has the patient <u>now</u> defaulted from their ART regimen?"
        ),
        max_length=5,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
        help_text="'DEFAULTED' means no ART for at least one month.",
    )

    current_arv_defaulted_date = models.DateField(
        verbose_name=mark_safe(
            "If the patient has DEFAULTED, on what date did they default "
            "from their <u>most recent</u> ART regimen?"
        ),
        validators=[date_not_future],
        null=True,
        blank=True,
    )

    current_arv_defaulted_date_estimated = IsDateEstimatedFieldNa(
        verbose_name="If DEFAULTED, is this date estimated?", default=NOT_APPLICABLE
    )

    current_arv_is_adherent = models.CharField(
        verbose_name=mark_safe(
            "If the patient is currently on ART, are they ADHERENT to "
            "their <u>current</u> ART regimen?"
        ),
        max_length=5,
        choices=YES_NO_NA,
        default=NOT_APPLICABLE,
    )

    current_arv_tablets_missed = models.IntegerField(
        verbose_name=("If not ADHERENT, how many doses missed in the last month?"),
        validators=[MinValueValidator(0), MaxValueValidator(31)],
        null=True,
        blank=True,
    )

    current_arv_decision = models.CharField(
        verbose_name=mark_safe(
            "What decision was made at admission regarding their "
            "<u>current</u> ART regimen?"
        ),
        max_length=25,
        choices=ARV_DECISION,
        default=NOT_APPLICABLE,
    )

    # retired
    second_arv_regimen = models.CharField(
        verbose_name="Second line ARV regimen",
        max_length=50,
        choices=SECOND_ARV_REGIMEN_RETIRED,
        default=QUESTION_RETIRED,
        editable=False,
    )

    # retired
    second_arv_regimen_other = OtherCharField(editable=False)

    # retired
    patient_adherence = models.CharField(
        verbose_name="Is the patient reportedly adherent?",
        max_length=25,
        choices=YES_NO_NA_RETIRED,
        default=QUESTION_RETIRED,
        editable=False,
    )

    # retired
    last_dose = models.IntegerField(
        verbose_name=(
            "If no tablets taken this month, how many months "
            "since the last dose taken?"
        ),
        validators=[MinValueValidator(0)],
        null=True,
        blank=True,
        editable=False,
    )

    last_viral_load = models.DecimalField(
        verbose_name="Last Viral Load, if known?",
        decimal_places=3,
        max_digits=10,
        null=True,
        blank=True,
        help_text="copies/mL",
    )

    viral_load_date = models.DateField(
        verbose_name="Viral Load date",
        validators=[date_not_future],
        null=True,
        blank=True,
    )

    vl_date_estimated = IsDateEstimatedFieldNa(
        verbose_name=("Is the subject's Viral Load date estimated?"),
        default=NOT_APPLICABLE,
    )

    last_cd4 = models.IntegerField(
        verbose_name="Last CD4, if known?",
        validators=[MinValueValidator(1), MaxValueValidator(2500)],
        null=True,
        blank=True,
        help_text=mark_safe("acceptable units are mm<sup>3</sup>"),
    )

    cd4_date = models.DateField(
        verbose_name="CD4 date", validators=[date_not_future], null=True, blank=True
    )

    cd4_date_estimated = IsDateEstimatedFieldNa(
        verbose_name=("Is the subject's CD4 date estimated?"), default=NOT_APPLICABLE
    )

    temp = models.DecimalField(
        verbose_name="Temperature:",
        validators=[MinValueValidator(30), MaxValueValidator(45)],
        decimal_places=1,
        max_digits=3,
        help_text="in degrees Celcius",
    )

    heart_rate = models.IntegerField(
        verbose_name="Heart rate:",
        validators=[MinValueValidator(30), MaxValueValidator(200)],
        help_text="bpm",
    )

    sys_blood_pressure = models.IntegerField(
        verbose_name="Blood pressure: systolic",
        validators=[MinValueValidator(50), MaxValueValidator(220)],
        help_text="in mm. format SYS, e.g. 120",
    )

    dia_blood_pressure = models.IntegerField(
        verbose_name="Blood pressure: diastolic",
        validators=[MinValueValidator(20), MaxValueValidator(150)],
        help_text="in Hg. format DIA, e.g. 80",
    )

    respiratory_rate = models.IntegerField(
        verbose_name="Respiratory rate:",
        validators=[MinValueValidator(6), MaxValueValidator(50)],
        help_text="breaths/min",
    )

    weight = models.DecimalField(
        verbose_name="Weight:",
        validators=[MinValueValidator(20), MaxValueValidator(150)],
        decimal_places=1,
        max_digits=4,
        help_text="kg",
    )

    weight_determination = models.CharField(
        verbose_name="Is weight estimated or measured?",
        max_length=15,
        choices=WEIGHT_DETERMINATION,
    )

    glasgow_coma_score = models.IntegerField(
        verbose_name="Glasgow Coma Score:",
        validators=[MinValueValidator(3), MaxValueValidator(15)],
        help_text="/15",
    )

    neurological = models.ManyToManyField(Neurological, blank=True)

    neurological_other = OtherCharField(
        verbose_name='If "Other CN palsy", specify',
        max_length=250,
        blank=True,
        null=True,
    )

    focal_neurologic_deficit = models.TextField(
        verbose_name='If "Focal neurologic deficit" chosen, please specify details:',
        null=True,
        blank=True,
    )

    visual_acuity_day = models.DateField(
        verbose_name="Study day visual acuity recorded?",
        validators=[date_not_future],
        null=True,
        blank=True,
    )

    left_acuity = models.DecimalField(
        verbose_name="Visual acuity left eye:",
        decimal_places=3,
        max_digits=4,
        null=True,
        blank=True,
    )

    right_acuity = models.DecimalField(
        verbose_name="Visual acuity right eye",
        decimal_places=3,
        max_digits=4,
        null=True,
        blank=True,
    )

    ecog_score = models.CharField(
        verbose_name="ECOG Disability Score", max_length=15, choices=ECOG_SCORE
    )

    ecog_score_value = models.CharField(
        verbose_name="ECOG Score", max_length=15, choices=ECOG_SCORE
    )

    lung_exam = models.CharField(
        verbose_name="Abnormal lung exam:", max_length=5, choices=YES_NO
    )

    cryptococcal_lesions = models.CharField(
        verbose_name="Cryptococcal related skin lesions:", max_length=5, choices=YES_NO
    )

    specify_medications = models.ManyToManyField(Medication, blank=True)

    specify_medications_other = models.TextField(max_length=150, blank=True, null=True)

    previous_oi = models.CharField(
        verbose_name="Previous opportunistic infection other than TB?",
        max_length=5,
        choices=YES_NO,
    )

    on_site = CurrentSiteManager()

    objects = CrfModelManager()

    history = HistoricalRecords()

    class Meta(CrfModelMixin.Meta):
        verbose_name = "Patient's History"
        verbose_name_plural = "Patient's History"
class MedicalExpenses(CrfModelMixin):

    info_source = models.CharField(
        verbose_name="What is the main source of this information?",
        max_length=25,
        choices=PATIENT_REL,
    )

    currency = models.CharField(verbose_name="Which currency do you use?",
                                max_length=20,
                                choices=CURRENCY)

    food_spend = models.DecimalField(
        verbose_name="How much do you/your family spend on food in a week?",
        decimal_places=2,
        max_digits=15,
        null=True,
        validators=[MinValueValidator(0)],
    )

    utilities_spend = models.DecimalField(
        verbose_name=
        "How much do you/your family spent on rent and utilities a month?",
        decimal_places=2,
        max_digits=15,
        null=True,
        validators=[MinValueValidator(0)],
    )

    item_spend = models.DecimalField(
        verbose_name=
        ("How much have you spent on large items (e.g. furniture, electrical "
         "items, cars) in the last year?"),
        decimal_places=2,
        max_digits=15,
        null=True,
        validators=[MinValueValidator(0)],
    )

    subject_spent_last_4wks = models.DecimalField(
        verbose_name=("Over the last 4/10 weeks, how much have you "
                      "spent on activities relating to your health?"),
        decimal_places=2,
        max_digits=15,
        null=True,
        validators=[MinValueValidator(0)],
        help_text=(
            "On D1 record data for the four weeks prior to recruitment. "
            "On W10 record data for the ten weeks since recruitment."),
    )

    someone_spent_last_4wks = models.DecimalField(
        verbose_name=("Over the last 4/10 weeks, how much has someone else "
                      "spent on activities relating to your health?"),
        decimal_places=2,
        max_digits=15,
        null=True,
        validators=[MinValueValidator(0)],
        help_text=(
            "On D1 record data for the four weeks prior to recruitment. "
            "On W10 record data for the ten weeks since recruitment."),
    )
    total_spent_last_4wks = models.DecimalField(
        verbose_name=
        ("How much in total has been spent on your healthcare in the last 4/10 weeks?"
         ),
        decimal_places=2,
        max_digits=16,
        null=True,
        validators=[MinValueValidator(0)],
        help_text=(
            "On D1 record data for the four weeks prior to recruitment. "
            "On W10 record data for the ten weeks since recruitment."),
    )

    care_before_hospital = models.CharField(
        verbose_name=(
            "Have you received any treatment or care "
            "for your present condition, before coming to the hospital?"),
        max_length=5,
        choices=YES_NO,
        help_text="If YES, please complete medical expenses part 2",
    )

    duration_present_condition = models.IntegerField(
        verbose_name="How long have you been sick with your current condition?",
        validators=[MinValueValidator(0)],
        null=True,
        help_text="in days",
    )

    activities_missed = models.CharField(
        verbose_name=("What would you have been doing if you were not sick "
                      "with your present condition"),
        max_length=25,
        null=True,
        choices=ACTIVITIES_MISSED,
    )

    activities_missed_other = OtherCharField(max_length=25,
                                             blank=True,
                                             null=True)

    time_off_work = models.DecimalField(
        verbose_name="How much time did you take off work?",
        max_digits=4,
        decimal_places=1,
        validators=[MinValueValidator(0)],
        blank=True,
        null=True,
        help_text="in days",
    )

    carer_time_off = models.IntegerField(
        verbose_name=("How much time did a caring family member "
                      "take to accompany you to the hospital?"),
        validators=[MinValueValidator(0)],
        blank=True,
        null=True,
        help_text="in days",
    )

    loss_of_earnings = models.CharField(
        verbose_name="Did you lose earnings as a result?",
        max_length=5,
        choices=YES_NO_NA,
    )

    earnings_lost_amount = models.DecimalField(
        verbose_name="How much did you lose?",
        decimal_places=2,
        max_digits=15,
        validators=[MinValueValidator(0)],
        null=True,
        blank=True,
    )

    form_of_transport = models.CharField(
        verbose_name="Which form of transport did you take to get here today?",
        max_length=25,
        default=NOT_APPLICABLE,
        choices=TRANSPORT,
    )

    transport_fare = models.DecimalField(
        verbose_name="How much did you spend on the transport (in total)?",
        decimal_places=2,
        max_digits=15,
        validators=[MinValueValidator(0)],
        blank=True,
        null=True,
    )

    travel_time = models.CharField(
        verbose_name="How long did it take you to reach there?",
        validators=[hm_validator],
        max_length=8,
        help_text="Specify as hours:minutes (format HH:MM)",
        null=True,
        blank=True,
    )

    loans = models.CharField(
        verbose_name="Did you take out any loans to pay for your healthcare?",
        max_length=5,
        choices=YES_NO,
    )

    sold_anything = models.CharField(
        verbose_name="Did you sell anything to pay for your healthcare?",
        max_length=5,
        choices=YES_NO,
    )

    private_healthcare = models.CharField(
        verbose_name="Do you have private healthcare insurance?",
        max_length=5,
        choices=YES_NO,
    )

    healthcare_insurance = models.CharField(
        verbose_name="Did you use it to help pay for your healthcare?",
        max_length=5,
        choices=YES_NO_NA,
    )

    welfare = models.CharField(
        verbose_name="Do you receive any welfare or social service support?",
        max_length=5,
        choices=YES_NO,
    )

    on_site = CurrentSiteManager()

    objects = CrfModelManager()

    history = HistoricalRecords()

    class Meta(CrfModelMixin.Meta):
        verbose_name = "Health Economics: Medical Expenses"
        verbose_name_plural = "Health Economics: Medical Expenses"
예제 #13
0
class MedicalExpensesTwoDetail(BaseUuidModel):

    medical_expenses_two = models.ForeignKey(MedicalExpensesTwo, on_delete=PROTECT)

    location_care = models.CharField(
        verbose_name="Where did you receive treatment or care?",
        max_length=35,
        choices=LOCATION_CARE,
    )

    location_care_other = OtherCharField()

    transport_form = models.CharField(
        verbose_name="Which form of transport did you take to reach there?",
        max_length=20,
        choices=TRANSPORT,
        default=NOT_APPLICABLE,
    )

    transport_cost = models.DecimalField(
        verbose_name="How much did you spend on the transport (return)?",
        decimal_places=2,
        max_digits=15,
        validators=[MinValueValidator(0)],
        null=True,
        blank=True,
    )

    transport_duration = models.CharField(
        verbose_name="How long did it take you to reach there?",
        validators=[hm_validator],
        max_length=8,
        help_text="Specify as hours:minutes (format HH:MM)",
        null=True,
        blank=True,
    )

    care_provider = models.CharField(
        verbose_name="Who provided treatment or care during that visit?",
        max_length=35,
        choices=CARE_PROVIDER,
    )

    care_provider_other = OtherCharField(max_length=25, blank=True, null=True)

    paid_treatment = models.CharField(
        verbose_name=(
            "Did you pay for the consultation you received during that visit"
        ),
        max_length=15,
        choices=YES_NO,
    )

    paid_treatment_amount = models.DecimalField(
        verbose_name=("How much did you pay for this visit?"),
        decimal_places=2,
        max_digits=15,
        validators=[MinValueValidator(0)],
        null=True,
        blank=True,
    )

    medication_bought = models.CharField(
        verbose_name="Did you buy other medication for relief?",
        max_length=15,
        choices=YES_NO,
    )

    medication_payment = models.DecimalField(
        verbose_name="How much did you pay?",
        decimal_places=2,
        max_digits=15,
        validators=[MinValueValidator(0)],
        null=True,
        blank=True,
    )

    other_place_visited = models.CharField(
        verbose_name="Before this, did you go to another place "
        "for the treatment of the present situation?",
        max_length=15,
        choices=YES_NO,
        help_text='If YES, click "Add another Medical Expenses Part 2: Detail" below.',
    )

    objects = ModelManager()

    history = HistoricalRecords()

    def __str__(self):
        return self.medical_expenses_two.visit.subject_identifier

    def natural_key(self):
        return (self.location_care,) + self.medical_expenses_two.natural_key()

    natural_key.dependencies = ["ambition_subject.medicalexpensestwo"]

    class Meta:
        verbose_name = "Medical Expenses Part 2: Detail"
        verbose_name_plural = "Medical Expenses Part 2: Detail"
예제 #14
0
class FollowUp(ClinicalAssessmentModelMixin, CrfModelMixin):

    fluconazole_dose = models.CharField(
        verbose_name="Fluconazole dose (day prior to visit)",
        max_length=25,
        choices=FLUCONAZOLE_DOSE,
    )

    fluconazole_dose_other = OtherCharField(
        verbose_name="If other, specify dose:", max_length=25)

    rifampicin_started = models.CharField(
        verbose_name="Rifampicin started since last visit?",
        max_length=25,
        choices=YES_NO_ALREADY_ND,
    )

    rifampicin_start_date = models.DateField(
        verbose_name="Date Rifampicin started",
        validators=[date_not_future],
        null=True,
        blank=True,
    )

    days_hospitalized = models.DecimalField(
        verbose_name=("Over the ten weeks spent in the study how "
                      "many days did the patient spend in hospital?"),
        decimal_places=3,
        max_digits=5,
        null=True,
    )

    antibiotic = models.ManyToManyField(
        Antibiotic,
        blank=True,
        verbose_name="Were any of the following antibiotics given?",
    )

    antibiotic_other = models.CharField(
        verbose_name="If other antibiotics, please specify:",
        max_length=50,
        null=True,
        blank=True,
    )

    blood_transfusions = models.CharField(
        verbose_name=
        "Has the patient had any blood transfusions since week two? ",
        max_length=5,
        choices=YES_NO,
        null=True,
    )

    blood_transfusions_units = models.DecimalField(
        verbose_name="If YES, no. of units?    ",
        decimal_places=3,
        max_digits=5,
        null=True,
        blank=True,
    )

    patient_help = models.CharField(
        verbose_name=("Does the patient require help from"
                      " anybody for everyday activities? "),
        max_length=10,
        choices=YES_NO_ND,
        help_text=("For example eating, drinking, washing,"
                   " brushing teeth, going to the toilet"),
    )

    patient_problems = models.CharField(
        verbose_name=
        "Has the illness left the patient with any other problems?",
        max_length=10,
        choices=YES_NO_ND,
    )

    rankin_score = models.CharField(
        verbose_name="Modified Rankin score",
        choices=RANKIN_SCORE,
        max_length=10,
        null=True,
    )

    other_significant_dx = models.CharField(
        verbose_name="Other significant diagnosis since last visit?",
        max_length=5,
        choices=YES_NO_NA,
    )

    on_site = CurrentSiteManager()

    objects = CrfModelManager()

    history = HistoricalRecords()

    class Meta(CrfModelMixin.Meta):
        verbose_name = "Follow-up"
        verbose_name_plural = "Follow-up"
class VisitModelFieldsMixin(models.Model):

    report_datetime = models.DateTimeField(
        verbose_name="Report date and time",
        validators=[datetime_not_before_study_start, datetime_not_future],
        default=get_utcnow,
        help_text="Date and time of this report",
    )

    reason = models.CharField(
        verbose_name="What is the reason for this report?",
        max_length=25,
    )

    reason_unscheduled = models.CharField(
        verbose_name="If 'unscheduled', provide the reason for " "the unscheduled visit",
        max_length=25,
        choices=VISIT_REASON_UNSCHEDULED,
        default=NOT_APPLICABLE,
    )

    reason_unscheduled_other = OtherCharField(
        verbose_name='If the reason for the unscheduled visit is "other", specify',
        max_length=25,
        blank=True,
        null=True,
    )

    reason_missed = models.CharField(
        verbose_name="If 'missed', provide the reason for the missed visit",
        max_length=35,
        blank=True,
        null=True,
    )

    reason_missed_other = OtherCharField(
        verbose_name='If the reason for the missed visit is "other", specify',
        max_length=25,
        blank=True,
        null=True,
    )

    study_status = models.CharField(
        verbose_name="What is the participant's current study status",
        max_length=50,
        null=True,
    )

    require_crfs = models.CharField(
        max_length=10,
        verbose_name="Are scheduled data being submitted with this visit?",
        choices=YES_NO,
        default=YES,
    )

    info_source = models.CharField(
        verbose_name="What is the main source of this information?", max_length=25
    )

    info_source_other = OtherCharField(
        verbose_name='If "Other" source of information, specify'
    )

    survival_status = models.CharField(
        max_length=10,
        verbose_name="Participant's survival status",
        choices=ALIVE_DEAD_UNKNOWN,
        null=True,
        default=ALIVE,
    )

    last_alive_date = models.DateField(
        verbose_name="Date participant last known alive",
        validators=[date_not_before_study_start, date_not_future],
        null=True,
        blank=True,
    )

    comments = models.TextField(
        verbose_name=(
            "Comment if any additional pertinent information " "about the participant"
        ),
        max_length=250,
        blank=True,
        null=True,
    )

    class Meta:
        abstract = True