class Appointment(AppointmentModelMixin, SurveyModelMixin, BaseUuidModel): # survey schedule fields are updated when the appointment # is created by 'create_appointments'. # See `extra_create_appointment_options` on the enrollment models. household_member = models.ForeignKey(HouseholdMember, on_delete=models.PROTECT) objects = AppointmentManager() history = HistoricalRecords() def save(self, *args, **kwargs): """Update survey schedule and survey to show same survey year as household member. """ self.survey_schedule = self.household_member.survey_schedule survey_name = site_surveys.get_survey_from_field_value( self.survey).name self.survey = S(self.survey_schedule_object.field_value, survey_name=survey_name).survey_field_value super().save(*args, **kwargs) class Meta(AppointmentModelMixin.Meta): app_label = 'bcpp_subject'
class EnrollmentLoss(BaseUuidModel): """A system model auto created that captures the reason for a present BHS eligible member who passes BHS eligibility but is not participating in the BHS. """ subject_eligibility = models.OneToOneField(SubjectEligibility, on_delete=models.PROTECT) report_datetime = models.DateTimeField(verbose_name='Report date', default=get_utcnow, validators=[datetime_not_future]) reason = models.TextField( verbose_name='Reason not eligible', max_length=500, help_text='Do not include any personal identifiable information.') objects = EnrollmentLossManager() history = HistoricalRecords() def natural_key(self): return (self.subject_eligibility.natural_key(), ) class Meta: verbose_name_plural = "Enrollment Loss"
class ChildDeathReport(DeathReportModelMixin, ActionModelMixin, SiteModelMixin, SearchSlugModelMixin, BaseUuidModel): ''' A model completed by the user after an infant's death. ''' tracking_identifier_prefix = 'ID' action_name = CHILD_DEATH_REPORT_ACTION haart_relationship = models.CharField( verbose_name=('Relationship between the infant\'s death and ' 'HAART '), max_length=20, choices=RELATIONSHIP_CHOICES) trad_med_relationship = models.CharField( verbose_name=('Relationship between the infant\'s death and ' 'traditional medicine use '), max_length=20, choices=RELATIONSHIP_CHOICES) history = HistoricalRecords() class Meta: app_label = 'flourish_prn' verbose_name = 'Child Death Report'
class EnrollmentLoss(HouseholdMemberModelMixin, BaseUuidModel): """A system model auto created that captures the reason for a present BHS eligible member who passes BHS eligibility but is not participating in the BHS. """ reason = models.TextField( verbose_name='Reason not eligible', max_length=500, help_text='Do not include any personal identifiable information.') objects = MemberEntryManager() history = HistoricalRecords() def natural_key(self): return (self.report_datetime, ) + self.household_member.natural_key() natural_key.dependencies = [ 'member.householdmember', ] class Meta(HouseholdMemberModelMixin.Meta): app_label = 'member' verbose_name = 'Enrollment loss' verbose_name_plural = 'Enrollment loss'
class SubstanceUse(CrfModelMixin): alcohol = models.CharField( verbose_name="In the past month, how often did you consume alcohol?", max_length=25, choices=ALCOHOL_CHOICE, help_text="If participant does not know exactly, ask to give a best guess.", ) smoke = models.CharField( verbose_name=("Do you currently smoke any tobacco products, " "such as cigarettes, cigars, or pipes?"), max_length=25, choices=YES_NO_DWTA, help_text="", ) drug_use = models.CharField( verbose_name='Do you currently use recreational drugs', max_length=25, choices=YES_NO_DWTA, help_text="", ) history = HistoricalRecords() class Meta(CrfModelMixin.Meta): app_label = 'bcpp_subject' verbose_name = "Substance Use" verbose_name_plural = "Substance Use"
class CrfModelMixin(VisitTrackingCrfModelMixin, OffstudyMixin, RequiresConsentMixin, PreviousVisitModelMixin, ReferenceModelMixin, MyUpdatesCrfMetadataModelMixin, FormAsJSONModelMixin, BaseUuidModel): """ Base model for all scheduled models (adds key to :class:`SubjectVisit`). """ subject_visit = models.OneToOneField(SubjectVisit, on_delete=PROTECT) report_datetime = models.DateTimeField( verbose_name="Report Date", validators=[datetime_not_future, datetime_not_before_study_start], default=get_utcnow, help_text=('If reporting today, use today\'s date/time, otherwise use ' 'the date/time this information was reported.')) objects = CrfModelManager() history = HistoricalRecords() def natural_key(self): return self.subject_visit.natural_key() natural_key.dependencies = ['bcpp_subject.subjectvisit'] class Meta(VisitTrackingCrfModelMixin.Meta, RequiresConsentMixin.Meta): consent_model = 'bcpp_subject.subjectconsent' anonymous_consent_model = 'bcpp_subject.anonymousconsent' abstract = True
class ActionItemUpdate(BaseUuidModel): action_item = models.ForeignKey(ActionItem, on_delete=PROTECT) report_datetime = models.DateTimeField(default=get_utcnow) comment = models.TextField(max_length=250, null=True, blank=True) objects = ActionItemUpdateManager() history = HistoricalRecords() def __str__(self): return self.action_item.subject_identifier def natural_key(self): return self.action_item.natural_key() natural_key.dependencies = ['edc_action_item.action_item'] @property def subject_identifier(self): return self.action_item.subject_identifier @property def action_identifier(self): return self.action_item.action_identifier
class InfantDummySubjectConsent( ConsentModelMixin, SiteModelMixin, NonUniqueSubjectIdentifierFieldMixin, PersonalFieldsMixin, BaseUuidModel): """ A dummy infant model auto completed by the s. """ consent_datetime = models.DateTimeField( verbose_name='Consent date and time',) report_datetime = models.DateTimeField( null=True, editable=False) version = models.CharField( verbose_name='Consent version', max_length=10, help_text='See \'Consent Type\' for consent versions by period.', editable=False) history = HistoricalRecords() def __str__(self): return f'{self.subject_identifier} V{self.version}' def natural_key(self): return (self.subject_identifier, self.version) class Meta(ConsentModelMixin.Meta): app_label = 'td_infant' verbose_name = 'Infant Consent' unique_together = ( ('subject_identifier', 'version'))
class PreFlourishOffStudy(OffScheduleModelMixin, ActionModelMixin, BaseUuidModel): tracking_identifier_prefix = 'MO' report_datetime = models.DateTimeField( verbose_name="Report Date", validators=[datetime_not_before_study_start, datetime_not_future], default=get_utcnow, help_text=('If reporting today, use today\'s date/time, otherwise use' ' the date/time this information was reported.')) reason = models.CharField( verbose_name=('Please code the primary reason participant taken' ' off-study'), max_length=115) objects = SubjectIdentifierManager() history = HistoricalRecords() def take_off_schedule(self): pass class Meta: app_label = 'pre_flourish' verbose_name = 'Off Study' verbose_name_plural = 'Off Studies'
class Appointment(AppointmentModelMixin, SiteModelMixin, BaseUuidModel): appt_datetime = models.DateTimeField( verbose_name=('Appointment date and time'), validators=[datetime_not_before_study_start], db_index=True) site = models.ForeignKey(Site, on_delete=models.PROTECT, null=True, editable=False, related_name='appoimtment_site') on_site = CurrentSiteManager() objects = AppointmentManager() history = HistoricalRecords() def natural_key(self): return (self.subject_identifier, self.visit_schedule_name, self.schedule_name, self.visit_code, self.visit_code_sequence) natural_key.dependencies = ['sites.Site'] class Meta(AppointmentModelMixin.Meta): pass
class InfantOffSchedule(ConsentVersionModelModelMixin, OffScheduleModelMixin, BaseUuidModel): schedule_name = models.CharField(max_length=25, blank=True, null=True) on_site = CurrentSiteManager() objects = SubjectIdentifierManager() history = HistoricalRecords() def take_off_schedule(self): pass def get_consent_version(self): subject_consent_cls = django_apps.get_model( 'td_infant.infantdummysubjectconsent') subject_consent_objs = subject_consent_cls.objects.filter( subject_identifier=self.subject_identifier).order_by( '-consent_datetime') if subject_consent_objs: return subject_consent_objs.first().version else: raise ValidationError( 'Missing Infant Dummy Consent form. Cannot proceed.') class Meta: unique_together = ('subject_identifier', 'schedule_name')
class AbsentMember(MemberEntryMixin, BaseUuidModel): """A model completed by the user that indicates the reason a household member is absent for each time the RA visits. """ reason = models.CharField(verbose_name="Reason?", max_length=100, choices=REASONS_ABSENT) objects = MemberEntryManager() history = HistoricalRecords() def __str__(self): return '{} {}'.format(self.report_datetime.strftime('%Y-%m-%d'), self.reason[0:20]) def natural_key(self): return (self.report_datetime, ) + self.household_member.natural_key() natural_key.dependencies = [ 'member.householdmember', ] class Meta(MemberEntryMixin.Meta): app_label = 'member'
class HeartAttack(CrfModelMixin): """A model completed by the user to record any heart conditions in the past 12 months. """ date_heart_attack = models.DateField( verbose_name="Date of the heart disease or stroke diagnosis:", validators=[date_not_future], help_text="", ) dx_heart_attack = models.ManyToManyField( HeartDisease, verbose_name= "[Interviewer:] What is the heart disease or stroke diagnosis as recorded?", help_text=("(tick all that apply)"), ) dx_heart_attack_other = OtherCharField() history = HistoricalRecords() class Meta(CrfModelMixin.Meta): app_label = 'bcpp_subject' verbose_name = "Heart Attack or Stroke" verbose_name_plural = "Heart Attack or Stroke"
class LocatorLogEntry(BaseUuidModel): """A model completed by the user to track an RA\'s attempts to confirm a Plot. """ locator_log = models.ForeignKey( LocatorLog, on_delete=PROTECT,) report_datetime = models.DateTimeField( verbose_name="Report date", validators=[datetime_not_future], default=get_utcnow) log_status = models.CharField( verbose_name='What is the status of the locator?', max_length=25, choices=LOCATOR_LOG_STATUS) comment = EncryptedTextField( verbose_name="Comments", max_length=250, null=True, blank=True, ) date_created = models.DateField(default=timezone.now) history = HistoricalRecords() def __str__(self): return f'{self.locator_log.maternal_dataset.study_maternal_identifier} ({self.report_datetime})' class Meta: unique_together = ('locator_log', 'report_datetime') ordering = ('report_datetime', )
class HivTestReview(CrfModelMixin): """Complete this form if HivTestingHistory.has_record. """ hiv_test_date = models.DateField( verbose_name='What was the recorded date of the last HIV test?', validators=[date_not_future], help_text= ('Obtain this information from the card the participant presents to you.' ), ) recorded_hiv_result = models.CharField( verbose_name='What was the recorded HIV test result?', max_length=30, choices=POS_NEG_IND_UNKNOWN, help_text=('If the participant and written record differ, the result ' 'from the written record should be recorded.'), ) history = HistoricalRecords() class Meta(CrfModelMixin.Meta): app_label = 'bcpp_subject' verbose_name = 'HIV Test Review' verbose_name_plural = 'HIV Test Review'
class InfantDeathReport(DeathReportModelMixin, ActionModelMixin, SiteModelMixin, SearchSlugModelMixin, BaseUuidModel): ''' A model completed by the user after an infant's death. ''' tracking_identifier_prefix = 'ID' action_name = INFANT_DEATH_REPORT_ACTION study_drug_relationship = models.CharField( verbose_name=('Relationship between the infant\'s death and ' '(CTX vs Placebo) '), max_length=20, choices=RELATIONSHIP_CHOICES) infant_nvp_relationship = models.CharField( verbose_name=('Relationship between the infant\'s death and ' 'infant extended nevirapine prophylaxis '), max_length=20, choices=RELATIONSHIP_CHOICES) haart_relationship = models.CharField( verbose_name=('Relationship between the infant\'s death and ' 'HAART '), max_length=20, choices=RELATIONSHIP_CHOICES) trad_med_relationship = models.CharField( verbose_name=('Relationship between the infant\'s death and ' 'traditional medicine use '), max_length=20, choices=RELATIONSHIP_CHOICES) history = HistoricalRecords() def get_consent_version(self): subject_screening_cls = django_apps.get_model( 'td_maternal.subjectscreening') consent_version_cls = django_apps.get_model( 'td_maternal.tdconsentversion') try: subject_screening_obj = subject_screening_cls.objects.get( subject_identifier=self.subject_identifier[:-3]) except subject_screening_cls.DoesNotExist: raise ValidationError( 'Missing Subject Screening form. Please complete ' 'it before proceeding.') else: try: consent_version_obj = consent_version_cls.objects.get( screening_identifier=subject_screening_obj. screening_identifier) except consent_version_cls.DoesNotExist: raise ValidationError( 'Missing Consent Version form. Please complete ' 'it before proceeding.') return consent_version_obj.version class Meta: app_label = 'td_prn' verbose_name = 'Infant Death Report'
class HivUntested (CrfModelMixin): why_no_hiv_test = models.CharField( verbose_name=( 'If you were not tested for HIV in the 12 months prior ' 'to today, what is the main reason why not?'), max_length=55, choices=WHY_NO_HIV_TESTING_CHOICE, help_text='', ) hiv_pills = models.CharField( verbose_name=( 'Have you ever heard about treatment for ' 'HIV with pills called antiretroviral therapy or ARVs or HAART?'), max_length=25, choices=YES_NO_UNSURE, ) arvs_hiv_test = models.CharField( verbose_name=( 'Do you believe that treatment for HIV with ' 'antiretroviral therapy (or ARVs) can help HIV-positive people ' 'to live longer?'), max_length=25, choices=YES_NO_UNSURE, ) history = HistoricalRecords() class Meta(CrfModelMixin.Meta): app_label = 'bcpp_subject' verbose_name = 'HIV Untested' verbose_name_plural = 'HIV Untested'
class HouseholdComposition(CrfModelMixin): physical_add = EncryptedCharField( verbose_name="Description of physical address: ", max_length=150, blank=True, null=True, ) coordinates = models.DecimalField( verbose_name="GPS coordinates", max_digits=10, decimal_places=4, help_text=" Record coordinates of the main gate to the household", ) contact = models.CharField( verbose_name="[To the respondent] Can we contact you by telephone?", max_length=3, choices=YES_NO, ) phone_number = models.IntegerField( verbose_name= "[To the respondent] What phone numbers can we use to reach you?", help_text="", ) history = HistoricalRecords() class Meta(CrfModelMixin.Meta): app_label = 'bcpp_subject' verbose_name = "Household Composition" verbose_name_plural = "Household Composition"
class CaregiverOffSchedule(OffScheduleModelMixin, BaseUuidModel): schedule_name = models.CharField(max_length=25, blank=True, null=True) objects = SubjectIdentifierManager() on_site = CurrentSiteManager() history = HistoricalRecords() def take_off_schedule(self): pass @property def latest_consent_obj_version(self): caregiver_consent_cls = django_apps.get_model( 'flourish_caregiver.subjectconsent') subject_consents = caregiver_consent_cls.objects.filter( subject_identifier=self.subject_identifier, ) if subject_consents: latest_consent = subject_consents.latest('consent_datetime') return latest_consent.version else: raise forms.ValidationError( 'Missing Subject Consent form, cannot proceed.') def save(self, *args, **kwargs): self.consent_version = self.latest_consent_obj_version super().save(*args, **kwargs) class Meta: unique_together = ('subject_identifier', 'schedule_name')
class InPersonLog(BaseUuidModel): """A system model to track an RA\'s attempts to confirm a Plot (related). """ worklist = models.OneToOneField( WorkList, on_delete=PROTECT, ) study_maternal_identifier = models.CharField( verbose_name='Study maternal Subject Identifier', max_length=50, unique=True) report_datetime = models.DateTimeField(verbose_name="Report date", default=get_utcnow) history = HistoricalRecords() def __str__(self): return self.study_maternal_identifier class Meta: app_label = 'flourish_follow'
class Tuberculosis(CrfModelMixin): """A model completed by the user to record any diagnosis of Tuberculosis in the past 12 months.""" tb_date = models.DateField( verbose_name="Date of the diagnosis of tuberculosis:", validators=[date_not_future], help_text="", ) tb_dx = models.CharField( verbose_name= "[Interviewer:]What is the tuberculosis diagnosis as recorded?", max_length=50, choices=DX_TB_CHOICE, help_text="", ) tb_dx_other = OtherCharField(null=True, ) history = HistoricalRecords() class Meta(CrfModelMixin.Meta): app_label = 'bcpp_subject' verbose_name = "Tuberculosis" verbose_name_plural = "Tuberculosis"
class Enrollment(NonUniqueSubjectIdentifierFieldMixin, SiteModelMixin, SearchSlugModelMixin, BaseUuidModel): """ A model completed by the user for enrollment """ enrollment_identifier = models.CharField( verbose_name='Enrollment Identifier', max_length=36, blank=True, null=True, unique=True) report_datetime = models.DateTimeField( verbose_name='Report Date and Time', default=get_utcnow, validators=[datetime_not_before_study_start, datetime_not_future], help_text='Date and time of enrollment') pregnant = models.CharField( max_length=3, choices=YES_NO, verbose_name="Are you currently pregnant?", ) history = HistoricalRecords() class Meta: app_label = 'flourish_caregiver' verbose_name = "Enrollment" verbose_name_plural = "Enrollment"
class Pregnancy(PregnancyModelMixin, CrfModelMixin): """A model completed by the user for pregnant participants.""" anc_reg = models.CharField( verbose_name="Have you registered for antenatal care?", max_length=55, null=True, blank=True, choices=ANC_REG_CHOICE, help_text="", ) lnmp = models.DateField( verbose_name= "When was the first day of your last normal menstrual period?", validators=[date_not_future], help_text="", ) history = HistoricalRecords() class Meta(CrfModelMixin.Meta): app_label = 'bcpp_subject' verbose_name = "Pregnancy" verbose_name_plural = "Pregnancy"
class OnSchedulePreFlourish(OnScheduleModelMixin, BaseUuidModel): """A model used by the system. Auto-completed by enrollment model. """ subject_identifier = models.CharField( verbose_name="Subject Identifier", max_length=50) schedule_name = models.CharField(max_length=25, blank=True, null=True) on_site = CurrentSiteManager() objects = SubjectIdentifierManager() history = HistoricalRecords() def put_on_schedule(self): pass def save(self, *args, **kwargs): self.consent_version = '1' super().save(*args, **kwargs) class Meta: unique_together = ('subject_identifier', 'schedule_name')
class SubjectVisit(VisitModelMixin, ReferenceModelMixin, CreatesMetadataModelMixin, SiteModelMixin, RequiresConsentFieldsModelMixin, BaseUuidModel): """A model completed by the user that captures the covering information for the data collected for this timepoint/appointment, e.g.report_datetime. """ appointment = models.OneToOneField(Appointment, on_delete=models.PROTECT) reason = models.CharField( verbose_name='What is the reason for this visit report?', max_length=25, choices=VISIT_REASON) reason_unscheduled = models.CharField( verbose_name=( 'If \'Unscheduled\' above, provide reason for ' 'the unscheduled visit'), max_length=25, choices=VISIT_UNSCHEDULED_REASON, default=NOT_APPLICABLE) info_source = models.CharField( verbose_name='What is the main source of this information?', max_length=25, choices=INFO_SOURCE) on_site = CurrentSiteManager() objects = VisitModelManager() history = HistoricalRecords() class Meta(VisitModelMixin.Meta): pass
class Enrollment(NonUniqueSubjectIdentifierFieldMixin, SiteModelMixin, SearchSlugModelMixin, BaseUuidModel): eligibility_checklist = Eligibility screening_identifier = models.CharField( verbose_name='Screening identifier', max_length=36, unique=True, # default=None ) gender = models.CharField(verbose_name='Gender ', choices=gender, blank=False, null=False, max_length=10) citizenship = models.CharField(verbose_name='Citizen of Botswana?', choices=yes_no, null=True, blank=True, max_length=5) legally_married = models.CharField( verbose_name='Legally married to a Botswana Citizen?', choices=yes_no, null=True, blank=True, max_length=5) marriage_certificate = models.CharField( verbose_name= 'Has the participant produced marriage certificate as proof?', choices=yes_no, null=True, blank=True, max_length=5) literacy = models.CharField( verbose_name= 'Is the participant literate or illiterate ?If illiterate is there a witness available?', choices=literacy, null=True, blank=True, max_length=50) minor = models.CharField( verbose_name='If minor, is there a guardian available?', choices=yes_no, null=True, blank=True, max_length=5) history = HistoricalRecords() class Meta: app_label = 'potlakosubject' verbose_name = 'Potlako + Eligibility' verbose_name_plural = 'Potlako + Eligibility'
class SubjectReferral(SubjectReferralModelMixin, CrfModelMixin): """A model completed by the user to indicate a referral to care. """ subject_referred = models.CharField(max_length=10, choices=REFERRAL_LETTER_YES_NO_REFUSED, help_text='') referral_appt_date = models.DateTimeField( verbose_name="Referral Appointment Date", validators=[ datetime_is_future, ], help_text=("The calculated referral appointment date" " communicated to the participant. See also " "attribute 'referral_appt_comment' for when " "the participant is unsure about attending " "on this date."), null=True, editable=False) referral_appt_comment = models.CharField( verbose_name='Reason for not attending suggested appointment date', max_length=50, choices=REFERRAL_APPT_COMMENTS, default=NOT_APPLICABLE, help_text=('If subject is unsure about attending the suggested ' 'appointment date, indicate the reason.')) scheduled_appt_date = models.DateField( verbose_name=("Previously scheduled clinic " "appointment date in this community"), validators=[ date_is_future, ], help_text=("Use the IDCC date. If subject is pregnant, " "use the ANC date instead of the IDCC date." " If the subject does not have a " "scheduled appointment, leave blank"), blank=True, null=True) comment = models.CharField( verbose_name="Comment", max_length=250, blank=True, help_text=('IMPORTANT: Do not include any names ' 'or other personally identifying ' 'information in this comment')) history = HistoricalRecords() def __str__(self): return '{0}: {1} {2} {3}'.format(self.subject_visit, self.referral_code, self.referral_appt_date, self.referral_clinic) class Meta(CrfModelMixin.Meta): app_label = 'bcpp_subject'
class ResultItem(ResultItemModelMixin, BaseUuidModel): result = models.ForeignKey(Result, on_delete=PROTECT) history = HistoricalRecords() class Meta: app_label = 'edc_lab'
class LogEntry(LogEntryModelMixin, BaseUuidModel): log = models.ForeignKey(Log) history = HistoricalRecords() class Meta(LogEntryModelMixin.Meta): app_label = 'edc_call_manager'
class Log(LogModelMixin, BaseUuidModel): call = models.ForeignKey(Call) history = HistoricalRecords() class Meta(LogModelMixin.Meta): app_label = 'edc_call_manager'