def _update_participant_summary(
      self, session, questionnaire_response, code_ids, questions, questionnaire_history):
    """Updates the participant summary based on questions answered and modules completed
    in the questionnaire response.

    If no participant summary exists already, only a response to the study enrollment consent
    questionnaire can be submitted, and it must include first and last name and e-mail address.
    """
    # Block on other threads modifying the participant or participant summary.
    participant = ParticipantDao().get_for_update(session, questionnaire_response.participantId)

    if participant is None:
      raise BadRequest('Participant with ID %d is not found.' %
                        questionnaire_response.participantId)

    participant_summary = participant.participantSummary

    code_ids.extend([concept.codeId for concept in questionnaire_history.concepts])

    code_dao = CodeDao()

    something_changed = False
    # If no participant summary exists, make sure this is the study enrollment consent.
    if not participant_summary:
      consent_code = code_dao.get_code(PPI_SYSTEM, CONSENT_FOR_STUDY_ENROLLMENT_MODULE)
      if not consent_code:
        raise BadRequest('No study enrollment consent code found; import codebook.')
      if not consent_code.codeId in code_ids:
        raise BadRequest("Can't submit order for participant %s without consent" %
                         questionnaire_response.participantId)
      raise_if_withdrawn(participant)
      participant_summary = ParticipantDao.create_summary_for_participant(participant)
      something_changed = True
    else:
      raise_if_withdrawn(participant_summary)

    # Fetch the codes for all questions and concepts
    codes = code_dao.get_with_ids(code_ids)

    code_map = {code.codeId: code for code in codes if code.system == PPI_SYSTEM}
    question_map = {question.questionnaireQuestionId: question for question in questions}
    race_code_ids = []
    ehr_consent = False
    # Set summary fields for answers that have questions with codes found in QUESTION_CODE_TO_FIELD
    for answer in questionnaire_response.answers:
      question = question_map.get(answer.questionId)
      if question:
        code = code_map.get(question.codeId)
        if code:
          summary_field = QUESTION_CODE_TO_FIELD.get(code.value)
          if summary_field:
            something_changed = self._update_field(participant_summary, summary_field[0],
                                                   summary_field[1], answer)
          elif code.value == RACE_QUESTION_CODE:
            race_code_ids.append(answer.valueCodeId)
          elif code.value == EHR_CONSENT_QUESTION_CODE:
            code = code_dao.get(answer.valueCodeId)
            if code and code.value == CONSENT_PERMISSION_YES_CODE:
              ehr_consent = True
          elif code.value == CABOR_SIGNATURE_QUESTION_CODE:
            if answer.valueUri or answer.valueString:
              # TODO: validate the URI? [DA-326]
              if not participant_summary.consentForCABoR:
                participant_summary.consentForCABoR = True
                participant_summary.consentForCABoRTime = questionnaire_response.created
                something_changed = True

    # If race was provided in the response in one or more answers, set the new value.
    if race_code_ids:
      race_codes = [code_dao.get(code_id) for code_id in race_code_ids]
      race = get_race(race_codes)
      if race != participant_summary.race:
        participant_summary.race = race
        something_changed = True

    # Set summary fields to SUBMITTED for questionnaire concepts that are found in
    # QUESTIONNAIRE_MODULE_CODE_TO_FIELD
    module_changed = False
    for concept in questionnaire_history.concepts:
      code = code_map.get(concept.codeId)
      if code:
        summary_field = QUESTIONNAIRE_MODULE_CODE_TO_FIELD.get(code.value)
        if summary_field:
          new_status = QuestionnaireStatus.SUBMITTED
          if code.value == CONSENT_FOR_ELECTRONIC_HEALTH_RECORDS_MODULE and not ehr_consent:
            new_status = QuestionnaireStatus.SUBMITTED_NO_CONSENT
          if getattr(participant_summary, summary_field) != new_status:
            setattr(participant_summary, summary_field, new_status)
            setattr(participant_summary, summary_field + 'Time', questionnaire_response.created)
            something_changed = True
            module_changed = True
    if module_changed:
      participant_summary.numCompletedBaselinePPIModules = \
          count_completed_baseline_ppi_modules(participant_summary)
      participant_summary.numCompletedPPIModules = \
          count_completed_ppi_modules(participant_summary)

    if something_changed:
      first_last_email = (
          participant_summary.firstName, participant_summary.lastName, participant_summary.email)
      if not all(first_last_email):
        raise BadRequest(
            'First name (%s), last name (%s), and email address (%s) required for consenting.'
            % tuple(['present' if part else 'missing' for part in first_last_email]))
      ParticipantSummaryDao().update_enrollment_status(participant_summary)
      participant_summary.lastModified = clock.CLOCK.now()
      session.merge(participant_summary)
