示例#1
0
class RegisteredSubject(BaseUuidModel):
    subject_identifier = models.CharField(max_length=25)

    first_name = FirstnameField(null=True)

    last_name = LastnameField(verbose_name="Last name")

    gender = models.CharField(max_length=1, choices=GENDER)
示例#2
0
class ChildBirth(UniqueSubjectIdentifierFieldMixin, SiteModelMixin,
                 CryptoMixin, BaseUuidModel):
    """ A model completed by the user on the infant's birth. """

    report_datetime = models.DateTimeField(
        verbose_name="Date and Time infant enrolled",
        validators=[
            datetime_not_future,
        ])

    first_name = FirstnameField(
        max_length=25,
        verbose_name="Infant's first name",
        help_text="If infant name is unknown or not yet determined, "
        "use Baby + birth order + mother's last name, e.g. 'Baby1Malane'")

    last_name = LastnameField(
        max_length=25,
        verbose_name="Infant's last name",
        help_text="If infant name is unknown or not yet determined, "
        "use Baby + birth order + mother's last name, e.g. 'Baby1Malane'")

    initials = EncryptedCharField(validators=[
        RegexValidator(regex=r'^[A-Z]{2,3}$',
                       message=('Ensure initials consist of letters '
                                'only in upper case, no spaces.'))
    ], )

    dob = models.DateField(verbose_name='Date of Birth',
                           help_text="Must match labour and delivery report.",
                           validators=[
                               date_not_future,
                           ])

    gender = models.CharField(max_length=10, choices=GENDER_UNDETERMINED)

    def __str__(self):
        return f'{self.first_name}, {self.initials}, {self.gender}'

    @property
    def registered_subject(self):
        """Return infant registered subject.
        """
        registered_subject_cls = django_apps.get_model(
            'edc_registration.registeredsubject')
        try:
            registered_subject = registered_subject_cls.objects.get(
                subject_identifier=self.subject_identifier)
        except registered_subject_cls.DoesNotExist:
            raise ValidationError(
                f'Registered Subject is missing for {self.subject_identifier}')
        else:
            return registered_subject

    class Meta:
        app_label = 'flourish_child'
        verbose_name = "Child Birth"
示例#3
0
class PersonalFieldsMixin(CryptoMixin, models.Model):

    first_name = FirstnameField(
        null=True, blank=False)

    last_name = LastnameField(
        verbose_name="Last name",
        null=True, blank=False)

    initials = EncryptedCharField(
        validators=[RegexValidator(
            regex=r'^[A-Z]{2,3}$',
            message=('Ensure initials consist of letters '
                     'only in upper case, no spaces.'))],
        null=True, blank=False)

    dob = models.DateField(
        verbose_name="Date of birth",
        null=True,
        blank=False)

    is_dob_estimated = IsDateEstimatedField(
        verbose_name="Is date of birth estimated?",
        null=True,
        blank=False)

    gender = models.CharField(
        verbose_name="Gender",
        choices=GENDER_UNDETERMINED,
        max_length=1,
        null=True,
        blank=False)

    guardian_name = LastnameField(
        verbose_name=('Guardian\'s last and first name'),
        validators=[FullNameValidator()],
        blank=True,
        null=True,
        help_text=mark_safe(
            'Required only if participant is a minor.<BR>'
            'Format is \'LASTNAME, FIRSTNAME\'. '
            'All uppercase separated by a comma.'))

    subject_type = models.CharField(
        max_length=25)

    class Meta:
        abstract = True
示例#4
0
class InformedConsent(SiteModelMixin, BaseUuidModel):
    consent_datetime = models.DateTimeField(
        verbose_name='Consent datetime',
        default=get_utcnow,
        help_text='Date and time of consent.')

    first_name = FirstnameField(blank=False)

    last_name = LastnameField(blank=False)

    language = models.CharField(
        verbose_name='Language of consent',
        max_length=50,
        choices=settings.LANGUAGES,
        null=True,
        blank=True,
        help_text=('The language used for the consent process will '
                   'also be used during data collection.'))

    is_literate = models.CharField(
        verbose_name='Is the participant literate?',
        max_length=5,
        choices=YES_NO,
        help_text='If No provide witness name on this form and signature'
        'on the paper document')

    witness_fname = FirstnameField(
        verbose_name='Witness first name',
        max_length=5,
    )

    witness_lname = LastnameField(
        verbose_name='Witness last name',
        max_length=5,
    )

    gender = models.CharField(verbose_name="Gender",
                              choices=GENDER,
                              max_length=1)

    date_of_birth = models.DateField(verbose_name="Date of birth",
                                     validators=[
                                         date_not_future,
                                     ])

    is_estimated = IsDateEstimatedField(
        verbose_name="Is date of birth estimated?", null=True, blank=False)
    national_identity = IdentityField(
        verbose_name='Patient ID number (Omang)',
        # validators=[identity_check, ],
        unique=True)

    identity_type = models.CharField(
        verbose_name='What type of identity number is this?',
        max_length=25,
        choices=IDENTITY_TYPE)
    """"Review Questions"""

    reviewed_consent = models.CharField(
        verbose_name='I have reviewed the consent with the participant',
        max_length=3,
        choices=YES_NO,
        help_text='If no, participant is not eligible.')

    answered_all_questions = models.CharField(
        verbose_name='I have answered all questions the participant'
        ' had about the study',
        max_length=3,
        choices=YES_NO,
        help_text='If no, participant is not eligible.')

    asked_questions = models.CharField(
        verbose_name='I have asked the participant questions about'
        ' this study and the participant has demonstrated '
        'understanding',
        max_length=3,
        choices=YES_NO,
        help_text='If no, participant is not eligible.')

    have_verified = models.CharField(
        verbose_name='I have verified that the participant has'
        'signed the consent form',
        max_length=3,
        choices=YES_NO,
        help_text='If no, participant is not eligible.')

    copy_of_consent = models.CharField(
        verbose_name='I have provided the participant with a copy'
        ' of their signed informed consent',
        max_length=3,
        choices=YES_NO,
        help_text='if declined, return copy with the consent')

    class Meta:
        verbose_name = "Informed Consent"
        verbose_name_plural = "Informed Consent"
示例#5
0
class PersonalFieldsMixin(CryptoMixin, models.Model):

    first_name = FirstnameField(
        null=True,
        blank=False,
        validators=[
            RegexValidator(
                regex=r"^([A-Z]+$|[A-Z]+\ [A-Z]+)$",
                message="Ensure name consist of letters only in upper case",
            )
        ],
        help_text="Use UPPERCASE letters only.",
    )

    last_name = LastnameField(
        verbose_name="Surname",
        null=True,
        blank=False,
        validators=[
            RegexValidator(
                regex=r"^([A-Z]+$|[A-Z]+\ [A-Z]+)$",
                message="Ensure name consist of letters only in upper case",
            )
        ],
        help_text="Use UPPERCASE letters only.",
    )

    initials = EncryptedCharField(
        validators=[
            RegexValidator(
                regex=r"^[A-Z]{2,3}$",
                message=
                "Ensure initials consist of letters only in upper case, no spaces.",
            )
        ],
        null=True,
        blank=False,
    )

    dob = models.DateField(verbose_name="Date of birth",
                           null=True,
                           blank=False)

    is_dob_estimated = IsDateEstimatedField(
        verbose_name="Is date of birth estimated?", null=True, blank=False)

    gender = models.CharField(
        verbose_name="Gender",
        choices=GENDER_UNDETERMINED,
        max_length=1,
        null=True,
        blank=False,
    )

    guardian_name = LastnameField(
        verbose_name="Guardian's last and first name",
        validators=[FullNameValidator()],
        blank=True,
        null=True,
        help_text=mark_safe("Required only if participant is a minor.<BR>"
                            "Format is 'LASTNAME, FIRSTNAME'. "
                            "All uppercase separated by a comma."),
    )

    subject_type = models.CharField(max_length=25)

    class Meta:
        abstract = True
示例#6
0
class CallModelMixin(models.Model):

    subject_identifier = models.CharField(max_length=50)

    label = models.CharField(max_length=50)

    scheduled = models.DateField(default=date.today)

    repeats = models.BooleanField(default=False)

    call_datetime = models.DateTimeField(
        null=True,
        editable=False,
        help_text='last call datetime updated by call log entry')

    first_name = FirstnameField(verbose_name='First name',
                                editable=False,
                                null=True)

    initials = models.CharField(verbose_name='Initials',
                                max_length=3,
                                editable=False,
                                null=True)

    consent_datetime = models.DateTimeField(
        verbose_name="Consent date and time",
        validators=[
            datetime_not_before_study_start,
            datetime_not_future,
        ],
        help_text="From Subject Consent.",
        null=True)

    call_attempts = models.IntegerField(default=0)

    call_outcome = models.TextField(max_length=150, null=True)

    call_status = models.CharField(max_length=15,
                                   choices=((NEW_CALL, 'New'),
                                            (OPEN_CALL, 'Open'), (CLOSED,
                                                                  'Closed')),
                                   default=NEW_CALL)

    auto_closed = models.BooleanField(
        default=False,
        editable=False,
        help_text='If True call status was changed to CLOSED by EDC.')

    objects = CallManager()

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

    def __str__(self):
        return '{} {} ({}) {}'.format(self.subject_identifier, self.first_name
                                      or '??', self.initials or '??',
                                      self.get_call_status_display(),
                                      ' by EDC' if self.auto_closed else '')

    class Meta:
        unique_together = (
            'subject_identifier',
            'label',
            'scheduled',
        )
        abstract = True
示例#7
0
class SubjectLocator(UniqueSubjectIdentifierFieldMixin, SiteModelMixin,
                     SubjectContactFieldsMixin, SearchSlugModelMixin,
                     BaseUuidModel):
    """A model completed by the user to that captures participant
    locator information and permission to contact.
    """

    loc_admin = models.CharField(verbose_name='Administered by', max_length=50)

    first_name = FirstnameField(verbose_name='First Names', max_length=50)

    last_name = LastnameField(verbose_name='Surname', max_length=50)

    initials = EncryptedCharField(validators=[
        RegexValidator(regex=r'^[A-Z]{2,3}$',
                       message=('Ensure initials consist of letters '
                                'only in upper case, no spaces.'))
    ],
                                  null=True,
                                  blank=False)

    loc_date = models.DateField(
        verbose_name='Date Completed',
        default=get_utcnow,
        validators=[date_not_before_study_start, date_not_future])

    may_call = models.CharField(
        max_length=3,
        choices=YES_NO,
        verbose_name=mark_safe(
            'Has the participant given permission <b>to be contacted on this '
            'cell number</b>?'),
        blank=True,
        null=True)

    may_call_alt = models.CharField(
        max_length=3,
        choices=YES_NO,
        verbose_name=mark_safe(
            'Has the participant given permission <b>to be contacted on this '
            'cell number</b>?'),
        blank=True,
        null=True)

    subject_cell_alt_3 = EncryptedCharField(
        verbose_name='Cell number (second alternate)', blank=True, null=True)

    may_call_tel = models.CharField(
        max_length=3,
        choices=YES_NO,
        verbose_name=mark_safe(
            'Has the participant given permission <b>to be contacted on this '
            'telephone number</b>?'),
        blank=True,
        null=True)

    loc_email = models.EmailField(blank=True,
                                  null=True,
                                  help_text='If no email, write None')

    may_contact_email = models.CharField(
        max_length=3,
        choices=YES_NO_NA,
        verbose_name=mark_safe(
            'Has the participant given permission <b>to be contacted by '
            'email</b>?'),
        blank=True,
        null=True)

    loc_village = EncryptedTextField(verbose_name='Home Village',
                                     max_length=500,
                                     help_text='')

    loc_address = EncryptedTextField(
        verbose_name='Physical address with detailed description',
        max_length=500,
        blank=True,
        null=True,
        help_text='')

    may_visit_home = models.CharField(
        max_length=25,
        choices=YES_NO,
        blank=True,
        null=True,
        verbose_name=mark_safe(
            'Has the participant given permission for study '
            'staff <b>to make home visits</b> for follow-up purposes?'))

    idcc_clinic = models.CharField(verbose_name='Name of IDCC Clinic',
                                   max_length=25,
                                   blank=True,
                                   null=True)

    may_contact_idcc = models.CharField(verbose_name=(
        'Has the participant given permission to be contacted, '
        'through their IDCC clinic?, if unable to contact phone numbers'),
                                        max_length=3,
                                        choices=YES_NO_NA,
                                        blank=True,
                                        null=True)

    loc_workplace = models.CharField(verbose_name='Name of workplace',
                                     max_length=25,
                                     blank=True,
                                     null=True,
                                     help_text='(for those who are working)')

    loc_workphone = EncryptedCharField(verbose_name='Work Telephone',
                                       blank=True,
                                       null=True)

    may_contact_work = models.CharField(verbose_name=(
        'Has participant given permission to be contacted at their '
        'workplace?, if unable to contact phone numbers'),
                                        max_length=3,
                                        choices=YES_NO_NA,
                                        blank=True,
                                        null=True)

    loc_kincontact = EncryptedTextField(verbose_name=(
        'Name and contact details of next of kin or any individuals '
        'participant allows us to contact if they can\'t be reached.'
        '(can list multiple people)'),
                                        max_length=500,
                                        blank=True,
                                        null=True)

    may_contact_kin = models.CharField(verbose_name=(
        'Has participant given permission to contact anyone else?'
        ' , if unable to contact phone numbers'),
                                       max_length=3,
                                       choices=YES_NO_NA,
                                       blank=True,
                                       null=True)

    date_followup = models.DateField(verbose_name='Date of follow-up visit')

    initial_call_date = models.DateField(verbose_name='Initial call date',
                                         default=get_utcnow)

    review_locator = models.CharField(
        verbose_name=('Did you review this form with the participant to '
                      'find out if there are any updates?'),
        max_length=3,
        choices=YES_NO)

    history = HistoricalRecords()

    objects = LocatorManager()

    def __str__(self):
        return '{}'.format(self.subject_identifier)

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

    natural_key.dependencies = ['sites.Site']

    def save(self, *args, **kwargs):
        if not self.initials:
            self.initials = f'{self.first_name[:1]}{self.last_name[:1]}'
        super().save(*args, **kwargs)

    class Meta:
        app_label = 'motheo_call_manager'
        verbose_name = 'Subject Locator'