Ejemplo n.º 2
0
    def _update_participant_summary(self, session, questionnaire_response,
                                    code_ids, questions, questionnaire_history,
                                    resource_json):
        """Updates the participant summary based on questions answered and modules completed
    in the questionnaire response.

    If no participant summary exists already, only a response to the study enrollment consent
    questionnaire can be submitted, and it must include first and last name and e-mail address.
    """

        # Block on other threads modifying the participant or participant summary.
        participant = ParticipantDao().get_for_update(
            session, questionnaire_response.participantId)

        if participant is None:
            raise BadRequest('Participant with ID %d is not found.' %
                             questionnaire_response.participantId)

        participant_summary = participant.participantSummary

        code_ids.extend(
            [concept.codeId for concept in questionnaire_history.concepts])

        code_dao = CodeDao()

        something_changed = False
        # If no participant summary exists, make sure this is the study enrollment consent.
        if not participant_summary:
            consent_code = code_dao.get_code(
                PPI_SYSTEM, CONSENT_FOR_STUDY_ENROLLMENT_MODULE)
            if not consent_code:
                raise BadRequest(
                    'No study enrollment consent code found; import codebook.')
            if not consent_code.codeId in code_ids:
                raise BadRequest(
                    "Can't submit order for participant %s without consent" %
                    questionnaire_response.participantId)
            raise_if_withdrawn(participant)
            participant_summary = ParticipantDao.create_summary_for_participant(
                participant)
            something_changed = True
        else:
            raise_if_withdrawn(participant_summary)

        # Fetch the codes for all questions and concepts
        codes = code_dao.get_with_ids(code_ids)

        code_map = {
            code.codeId: code
            for code in codes if code.system == PPI_SYSTEM
        }
        question_map = {
            question.questionnaireQuestionId: question
            for question in questions
        }
        race_code_ids = []
        ehr_consent = False
        dvehr_consent = QuestionnaireStatus.SUBMITTED_NO_CONSENT
        # Set summary fields for answers that have questions with codes found in QUESTION_CODE_TO_FIELD
        for answer in questionnaire_response.answers:
            question = question_map.get(answer.questionId)
            if question:
                code = code_map.get(question.codeId)
                if code:
                    summary_field = QUESTION_CODE_TO_FIELD.get(code.value)
                    if summary_field:
                        if something_changed:
                            self._update_field(participant_summary,
                                               summary_field[0],
                                               summary_field[1], answer)
                        else:
                            something_changed = self._update_field(
                                participant_summary, summary_field[0],
                                summary_field[1], answer)
                    elif code.value == RACE_QUESTION_CODE:
                        race_code_ids.append(answer.valueCodeId)

                    elif code.value == DVEHR_SHARING_QUESTION_CODE:
                        code = code_dao.get(answer.valueCodeId)
                        if code and code.value == DVEHRSHARING_CONSENT_CODE_YES:
                            dvehr_consent = QuestionnaireStatus.SUBMITTED
                        elif code and code.value == DVEHRSHARING_CONSENT_CODE_NOT_SURE:
                            dvehr_consent = QuestionnaireStatus.SUBMITTED_NOT_SURE
                    elif code.value == EHR_CONSENT_QUESTION_CODE:
                        code = code_dao.get(answer.valueCodeId)
                        if code and code.value == CONSENT_PERMISSION_YES_CODE:
                            ehr_consent = True
                    elif code.value == CABOR_SIGNATURE_QUESTION_CODE:
                        if answer.valueUri or answer.valueString:
                            # TODO: validate the URI? [DA-326]
                            if not participant_summary.consentForCABoR:
                                participant_summary.consentForCABoR = True
                                participant_summary.consentForCABoRTime = questionnaire_response.created
                                something_changed = True

        # If race was provided in the response in one or more answers, set the new value.
        if race_code_ids:
            race_codes = [code_dao.get(code_id) for code_id in race_code_ids]
            race = get_race(race_codes)
            if race != participant_summary.race:
                participant_summary.race = race
                something_changed = True

        # Set summary fields to SUBMITTED for questionnaire concepts that are found in
        # QUESTIONNAIRE_MODULE_CODE_TO_FIELD
        module_changed = False
        for concept in questionnaire_history.concepts:
            code = code_map.get(concept.codeId)
            if code:
                summary_field = QUESTIONNAIRE_MODULE_CODE_TO_FIELD.get(
                    code.value)
                if summary_field:
                    new_status = QuestionnaireStatus.SUBMITTED
                    if code.value == CONSENT_FOR_ELECTRONIC_HEALTH_RECORDS_MODULE and not ehr_consent:
                        new_status = QuestionnaireStatus.SUBMITTED_NO_CONSENT
                    elif code.value == CONSENT_FOR_DVEHR_MODULE:
                        new_status = dvehr_consent
                    elif code.value == CONSENT_FOR_STUDY_ENROLLMENT_MODULE:
                        # set language of consent to participant summary
                        for extension in resource_json.get('extension', []):
                            if extension.get('url') == _LANGUAGE_EXTENSION and \
                              extension.get('valueCode') in LANGUAGE_OF_CONSENT:
                                if participant_summary.primaryLanguage != extension.get(
                                        'valueCode'):
                                    participant_summary.primaryLanguage = extension.get(
                                        'valueCode')
                                    something_changed = True
                                break
                            elif extension.get('url') == _LANGUAGE_EXTENSION and \
                              extension.get('valueCode') not in LANGUAGE_OF_CONSENT:
                                logging.warn(
                                    'consent language %s not recognized.' %
                                    extension.get('valueCode'))
                    if getattr(participant_summary,
                               summary_field) != new_status:
                        setattr(participant_summary, summary_field, new_status)
                        setattr(participant_summary, summary_field + 'Time',
                                questionnaire_response.created)
                        something_changed = True
                        module_changed = True
        if module_changed:
            participant_summary.numCompletedBaselinePPIModules = \
                count_completed_baseline_ppi_modules(participant_summary)
            participant_summary.numCompletedPPIModules = \
                count_completed_ppi_modules(participant_summary)

        if something_changed:
            first_last = (participant_summary.firstName,
                          participant_summary.lastName)
            email_phone = (participant_summary.email,
                           participant_summary.loginPhoneNumber)
            if not all(first_last):
                raise BadRequest(
                    'First name (%s), and last name (%s) required for consenting.'
                    % tuple([
                        'present' if part else 'missing' for part in first_last
                    ]))
            if not any(email_phone):
                raise BadRequest(
                    'Email address (%s), or phone number (%s) required for consenting.'
                    % tuple([
                        'present' if part else 'missing'
                        for part in email_phone
                    ]))

            ParticipantSummaryDao().update_enrollment_status(
                participant_summary)
            participant_summary.lastModified = clock.CLOCK.now()
            session.merge(participant_summary)

            # switch account to test account if the phone number is start with 444
            # this is a requirement from PTSC
            if participant_summary.loginPhoneNumber is not None and \
              participant_summary.loginPhoneNumber.startswith(TEST_LOGIN_PHONE_NUMBER_PREFIX):
                ParticipantDao().switch_to_test_account(
                    session, participant_summary.participantId)
Ejemplo n.º 3
0
_MAX_RACE_ANSWERS = 3

# Maximum age of participants
_MAX_PARTICIPANT_AGE = 102

# Minimum age of participants
_MIN_PARTICIPANT_AGE = 12

_QUESTIONNAIRE_CONCEPTS = [CONSENT_FOR_STUDY_ENROLLMENT_MODULE,
                          CONSENT_FOR_ELECTRONIC_HEALTH_RECORDS_MODULE,
                          OVERALL_HEALTH_PPI_MODULE,
                          LIFESTYLE_PPI_MODULE,
                          THE_BASICS_PPI_MODULE]
_CALIFORNIA_HPOS = ['CAL_PMC', 'SAN_YSIDRO']

_QUESTION_CODES = QUESTION_CODE_TO_FIELD.keys() + [RACE_QUESTION_CODE,
                                                   CABOR_SIGNATURE_QUESTION_CODE]

_CONSTANT_CODES = [PMI_PREFER_NOT_TO_ANSWER_CODE, PMI_OTHER_CODE]


class FakeParticipantGenerator(object):

  def __init__(self, client, use_local_files=None):
    self._use_local_files = use_local_files
    self._client = client
    self._hpos = HPODao().get_all()
    self._sites = SiteDao().get_all()
    if not self._sites:
      raise BadRequest('No sites found; import sites before running generator.')
    self._now = clock.CLOCK.now()