class ChildDataset(NonUniqueSubjectIdentifierFieldMixin, SiteModelMixin,
                   BaseUuidModel):

    study_child_identifier = models.CharField(
        max_length=150,
        unique=True,
        verbose_name='Study Child Subject Identifier')

    study_maternal_identifier = models.CharField(
        verbose_name="Study maternal Subject Identifier", max_length=50)

    first_name = FirstnameField(verbose_name='Firstname',
                                null=True,
                                blank=False)

    last_name = LastnameField(null=True, blank=False)

    dob = models.DateField(null=True, blank=True)

    age_today = models.DecimalField(verbose_name='Age today',
                                    decimal_places=2,
                                    max_digits=10,
                                    blank=True,
                                    null=True)

    age_calculation_date = models.DateField(
        verbose_name='Age calculation date', blank=True, null=True)

    infant_enrolldate = models.DateField(verbose_name='Infant enrollment date')

    infant_randdt = models.DateField(
        verbose_name='Date of infant randomization', blank=True, null=True)

    infant_sex = models.CharField(verbose_name='Infant gender', max_length=7)

    infant_azt_birth = models.CharField(verbose_name='Infant started AZT',
                                        max_length=15,
                                        blank=True,
                                        null=True)

    infant_azt_days = models.IntegerField(
        verbose_name='Duration of infant AZT (days)', blank=True, null=True)

    infant_azt_startdate = models.DateField(verbose_name='AZT start date',
                                            blank=True,
                                            null=True)

    infant_azt_stopdate = models.DateField(verbose_name='AZT stop date',
                                           blank=True,
                                           null=True)

    infant_sdnvp_birth = models.CharField(verbose_name='Infant received sdNVP',
                                          max_length=15,
                                          null=True)

    infant_hiv_exposed = models.CharField(
        verbose_name='Infant HIV exposure status', max_length=150)

    infant_hiv_status = models.CharField(
        verbose_name='Infant HIV infection status', max_length=150)

    infant_breastfed = models.CharField(verbose_name='Infant breastfed',
                                        max_length=150,
                                        blank=True,
                                        null=True)

    infant_breastfed_days = models.IntegerField(
        verbose_name='Breastfeeding duration (days)', blank=True, null=True)

    weaned = models.CharField(verbose_name='Weaning indicator',
                              max_length=150,
                              blank=True,
                              null=True)

    weandt = models.DateField(verbose_name='Weaning date',
                              blank=True,
                              null=True)

    weancat = models.CharField(verbose_name='Weaning by category',
                               max_length=150,
                               blank=True,
                               null=True)

    birthweight = models.DecimalField(verbose_name='Birth weight (kg)',
                                      decimal_places=2,
                                      max_digits=10,
                                      blank=True,
                                      null=True)

    birthwtcat = models.CharField(verbose_name='Birth weight (kg) by category',
                                  max_length=150,
                                  blank=True,
                                  null=True)

    height_0 = models.DecimalField(verbose_name='Height (cm) at delivery',
                                   decimal_places=2,
                                   max_digits=10,
                                   blank=True,
                                   null=True)

    headcirc_0 = models.DecimalField(
        verbose_name='Head circumference (cm) at delivery',
        decimal_places=2,
        max_digits=10,
        blank=True,
        null=True)

    apgarscore_1min = models.IntegerField(verbose_name='APGAR score at 1min',
                                          blank=True,
                                          null=True)

    apgarscore_5min = models.IntegerField(verbose_name='APGAR score at 5min',
                                          blank=True,
                                          null=True)

    apgarscore_10min = models.IntegerField(verbose_name='APGAR score at 10min',
                                           blank=True,
                                           null=True)

    low_birthweight = models.CharField(
        verbose_name='Infant born low birth weight',
        max_length=150,
        blank=True,
        null=True)

    infant_premature = models.CharField(
        verbose_name='Infant born premature (<37 weeks)',
        max_length=150,
        blank=True,
        null=True)

    height_6mo = models.DecimalField(verbose_name='Height (cm) at 6 months',
                                     decimal_places=2,
                                     max_digits=10,
                                     blank=True,
                                     null=True)

    height_18mo = models.DecimalField(verbose_name='Height (cm) at 18 months',
                                      decimal_places=2,
                                      max_digits=10,
                                      blank=True,
                                      null=True)

    height_24mo = models.DecimalField(verbose_name='Height (cm) at 24 months',
                                      decimal_places=2,
                                      max_digits=10,
                                      blank=True,
                                      null=True)

    headcirc_18mo = models.DecimalField(
        verbose_name='Head circumference (cm) at 18 months',
        decimal_places=2,
        max_digits=10,
        blank=True,
        null=True)

    headcirc_24mo = models.DecimalField(
        verbose_name='Head circumference (cm) at 24 months',
        decimal_places=2,
        max_digits=10,
        blank=True,
        null=True)

    weight_18mo = models.DecimalField(verbose_name='Weight (kg) at 18 months',
                                      decimal_places=2,
                                      max_digits=10,
                                      blank=True,
                                      null=True)

    weight_24mo = models.DecimalField(verbose_name='Weight (kg) at 18 months',
                                      decimal_places=2,
                                      max_digits=10,
                                      blank=True,
                                      null=True)

    infant_vitalstatus_final = models.CharField(
        verbose_name='Final infant vital status', max_length=150)

    deathdt = models.DateField(verbose_name='Death date',
                               blank=True,
                               null=True)

    deathcause = models.CharField(verbose_name='Cause of death',
                                  max_length=150,
                                  blank=True,
                                  null=True)

    firsthospdt = models.DateField(
        verbose_name='Date of first hospitalization', blank=True, null=True)

    hospnum = models.IntegerField(verbose_name='Number of times hospitalized',
                                  blank=True,
                                  null=True)

    idth = models.IntegerField(
        verbose_name='Infant death indicator (0= censored)',
        blank=True,
        null=True)

    idth_days = models.IntegerField(
        verbose_name='Days from infant birth to death (censored)',
        blank=True,
        null=True)

    ihiv = models.IntegerField(
        verbose_name='Indicator of HIV endpoint (0=censored)',
        blank=True,
        null=True)

    ihiv_days = models.IntegerField(
        verbose_name='Time to HIV endpoint (days from birth)',
        blank=True,
        null=True)

    ihosp = models.IntegerField(
        verbose_name='Infant hospitalization indicator (0= censored)',
        blank=True,
        null=True)

    ihosp_days = models.IntegerField(
        verbose_name=
        'Days from infant birth to first hospitalization (censored)',
        blank=True,
        null=True)

    infantvacc_bcg = models.CharField(verbose_name='BCG vaccine received?',
                                      max_length=150,
                                      blank=True,
                                      null=True)

    infantvacc_dtap = models.CharField(verbose_name='DTAP vaccine received?',
                                       max_length=150,
                                       blank=True,
                                       null=True)

    infantvacc_hbv = models.CharField(verbose_name='HBV vaccine received?',
                                      max_length=150,
                                      blank=True,
                                      null=True)

    infantvacc_hiv = models.CharField(verbose_name='HIV vaccine received?',
                                      max_length=150,
                                      blank=True,
                                      null=True)

    infantvacc_measles = models.CharField(
        verbose_name='Measles vaccine received?',
        max_length=150,
        blank=True,
        null=True)

    infantvacc_mmr = models.CharField(verbose_name='MMR vaccine received?',
                                      max_length=150,
                                      blank=True,
                                      null=True)

    infantvacc_pneum = models.CharField(
        verbose_name='Pneumoccal vaccine received?',
        max_length=150,
        blank=True,
        null=True)

    infantvacc_polio = models.CharField(verbose_name='Polio vaccine received?',
                                        max_length=150,
                                        blank=True,
                                        null=True)

    infantvacc_rota = models.CharField(
        verbose_name='Rotavirus vaccine received?',
        max_length=150,
        blank=True,
        null=True)

    infant_offstudydate = models.DateField(blank=True, null=True)

    infant_lastcontactdt = models.DateField(blank=True, null=True)

    infant_onstudy_days = models.IntegerField(blank=True, null=True)

    infant_offstudy_reason = models.CharField(
        verbose_name='Days infant on-study', max_length=200)

    curr_age = models.DecimalField(verbose_name='Current Age',
                                   decimal_places=2,
                                   max_digits=10,
                                   blank=True,
                                   null=True)

    age_gt17_5 = models.IntegerField(verbose_name='Age greater than 17.5')

    infant_offstudy_complete = models.IntegerField(
        verbose_name='Infant Offstudy Complete')

    # today = models.DateField(
    #     blank=True, null=True)

    offstrs = models.CharField(verbose_name='Offstrs',
                               max_length=150,
                               blank=True,
                               null=True)

    offstcd = models.CharField(verbose_name='Offstcd',
                               max_length=50,
                               blank=True,
                               null=True)

    twin_triplet = models.BooleanField(default=False, editable=False)

    class Meta:
        app_label = 'flourish_child'
        verbose_name = 'Infant Dataset'
class CaregiverChildConsent(SiteModelMixin, NonUniqueSubjectIdentifierFieldMixin,
                            IdentityFieldsMixin, ReviewFieldsMixin,
                            PersonalFieldsMixin, VerificationFieldsMixin, BaseUuidModel):

    """Inline table for caregiver's children"""

    subject_consent = models.ForeignKey(
        SubjectConsent,
        on_delete=models.PROTECT)

    subject_identifier = models.CharField(
        verbose_name="Subject Identifier",
        max_length=50)

    first_name = FirstnameField(
        null=True, blank=True)

    last_name = LastnameField(
        verbose_name="Last name",
        null=True, blank=True)

    study_child_identifier = models.CharField(
        verbose_name='Previous study identifier',
        max_length=50,
        null=True,
        blank=True)

    gender = models.CharField(
        verbose_name="Gender",
        choices=GENDER,
        max_length=1,
        null=True,
        blank=True)

    identity = IdentityField(
        verbose_name='Identity number',
        null=True,
        blank=True)

    identity_type = models.CharField(
        verbose_name='What type of identity number is this?',
        max_length=25,
        choices=CHILD_IDENTITY_TYPE,
        null=True,
        blank=True)

    confirm_identity = IdentityField(
        help_text='Retype the identity number',
        null=True,
        blank=True)

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

    child_test = models.CharField(
        verbose_name='Will you allow for HIV testing and counselling of '
                     'your Child',
        max_length=5,
        choices=YES_NO,
        help_text='If no, participant is not eligible.')

    child_remain_in_study = models.CharField(
        verbose_name='Is your child willing to remain in the study area until '
                     '2025?',
        max_length=5,
        choices=YES_NO,
        help_text='If no, participant is not eligible.')

    child_preg_test = models.CharField(
        verbose_name='If your child is female and will be 12 years or older '
                     'prior to 30-Jun-2025, will you allow the female child '
                     'to undergo pregnancy testing?',
        max_length=5,
        choices=YES_NO_NA,
        help_text='If no, participant is not eligible.')

    child_knows_status = models.CharField(
        verbose_name='If your child is ≥ 16 years, have they been told about '
                     'your HIV?',
        max_length=5,
        choices=YES_NO_NA,
        help_text='If no, participant is not eligible.')

    future_studies_contact = models.CharField(
        verbose_name=('Do you give us permission for us to contact you or your child'
                      ' for future studies?'),
        max_length=3,
        choices=YES_NO,)

    specimen_consent = models.CharField(
        verbose_name=('Do you give us permission for us to use your child\'s blood '
                      'samples for future studies?'),
        max_length=3,
        choices=YES_NO,)

    child_age_at_enrollment = models.DecimalField(
        decimal_places=2,
        max_digits=4)

    consent_datetime = models.DateTimeField(
        verbose_name='Consent date and time',
        validators=[
            datetime_not_before_study_start,
            datetime_not_future])

    version = models.CharField(
        verbose_name='Consent version',
        max_length=4,
        choices=CHILD_CONSENT_VERSION,
        blank=True)

    cohort = models.CharField(
        max_length=12,
        choices=COHORTS,
        blank=True,
        null=True)

    caregiver_visit_count = models.IntegerField(
        validators=[MinValueValidator(1), MaxValueValidator(3)],
        blank=True,
        null=True)

    is_eligible = models.BooleanField(
        default=False,
        editable=False)

    preg_enroll = models.BooleanField(
        default=False,
        editable=False)

    ineligibility = models.TextField(
        verbose_name="Reason not eligible",
        max_length=150,
        null=True,
        editable=False)

    def save(self, *args, **kwargs):

        self.preg_enroll = self.is_preg

        eligibility_criteria = CaregiverChildConsentEligibility(
            self.child_test, self.child_remain_in_study, self.child_preg_test,
            self.child_knows_status)

        self.is_eligible = eligibility_criteria.is_eligible
        self.ineligibility = eligibility_criteria.error_message

        self.child_age_at_enrollment = (
            self.get_child_age_at_enrollment() if self.child_dob else 0)

        self.set_defaults()

        if self.is_eligible and (not self.subject_identifier or not self.version):

            # if self.consent_datetime >=
            self.version = '2.1'

            if self.preg_enroll:
                self.duplicate_subject_identifier_preg()

            if not self.subject_identifier:
                self.subject_identifier = InfantIdentifier(
                    maternal_identifier=self.subject_consent.subject_identifier,
                    birth_order=self.birth_order,
                    live_infants=self.live_infants,
                    registration_status=self.registration_status,
                    registration_datetime=self.consent_datetime,
                    subject_type=INFANT,
                    supplied_infant_suffix=self.subject_identifier_sufix).identifier

        super().save(*args, **kwargs)

    def set_defaults(self):

        if (not self.preg_enroll and self.study_child_identifier):

            child_dataset = self.get_child_dataset(self.study_child_identifier)

            if child_dataset:
                self.child_dob = child_dataset.dob
                self.gender = child_dataset.infant_sex.upper()[0]

    def get_child_dataset(self, study_child_identifier):
        child_dataset_cls = django_apps.get_model(
            'flourish_child.childdataset')

        try:
            child_dataset_obj = child_dataset_cls.objects.get(
                study_child_identifier=study_child_identifier)
        except child_dataset_cls.DoesNotExist:
            pass
        else:
            return child_dataset_obj

    def duplicate_subject_identifier_preg(self):
        try:
            child_consent = self._meta.model.objects.get(
                preg_enroll=True,
                subject_identifier__startswith=self.subject_consent.subject_identifier)
        except self._meta.model.DoesNotExist:
            pass
        else:
            self.subject_identifier = child_consent.subject_identifier

    @property
    def child_consent_version(self):

        consent_version_cls = django_apps.get_model(
            'flourish_caregiver.flourishconsentversion')
        try:
            consent_version_obj = consent_version_cls.objects.get(
                screening_identifier=self.subject_consent.screening_identifier)
        except consent_version_cls.DoesNotExist:
            pass
        else:
            return consent_version_obj.child_version

    @property
    def is_preg(self):

        if not self.study_child_identifier:
            return (self.child_dob and self.child_dob > self.consent_datetime.date()
                    or self.child_dob is None)
        return False

    @property
    def live_infants(self):
        child_dummy_consent_cls = django_apps.get_model(
            'flourish_child.childdummysubjectconsent')
        return child_dummy_consent_cls.objects.filter(
            subject_identifier__icontains=self.subject_consent.subject_identifier).exclude(
                identity=self.identity).count() + 1

    @property
    def subject_identifier_sufix(self):

        caregiver_child_consent_cls = django_apps.get_model(self._meta.label_lower)
        child_identifier_postfix = ''
        if self.child_dataset:
            if self.subject_consent.multiple_birth:
                if (self.subject_consent.multiple_births == 'twins'
                        and self.child_dataset.twin_triplet):
                    twin_id = self.subject_consent.subject_identifier + '-' + '25'
                    try:
                        caregiver_child_consent_cls.objects.get(
                            subject_identifier=twin_id)
                    except caregiver_child_consent_cls.DoesNotExist:
                        child_identifier_postfix = '25'
                    else:
                        child_identifier_postfix = '35'
                elif (self.subject_consent.multiple_births == 'triplets'
                        and self.child_dataset.twin_triplet):
                    twin_id = self.subject_consent.subject_identifier + '-' + '36'
                    try:
                        caregiver_child_consent_cls.objects.get(
                            subject_identifier=twin_id)
                    except caregiver_child_consent_cls.DoesNotExist:
                        child_identifier_postfix = '36'
                    else:
                        twin_id = self.subject_consent.subject_identifier + '-' + '46'
                        try:
                            caregiver_child_consent_cls.objects.get(
                                subject_identifier=twin_id)
                        except caregiver_child_consent_cls.DoesNotExist:
                            child_identifier_postfix = '46'
                        else:
                            child_identifier_postfix = '56'
            else:
                children_count = caregiver_child_consent_cls.objects.filter(
                    subject_identifier__startswith=self.subject_consent.subject_identifier).exclude(
                        child_dob=self.child_dob,
                        first_name=self.first_name).count()
                if children_count:
                    child_identifier_postfix = str((children_count + 5) * 10)
                else:
                    child_identifier_postfix = 10
        else:
            children_count = caregiver_child_consent_cls.objects.filter(
                    subject_identifier__startswith=self.subject_consent.subject_identifier).exclude(
                        child_dob=self.child_dob,
                        first_name=self.first_name).count()
            if children_count:
                child_identifier_postfix = str((children_count + 5) * 10)
            else:
                child_identifier_postfix = 10
        return child_identifier_postfix

    @property
    def child_dataset(self):
        child_dataset_cls = django_apps.get_model('flourish_child.childdataset')
        try:
            child_dataset = child_dataset_cls.objects.get(
                study_child_identifier=self.study_child_identifier)
        except child_dataset_cls.DoesNotExist:
            pass
        else:
            return child_dataset
        return None

    @property
    def registration_status(self):
        return 'REGISTERED'

    @property
    def birth_order(self):
        caregiver_child_consent_cls = django_apps.get_model(self._meta.label_lower)
        return caregiver_child_consent_cls.objects.filter(
            subject_identifier__icontains=self.subject_consent.subject_identifier).exclude(
                identity=self.identity).count() + 1

    def get_child_age_at_enrollment(self):
        return Cohort().age_at_enrollment(
            child_dob=self.child_dob,
            check_date=self.created.date())

    class Meta:
        app_label = 'flourish_caregiver'
        verbose_name = 'Caregiver Consent On Behalf Of Child'
        verbose_name_plural = 'Caregiver Consent On Behalf Of Child'
示例#10
0
class InfantBirth(UniqueSubjectIdentifierFieldMixin, SiteModelMixin,
                  SearchSlugModelMixin, CryptoMixin, BaseUuidModel):
    """ A model completed by the user on the infant's birth. """

    report_datetime = models.DateTimeField(
        verbose_name="Date and Time infant enrolled",
        validators=[
            datetime_not_future,
        ],
        help_text='')

    first_name = FirstnameField(
        max_length=25,
        verbose_name="Infant's first name",
        help_text="If infant name is unknown or not yet determined, "
        "use Baby + birth order + mother's last name, e.g. 'Baby1Malane'")

    initials = EncryptedCharField(validators=[
        RegexValidator(regex=r'^[A-Z]{2,3}$',
                       message=('Ensure initials consist of letters '
                                'only in upper case, no spaces.'))
    ], )

    dob = models.DateField(verbose_name='Date of Birth',
                           help_text="Must match labour and delivery report.",
                           validators=[
                               date_not_future,
                           ])

    gender = models.CharField(max_length=10, choices=GENDER_UNDETERMINED)

    def __str__(self):
        return f'{self.first_name}, {self.initials}, {self.gender}'

    def save(self, *args, **kwargs):
        self.consent_version = self.get_consent_version()
        super(InfantBirth, self).save(*args, **kwargs)

    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.')

    @property
    def schedule_name(self):
        """Return a visit schedule name.
        """
        schedule_name = None
        subject_consent = django_apps.get_model(
            'td_maternal.subjectconsent').objects.filter(
                subject_identifier=self.registered_subject.relative_identifier
            ).order_by('version').last()
        if subject_consent.version == '1':
            schedule_name = 'infant_schedule_v1'
        elif subject_consent.version == '3':
            schedule_name = 'infant_schedule_v3'
        return schedule_name

    @property
    def registered_subject(self):
        """Return infant registered subject.
        """
        registered_subject_cls = django_apps.get_model(
            'edc_registration.registeredsubject')
        try:
            registered_subject = registered_subject_cls.objects.get(
                subject_identifier=self.subject_identifier)
        except registered_subject_cls.DoesNotExist:
            raise ValidationError(
                f'Registered Subject is missing for {self.subject_identifier}')
        else:
            return registered_subject

    class Meta:
        app_label = 'td_infant'
        verbose_name = "Infant Birth"
示例#11
0
class CorrectConsent(CorrectConsentMixin, BaseUuidModel):

    """A model linked to the subject consent to record corrections."""

    subject_consent = models.OneToOneField(
        SubjectConsent, on_delete=PROTECT)

    report_datetime = models.DateTimeField(
        verbose_name="Correction report date ad time",
        null=True,
        validators=[
            datetime_not_future],
    )

    old_first_name = FirstnameField(
        null=True,
        blank=True,
    )

    new_first_name = FirstnameField(
        null=True,
        blank=True,
    )

    old_last_name = LastnameField(
        null=True,
        blank=True,
    )
    new_last_name = LastnameField(
        null=True,
        blank=True,
    )

    old_initials = EncryptedCharField(
        blank=True,
        null=True,
        validators=[RegexValidator(
            regex=r'^[A-Z]{2,3}$',
            message='Ensure initials consist of letters only in upper case, no spaces.'), ],
    )

    new_initials = EncryptedCharField(
        validators=[RegexValidator(
            regex=r'^[A-Z]{2,3}$',
            message='Ensure initials consist of letters only in upper case, no spaces.'), ],
        null=True,
        blank=True,
    )

    old_dob = models.DateField(
        verbose_name="Old Date of birth",
        null=True,
        blank=True,
        help_text="Format is YYYY-MM-DD",
    )

    new_dob = models.DateField(
        verbose_name="New Date of birth",
        null=True,
        blank=True,
        help_text="Format is YYYY-MM-DD",
    )

    old_gender = models.CharField(
        choices=GENDER_UNDETERMINED,
        blank=True,
        null=True,
        max_length=1)

    new_gender = models.CharField(
        choices=GENDER_UNDETERMINED,
        max_length=1,
        null=True,
        blank=True,
    )

    old_guardian_name = LastnameField(
        validators=[
            RegexValidator('^[A-Z]{1,50}\, [A-Z]{1,50}$',
                           'Invalid format. Format is '
                           '\'LASTNAME, FIRSTNAME\'. All uppercase separated by a comma')],
        blank=True,
        null=True,
    )

    new_guardian_name = LastnameField(
        validators=[
            RegexValidator('^[A-Z]{1,50}\, [A-Z]{1,50}$',
                           'Invalid format. Format is \'LASTNAME, FIRSTNAME\'. '
                           'All uppercase separated by a comma')],
        blank=True,
        null=True,
    )

    old_may_store_samples = models.CharField(
        verbose_name="Old Sample storage",
        max_length=3,
        blank=True,
        null=True,
        choices=YES_NO,
    )

    new_may_store_samples = models.CharField(
        verbose_name="New Sample storage",
        max_length=3,
        blank=True,
        null=True,
        choices=YES_NO,
    )

    old_is_literate = models.CharField(
        verbose_name="(Old) Is the participant LITERATE?",
        max_length=3,
        blank=True,
        null=True,
        choices=YES_NO,
    )

    new_is_literate = models.CharField(
        verbose_name="(New) Is the participant LITERATE?",
        max_length=3,
        blank=True,
        null=True,
        choices=YES_NO,
    )

    old_witness_name = LastnameField(
        verbose_name="Witness\'s Last and first name (illiterates only)",
        validators=[
            RegexValidator(
                '^[A-Z]{1,50}\, [A-Z]{1,50}$',
                'Invalid format. Format '
                'is \'LASTNAME, FIRSTNAME\'. All uppercase separated by a comma')],
        blank=True,
        null=True,
        help_text=('Required only if subject is illiterate. '
                   'Format is \'LASTNAME, FIRSTNAME\'. '
                   'All uppercase separated by a comma'),
    )

    new_witness_name = LastnameField(
        verbose_name="Witness\'s Last and first name (illiterates only)",
        validators=[
            RegexValidator(
                '^[A-Z]{1,50}\, [A-Z]{1,50}$',
                'Invalid format. Format is \'LASTNAME, FIRSTNAME\'. '
                'All uppercase separated by a comma')],
        blank=True,
        null=True,
        help_text=('Required only if subject is illiterate. '
                   'Format is \'LASTNAME, FIRSTNAME\'. '
                   'All uppercase separated by a comma'),
    )

    objects = CorrectConsentManager()

    history = HistoricalRecords()

    def __str__(self):
        return str(self.subject_consent,)

    def natural_key(self):
        return self.subject_consent.natural_key()
    natural_key.dependencies = ['bcpp_subject.subject_consent']

    def dashboard(self):
        ret = None
        dashboard_type = self.subject_consent.registered_subject.subject_type.lower()
        if self.appointment:
            url = reverse('bcpp_subject_dashboard:dashboard_url',
                          kwargs={'dashboard_type': dashboard_type,
                                  'dashboard_model': 'appointment',
                                  'dashboard_id': self.appointment.pk,
                                  'show': 'appointments'})
            ret = """<a href="{url}" />dashboard</a>""".format(url=url)
        return ret
    dashboard.allow_tags = True

    class Meta:
        app_label = 'bcpp_subject'
示例#12
0
class KaraboSubjectConsent(CryptoMixin, VerificationFieldsMixin,
                           SiteModelMixin, BaseUuidModel):

    subject_identifier = models.CharField(verbose_name="Subject Identifier",
                                          max_length=50)

    screening_identifier = models.CharField(
        verbose_name="Screening Identifier", max_length=36, unique=True)

    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.'))

    first_name = FirstnameField(verbose_name='First Name',
                                help_text=('(Must match name on file'
                                           ' with Tshilo Dikotla Study)'))

    last_name = LastnameField(verbose_name='Surname',
                              help_text=('(Must match name on file '
                                         'with Tshilo Dikotla Study)'))

    initials = EncryptedCharField(verbose_name='Initials ',
                                  help_text=('(Must match initials on file '
                                             'with Tshilo Dikotla Study)'))

    dob = models.DateField(verbose_name="Date of birth",
                           null=True,
                           blank=False)

    is_dob_estimated = IsDateEstimatedField(
        verbose_name="Is date of birth estimated?", null=True, blank=False)

    language = models.CharField(verbose_name='Language of consent:',
                                max_length=25,
                                choices=settings.LANGUAGES)

    is_literate = models.CharField(verbose_name='Is the participant literate?',
                                   max_length=25,
                                   choices=YES_NO)

    guardian_name = LastnameField(
        verbose_name='Witness\'s last and first name',
        validators=[FullNameValidator()],
        blank=True,
        null=True,
        help_text=mark_safe('Required only if participant is illiterate.<br>'
                            'Format is \'LASTNAME, FIRSTNAME\'. '
                            'All uppercase separated by a comma.'))

    consent_datetime = models.DateTimeField(
        verbose_name='Consent date and time',
        validators=[datetime_not_before_study_start, datetime_not_future])

    identity = IdentityField(verbose_name='Omang of consenting woman',
                             help_text=mark_safe(
                                 '(must match Omang on file '
                                 'with Tshilo Dikotla Study)'
                                 ' (Confirm that all Tshilo Dikotla '
                                 'women have enrolled with an Omang, '
                                 'otherwise will need additional ID '
                                 'questions.)'))

    consent_reviewed = models.CharField(
        verbose_name='I have reviewed the Karabo study '
        'consent with the client.',
        max_length=3,
        choices=YES_NO)

    study_questions = models.CharField(
        verbose_name='I have answered all questions the client'
        ' had about the Karabo study consent.',
        max_length=3,
        choices=YES_NO)

    assessment_score = models.CharField(
        verbose_name='I have asked the client questions'
        ' about the Karabo study and they have demonstrated an'
        ' understanding of the study by their answers.',
        max_length=3,
        choices=YES_NO)

    consent_signature = models.CharField(
        verbose_name='The client has signed the consent form.',
        max_length=3,
        choices=YES_NO)

    consent_copy = models.CharField(
        verbose_name='I have offered the client a signed copy'
        ' of the consent form.',
        max_length=25,
        choices=ANSWERS)

    def __str__(self):
        return f'{self.subject_identifier} {self.screening_identifier}'

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

    objects = KaraboSubjectConsentManager()

    history = HistoricalRecords()

    on_site = CurrentSiteManager()

    class Meta:
        app_label = 'td_maternal'
        verbose_name = "Karabo Subject Consent"
        verbose_name_plural = "Karabo Subject Consents"
示例#13
0
class HouseholdMember(UpdatesOrCreatesRegistrationModelMixin,
                      RepresentativeModelMixin,
                      CloneModelMixin, NextMemberModelMixin, ConsentModelMixin,
                      MemberStatusModelMixin, MemberEligibilityModelMixin,
                      MemberIdentifierModelMixin, RequiresHouseholdLogEntryMixin,
                      SurveyScheduleModelMixin, SearchSlugModelMixin, BaseUuidModel):
    """A model completed by the user to represent an enumerated
    household member.
    """

    household_structure = models.ForeignKey(
        HouseholdStructure, on_delete=models.PROTECT)

    household_identifier = models.CharField(
        max_length=25,
        help_text='updated on save from household')

    internal_identifier = models.UUIDField(
        default=uuid4,
        editable=False,
        help_text='Identifier to track member between surveys, '
                  'is the id of the member\'s first appearance in the table.')

    report_datetime = models.DateTimeField(
        verbose_name='Report date',
        default=get_utcnow,
        validators=[datetime_not_future])

    first_name = FirstnameField(
        verbose_name='First name',
        validators=[RegexValidator(
            '^[A-Z]{1,250}$', (
                'Ensure first name is only CAPS and does not '
                'contain any spaces or numbers'))])

    initials = models.CharField(
        verbose_name='Initials',
        max_length=3,
        validators=[
            MinLengthValidator(2),
            MaxLengthValidator(3),
            RegexValidator(
                '^[A-Z]{1,3}$', (
                    'Must be Only CAPS and 2 or 3 letters. '
                    'No spaces or numbers allowed.'))])

    gender = models.CharField(
        verbose_name='Gender',
        max_length=1,
        choices=GENDER)

    age_in_years = models.IntegerField(
        verbose_name='Age in years',
        validators=[MinValueValidator(0), MaxValueValidator(120)],
        help_text=(
            'If age is unknown, enter 0. If member is '
            'less than one year old, enter 1'))

    survival_status = models.CharField(
        verbose_name='Survival status',
        max_length=10,
        default=ALIVE,
        choices=ALIVE_DEAD_UNKNOWN,
        null=True,
        blank=False)

    present_today = models.CharField(
        verbose_name='Is the member present today?',
        max_length=3,
        choices=YES_NO_NA,
        null=True,
        blank=False)

    has_moved = models.CharField(
        verbose_name='Has the member moved out of this household?',
        max_length=3,
        default=NOT_APPLICABLE,
        choices=YES_NO_NA,
        null=True,
        blank=False)

    inability_to_participate = models.CharField(
        verbose_name='Do any of the following reasons apply to the participant?',
        max_length=17,
        null=True,
        choices=INABILITY_TO_PARTICIPATE_REASON,
        help_text=('Participant can only participate if ABLE is selected. '
                   '(Any other reason make the participant unable to take '
                   'part in the informed consent process)'))

    inability_to_participate_other = OtherCharField(
        null=True)

    study_resident = models.CharField(
        verbose_name='In the past 12 months, have you typically spent 3 or '
                     'more nights per month in this community? ',
        max_length=17,
        choices=YES_NO_NA_DWTA,
        null=True,
        blank=False,
        help_text=('If participant has moved into the '
                   'community in the past 12 months, then '
                   'since moving in has the participant typically '
                   'spent 3 or more nights per month in this community.'))

    visit_attempts = models.IntegerField(
        default=0,
        help_text='')

    eligible_htc = models.BooleanField(
        default=False,
        editable=False,
        help_text='')

    refused_htc = models.BooleanField(
        default=False,
        editable=False,
        help_text='updated by subject HTC save method only')

    htc = models.BooleanField(
        default=False,
        editable=False,
        help_text='updated by the subject HTC save method only')

    target = models.IntegerField(
        default=0,
        editable=False,
    )

    additional_key = models.CharField(
        max_length=36,
        verbose_name='-',
        editable=False,
        default=None,
        null=True,
        help_text=(
            'A uuid to be added to bypass the '
            'unique constraint for firstname, initials, household_structure. '
            'Should remain as the default value for normal enumeration. '
            'Is needed for Members added to the data from the clinic '
            'section where household_structure is always the same value.'),
    )

    objects = Manager()

    history = HistoricalRecords()

    def __str__(self):
        return (f'{self.first_name} {self.initials} {self.age_in_years}{self.gender} '
                f'{self.household_structure.survey_schedule}')

    def save(self, *args, **kwargs):
        self.household_identifier = (
            self.household_structure.household.household_identifier)
        if not self.id and not self.internal_identifier:
            self.internal_identifier = uuid4()
        self.survey_schedule = self.household_structure.survey_schedule
        super().save(*args, **kwargs)

    def natural_key(self):
        return ((self.internal_identifier,)
                + self.household_structure.natural_key())
    natural_key.dependencies = ['household.householdstructure']

    def update_subject_identifier_on_save(self):
        """Overridden to not set the subject identifier on save.
        """
        if not self.subject_identifier:
            self.subject_identifier = self.subject_identifier_as_pk.hex
            self.subject_identifier_aka = self.subject_identifier_as_pk.hex
        return self.subject_identifier

    @property
    def registration_unique_field(self):
        return 'internal_identifier'

    @property
    def registered_subject_unique_field(self):
        return 'registration_identifier'

    @property
    def registration_options(self):
        options = super().registration_options
        options.update(registration_identifier=self.internal_identifier.hex)
        return options

    @property
    def anonymous(self):
        """Returns True if this member resides on the anonymous plot.
        """
        plot = get_anonymous_plot()
        if self.household_structure.household.plot == plot:
            return True
        return False

    def common_clean(self):
        if self.survival_status == DEAD and self.present_today == YES:
            raise MemberValidationError(
                'Invalid combination. Got member status == {} but '
                'present today == {}'.format(
                    self.survival_status, self.present_today))
        super().common_clean()

    @property
    def common_clean_exceptions(self):
        return super().common_clean_exceptions + [MemberValidationError]

    class Meta:
        app_label = 'member'
        ordering = ['-created']
        unique_together = (
            ('internal_identifier', 'household_structure'),
            ('first_name', 'initials', 'household_structure'))
        index_together = [['internal_identifier',
                           'subject_identifier', 'created'], ]
class MaternalDataset(NonUniqueSubjectIdentifierFieldMixin, SiteModelMixin,
                      SearchSlugModelMixin, BaseUuidModel):

    identifier_cls = ScreeningIdentifier

    screening_identifier = models.CharField(
        verbose_name="Eligibility Identifier",
        max_length=36,
        blank=True,
        null=True,
        unique=True)

    study_maternal_identifier = models.CharField(
        verbose_name="Study maternal Subject Identifier",
        max_length=50,
        unique=True)

    first_name = FirstnameField(verbose_name='Firstname',
                                null=True,
                                blank=False)

    last_name = LastnameField(verbose_name='Lastname', null=True, blank=False)

    protocol = models.CharField(max_length=150)

    delivdt = models.DateField(verbose_name='Delivery date',
                               blank=True,
                               null=True)

    site_name = models.CharField(max_length=150)

    mom_enrolldate = models.DateField(verbose_name='Maternal enrollment date',
                                      blank=True,
                                      null=True)

    delivmeth = models.CharField(verbose_name='Method of delivery',
                                 max_length=150,
                                 blank=True,
                                 null=True)

    delivery_location = models.CharField(verbose_name='Delivery location',
                                         max_length=150,
                                         blank=True,
                                         null=True)

    ega_delivery = models.IntegerField(verbose_name='EGA at delivery',
                                       blank=True,
                                       null=True)

    mom_age_enrollment = models.CharField(
        verbose_name='Mother\'s age at enrollment',
        max_length=150,
        blank=True,
        null=True)

    mom_hivstatus = models.CharField(
        verbose_name='Maternal HIV infection status', max_length=150)

    parity = models.IntegerField(blank=True, null=True)

    gravida = models.IntegerField(blank=True, null=True)

    mom_education = models.CharField(verbose_name='Maternal education level',
                                     max_length=150,
                                     blank=True,
                                     null=True)

    mom_maritalstatus = models.CharField(
        verbose_name='Maternal marital status',
        max_length=150,
        blank=True,
        null=True)

    mom_personal_earnings = models.CharField(
        verbose_name='Mother\'s personal earnings',
        max_length=150,
        blank=True,
        null=True)

    mom_moneysource = models.CharField(
        verbose_name='Maternal source of income',
        max_length=150,
        blank=True,
        null=True)

    mom_occupation = models.CharField(verbose_name='Mother\'s occupation',
                                      max_length=150,
                                      blank=True,
                                      null=True)

    mom_pregarv_strat = models.CharField(
        verbose_name='Maternal ARVs during pregnancy',
        max_length=150,
        blank=True,
        null=True)

    mom_arvstart_date = models.DateField(
        verbose_name='Date mother started HAART', blank=True, null=True)

    mom_baseline_cd4 = models.IntegerField(
        verbose_name='Maternal baseline CD4 count', blank=True, null=True)

    mom_baseline_cd4date = models.DateField(
        verbose_name='Draw data of mother\'s baseline CD4',
        blank=True,
        null=True)

    mom_baseline_vl = models.IntegerField(
        verbose_name='Maternal baseline viral load', blank=True, null=True)

    mom_baseline_vldate = models.DateField(
        verbose_name='Draw date of mother\'s baseline VL',
        blank=True,
        null=True)

    mom_baseline_hgb = models.DecimalField(
        verbose_name='Maternal baseline HGB',
        decimal_places=1,
        max_digits=10,
        blank=True,
        null=True)

    mom_baseline_hgbdt = models.DateField(
        verbose_name='Date of maternal baseline HGB', blank=True, null=True)

    mom_deathdate = models.DateField(verbose_name='Date mother died',
                                     blank=True,
                                     null=True)

    cooking_method = models.CharField(verbose_name='Primary cooking method',
                                      max_length=200,
                                      blank=True,
                                      null=True)

    home_eletrified = models.CharField(verbose_name='Electricity in home',
                                       max_length=150,
                                       blank=True,
                                       null=True)

    house_type = models.CharField(verbose_name='Type of dwelling',
                                  max_length=150,
                                  blank=True,
                                  null=True)

    toilet = models.CharField(verbose_name='Toilet facilities',
                              max_length=150,
                              blank=True,
                              null=True)

    toilet_indoors = models.CharField(verbose_name='House has indoor toilet',
                                      max_length=150,
                                      blank=True,
                                      null=True)

    toilet_private = models.CharField(
        verbose_name='Private toilet for compound',
        max_length=150,
        blank=True,
        null=True)

    piped_water = models.CharField(verbose_name='Water piped into home',
                                   max_length=150,
                                   blank=True,
                                   null=True)

    home_refridgeration = models.CharField(
        verbose_name='Refrigeration in home',
        max_length=150,
        blank=True,
        null=True)

    drinking_water = models.CharField(verbose_name='Source of drinking water',
                                      max_length=150,
                                      blank=True,
                                      null=True)

    live_inhouse_number = models.IntegerField(
        verbose_name='Number of people living in household',
        blank=True,
        null=True)

    twin_triplet = models.IntegerField(verbose_name='Twins or thiplets',
                                       blank=True,
                                       null=True)

    preg_dtg = models.IntegerField(verbose_name='Preg DTG',
                                   blank=True,
                                   null=True)

    preg_pi = models.IntegerField(verbose_name='Preg PI',
                                  blank=True,
                                  null=True)

    preg_efv = models.IntegerField(verbose_name='Preg EFV',
                                   blank=True,
                                   null=True)

    on_worklist = models.BooleanField(default=False, blank=True, null=True)

    objects = MaternalDatasetManager()

    def __str__(self):
        return self.study_maternal_identifier

    def save(self, *args, **kwargs):
        if not self.screening_identifier:
            self.screening_identifier = self.identifier_cls().identifier
        super().save(*args, **kwargs)

    def get_search_slug_fields(self):
        fields = super().get_search_slug_fields()
        fields.append('screening_identifier')
        fields.append('study_maternal_identifier')
        fields.append('first_name')
        return fields

    class Meta:
        app_label = 'flourish_caregiver'
        verbose_name = 'Maternal Dataset'
示例#15
0
class HomeVisitAttempt(BaseUuidModel):

    home_visit = models.ForeignKey(
        HomeVisit,
        on_delete=PROTECT)

    contact_attempted = models.CharField(
        verbose_name='Was a home visit attempt made?',
        choices=YES_NO,
        max_length=3)

    contact_staff = FirstnameField(
        verbose_name='Name(s) of staff member who visited the participant',
        blank=True,
        null=True)

    contact_date = models.DateField(
        verbose_name='Date of home visit attempt',
        validators=[date_not_future, ],
        blank=True,
        null=True)

    contact_loc = EncryptedTextField(
        verbose_name='Which address was used for contact attempt?',
        max_length=500,
        help_text='Provide a detailed description of the physical address.',
        blank=True,
        null=True)

    contact_outcome = models.TextField(
        verbose_name='What was the outcome of the in person visit.',
        max_length=500,
        null=True,
        blank=True)

    appt = models.CharField(
        verbose_name='Is the participant willing to schedule an appointment',
        max_length=7,
        choices=YES_NO,
        null=True,
        blank=True)

    appt_date = models.DateField(
        verbose_name='Appointment Date',
        validators=[date_is_future],
        null=True,
        blank=True,
        help_text='This can only come from the participant.')

    offstudy = models.CharField(
        verbose_name='Is the participant going offstudy?',
        choices=YES_NO,
        max_length=3,
        blank=True,
        null=True)

    comment = models.TextField(
        verbose_name='Additional Comments',
        blank=True,
        null=True)

    class Meta:
        app_label = 'motheo_call_manager'
class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin,
                        edc_models.BaseUuidModel):
    """A model mixin for the RegisteredSubject model (only)."""

    # may not be available when instance created (e.g. infants prior to birth
    # report)
    first_name = FirstnameField(null=True)

    # may not be available when instance created (e.g. infants or household
    # subject before consent)
    last_name = LastnameField(verbose_name="Last name", null=True)

    # may not be available when instance created (e.g. infants)
    initials = EncryptedCharField(
        validators=[
            RegexValidator(
                regex=r"^[A-Z]{2,3}$",
                message=("Ensure initials consist of letters "
                         "only in upper case, no spaces."),
            )
        ],
        null=True,
    )

    dob = models.DateField(
        verbose_name=_("Date of birth"),
        null=True,
        blank=False,
        help_text=_("Format is YYYY-MM-DD"),
    )

    is_dob_estimated = IsDateEstimatedField(
        verbose_name=_("Is date of birth estimated?"), null=True, blank=False)

    gender = models.CharField(verbose_name="Gender",
                              max_length=1,
                              choices=GENDER,
                              null=True,
                              blank=False)

    subject_consent_id = models.CharField(max_length=100,
                                          null=True,
                                          blank=True)

    registration_identifier = models.CharField(max_length=36,
                                               null=True,
                                               blank=True)

    sid = models.CharField(verbose_name="SID",
                           max_length=15,
                           null=True,
                           blank=True)

    subject_type = models.CharField(max_length=25, null=True, blank=True)

    relative_identifier = models.CharField(
        verbose_name="Identifier of immediate relation",
        max_length=36,
        null=True,
        blank=True,
        help_text=
        "For example, mother's identifier, if available / appropriate",
    )

    identity = IdentityField(null=True, blank=True)

    identity_type = IdentityTypeField(null=True, blank=True)

    screening_identifier = models.CharField(max_length=36,
                                            null=True,
                                            blank=True)

    screening_datetime = models.DateTimeField(null=True, blank=True)

    screening_age_in_years = models.IntegerField(null=True, blank=True)

    registration_datetime = models.DateTimeField(null=True, blank=True)

    # For simplicity, if going straight from screen to rando,
    # update both registration date and randomization date
    randomization_datetime = models.DateTimeField(null=True, blank=True)

    registration_status = models.CharField(verbose_name="Registration status",
                                           max_length=25,
                                           null=True,
                                           blank=True)

    consent_datetime = models.DateTimeField(null=True, blank=True)

    comment = models.TextField(verbose_name="Comment",
                               max_length=250,
                               null=True,
                               blank=True)

    additional_key = models.CharField(
        max_length=36,
        verbose_name="-",
        editable=False,
        default=None,
        null=True,
        help_text=(
            "A uuid (or some other text value) to be added to bypass the "
            "unique constraint of just firstname, initials, and dob."
            "The default constraint proves limiting since the source "
            "model usually has some other attribute in additional to "
            "first_name, initials and dob which is not captured in "
            "this model"),
    )

    dm_comment = models.CharField(
        verbose_name="Data Management comment",
        max_length=150,
        null=True,
        editable=False,
    )

    randomization_list_model = models.CharField(max_length=150, null=True)

    on_site = CurrentSiteManager()

    history = edc_models.HistoricalRecords()

    objects = RegisteredSubjectManager()

    def save(self, *args, **kwargs):
        if self.identity:
            self.additional_key = None
        self.set_uuid_as_subject_identifier_if_none()
        self.raise_on_duplicate("subject_identifier")
        self.raise_on_duplicate("identity")
        self.raise_on_changed_subject_identifier()
        super().save(*args, **kwargs)

    def natural_key(self):
        return tuple(self.subject_identifier_as_pk)

    def __str__(self):
        return self.masked_subject_identifier

    natural_key.dependencies = ["sites.Site"]

    def update_subject_identifier_on_save(self):
        """Overridden to not set the subject identifier on save."""
        if not self.subject_identifier:
            self.subject_identifier = self.subject_identifier_as_pk.hex
        elif re.match(UUID_PATTERN, self.subject_identifier):
            pass
        return self.subject_identifier

    def make_new_identifier(self):
        return self.subject_identifier_as_pk.hex

    @property
    def masked_subject_identifier(self):
        """Returns the subject identifier, if set, otherwise
        the string '<identifier not set>'.
        """
        if not self.subject_identifier_is_set:
            return "<identifier not set>"
        return self.subject_identifier

    @property
    def subject_identifier_is_set(self):
        """Returns True if subject identifier has been set to a
        subject identifier; that is, no longer the default UUID.
        """
        is_set = True
        try:
            obj = self.__class__.objects.get(pk=self.id)
        except ObjectDoesNotExist:
            is_set = False
        else:
            if re.match(UUID_PATTERN, obj.subject_identifier):
                return False
        return is_set

    def raise_on_changed_subject_identifier(self):
        """Raises an exception if there is an attempt to change
        the subject identifier for an existing instance if the subject
        identifier is already set.
        """
        if self.id and self.subject_identifier_is_set:
            with transaction.atomic():
                obj = self.__class__.objects.get(pk=self.id)
                if obj.subject_identifier != self.subject_identifier_as_pk.hex:
                    if self.subject_identifier != obj.subject_identifier:
                        raise RegisteredSubjectError(
                            "Subject identifier cannot be changed for "
                            "existing registered subject. "
                            f"Got {self.subject_identifier} <> {obj.subject_identifier}."
                        )

    def raise_on_duplicate(self, attrname):
        """Checks if the subject identifier (or other attr) is in use,
        for new and existing instances.
        """
        if getattr(self, attrname):
            with transaction.atomic():
                error_msg = (
                    f"Cannot {{action}} registered subject with a duplicate "
                    f"'{attrname}'. Got {getattr(self, attrname)}.")
                try:
                    obj = self.__class__.objects.exclude(**{
                        "pk": self.pk
                    } if self.id else {}).get(
                        **{attrname: getattr(self, attrname)})
                    if not self.id:
                        raise RegisteredSubjectError(
                            error_msg.format(action="insert"))
                    elif self.subject_identifier_is_set and obj.id != self.id:
                        raise RegisteredSubjectError(
                            error_msg.format(action="update"))
                    else:
                        raise RegisteredSubjectError(
                            error_msg.format(action="update"))
                except ObjectDoesNotExist:
                    pass

    def set_uuid_as_subject_identifier_if_none(self):
        """Inserts a random uuid as a dummy identifier for a new
        instance.

        Model uses subject_identifier_as_pk as a natural key for
        serialization/deserialization. Value must not change
        once set.
        """
        if not self.subject_identifier:
            self.subject_identifier = self.subject_identifier_as_pk.hex

    class Meta(edc_models.BaseUuidModel.Meta):
        verbose_name = "Registered Subject"
        ordering = ["subject_identifier"]
        unique_together = ("first_name", "dob", "initials", "additional_key")
        indexes = [
            models.Index(
                fields=["first_name", "dob", "initials", "additional_key"]),
            models.Index(fields=[
                "identity", "subject_identifier", "screening_identifier"
            ]),
        ]
        permissions = (
            ("display_firstname", "Can display first name"),
            ("display_lastname", "Can display last name"),
            ("display_dob", "Can display DOB"),
            ("display_identity", "Can display identity number"),
            ("display_initials", "Can display initials"),
        )
示例#17
0
class MoccaRegister(SiteModelMixin, BaseUuidModel):

    report_datetime = models.DateTimeField(default=get_utcnow)

    screening_identifier = models.CharField(
        verbose_name="MOCCA (ext) screening identifier",
        max_length=15,
        null=True,
    )

    mocca_screening_identifier = models.CharField(
        verbose_name="MOCCA (original) screening identifier",
        max_length=15,
        null=True,
        blank=True,
        help_text="If known",
    )

    mocca_study_identifier = models.CharField(
        verbose_name="MOCCA (original) study identifier",
        max_length=25,
        validators=[
            RegexValidator(
                r"0[0-9]{1}\-0[0-9]{3}|[0-9]{6}",
                "Invalid format. Expected 12-3456 for UG, 123456 for TZ",
            )
        ],
        help_text="Format must match original identifier. e.g. 12-3456 for UG, 123456 for TZ",
    )

    mocca_country = models.CharField(
        max_length=25, choices=(("uganda", "Uganda"), ("tanzania", "Tanzania"))
    )

    mocca_site = models.ForeignKey(
        MoccaOriginalSites,
        on_delete=models.PROTECT,
        limit_choices_to=get_mocca_site_limited_to,
    )

    first_name = FirstnameField(null=True)

    last_name = LastnameField(null=True)

    initials = EncryptedCharField(
        validators=[
            RegexValidator("[A-Z]{1,3}", "Invalid format"),
            MinLengthValidator(2),
            MaxLengthValidator(3),
        ],
        help_text="Use UPPERCASE letters only. May be 2 or 3 letters.",
        null=True,
        blank=False,
    )
    gender = models.CharField(max_length=10, choices=GENDER, null=True, blank=False)

    age_in_years = models.IntegerField(
        validators=[MinValueValidator(18), MaxValueValidator(110)],
        null=True,
        blank=False,
    )

    birth_year = models.IntegerField(
        validators=[MinValueValidator(1900), MaxValueValidator(2002)],
        null=True,
        blank=False,
    )
    dob = models.DateField(null=True, blank=True)

    survival_status = models.CharField(
        max_length=25, choices=ALIVE_DEAD_UNKNOWN, default=UNKNOWN
    )

    contact_attempts = models.IntegerField(default=0, help_text="auto-updated")

    call = models.CharField(verbose_name="Call?", max_length=15, choices=YES_NO, default=YES)

    subject_present = models.CharField(
        verbose_name="Patient is present. Screen now instead of calling?",
        max_length=15,
        choices=YES_NO,
        default=NO,
        help_text="Only select 'yes' if the patient is present in the clinic now.",
    )

    date_last_called = models.DateField(null=True, help_text="auto-updated")

    next_appt_date = models.DateField(
        verbose_name="Appt", null=True, blank=True, help_text="auto-updated"
    )

    notes = EncryptedTextField(verbose_name="General notes", null=True, blank=True)

    tel_one = EncryptedCharField("Tel/Mobile(1)", max_length=15, null=True)
    tel_two = EncryptedCharField("Tel/Mobile(2)", max_length=15, null=True)
    tel_three = EncryptedCharField("Tel/Mobile(3)", max_length=15, null=True)
    best_tel = models.CharField(
        verbose_name="Prefered Telephone / Mobile",
        max_length=15,
        choices=TEL_CHOICES,
        null=True,
        blank=True,
        help_text="If any, select the best telephone/mobile from above",
    )

    on_site = CurrentSiteManager()
    objects = Manager()
    history = HistoricalRecords()

    def __str__(self):
        return (
            f"{self.mocca_study_identifier} {self.initials} {self.age_in_years} {self.gender}"
        )

    def save(self, *args, **kwargs):
        if self.screening_identifier:
            self.call = NO
        super().save(*args, **kwargs)

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

    natural_key.dependencies = [
        "sites.Site",
        "mocca_lists.MoccaOriginalSites",
    ]

    class Meta(BaseUuidModel.Meta):
        verbose_name = "MOCCA Patient Register"
        verbose_name_plural = "MOCCA Patient Register"
        ordering = ["mocca_country", "mocca_site"]
        indexes = [
            Index(fields=["mocca_country", "mocca_site"]),
            Index(fields=["mocca_study_identifier", "initials", "gender"]),
        ]
        constraints = [
            UniqueConstraint(
                fields=["mocca_screening_identifier"],
                name="unique_mocca_screening_identifier",
            ),
            UniqueConstraint(
                fields=["mocca_study_identifier"], name="unique_mocca_study_identifier"
            ),
        ]