def test_identifier_case_property_deleted(self, get_patient_mock,
                                              case_blocks_mock):
        """
        CommCare should drop the case's patient ID when an OpenMRS patient is voided
        """
        requests = None
        info = CaseTriggerInfo(
            domain=self.case.domain,
            case_id=self.case.case_id,
            type=self.case.type,
            name=self.case.name,
            extra_fields={
                "external_id": self.case.external_id,
            },
        )
        openmrs_config = OpenmrsConfig.wrap({
            "case_config": {
                "patient_finder": {},
                "patient_identifiers": {
                    "uuid": {
                        "case_property": "external_id"
                    },
                },
                "match_on_ids": ["uuid"],
                "person_properties": {},
                "person_preferred_address": {},
                "person_preferred_name": {},
            },
            "form_configs": [],
        })
        voided_patient = self.get_json("voided_patient")
        get_patient_mock.return_value = voided_patient

        patient = get_patient(requests, DOMAIN, info, openmrs_config)

        self.assertEqual(info.extra_fields, {"external_id": None})
        case_block_re = strip_xml(f"""
            <case case_id="123456" »
                  date_modified="{DATETIME_PATTERN}" »
                  xmlns="http://commcarehq.org/case/transaction/v2">
              <update>
                <external_id />
              </update>
            </case>
        """)
        case_block = case_blocks_mock.call_args[0][0][0]
        self.assertIsNotNone(re.match(case_block_re, case_block))
        self.assertIsNone(patient)
Exemple #2
0
def sync_openmrs_patient(requests, info, openmrs_config, problem_log):
    patient = get_patient(requests, info, openmrs_config, problem_log)
    person_uuid = patient['person']['uuid']
    update_person_properties(requests, info, openmrs_config, person_uuid)

    name_uuid = patient['person']['preferredName']['uuid']
    update_person_name(requests, info, openmrs_config, person_uuid, name_uuid)

    address_uuid = patient['person']['preferredAddress']['uuid'] if patient[
        'person']['preferredAddress'] else None
    if address_uuid:
        update_person_address(requests, info, openmrs_config, person_uuid,
                              address_uuid)
    else:
        create_person_address(requests, info, openmrs_config, person_uuid)

    sync_person_attributes(requests, info, openmrs_config, person_uuid,
                           patient['person']['attributes'])

    return person_uuid
Exemple #3
0
def sync_openmrs_patient(requests, info, openmrs_config, problem_log):
    patient = get_patient(requests, info, openmrs_config, problem_log)
    if patient is None:
        raise ValueError('CommCare patient was not found in OpenMRS')
    person_uuid = patient['person']['uuid']
    update_person_properties(requests, info, openmrs_config, person_uuid)

    name_uuid = patient['person']['preferredName']['uuid']
    update_person_name(requests, info, openmrs_config, person_uuid, name_uuid)

    address_uuid = patient['person']['preferredAddress']['uuid'] if patient[
        'person']['preferredAddress'] else None
    if address_uuid:
        update_person_address(requests, info, openmrs_config, person_uuid,
                              address_uuid)
    else:
        create_person_address(requests, info, openmrs_config, person_uuid)

    sync_person_attributes(requests, info, openmrs_config, person_uuid,
                           patient['person']['attributes'])

    return person_uuid
Exemple #4
0
def sync_openmrs_patient(requests, info, form_json, form_question_values, openmrs_config):
    patient = get_patient(requests, info, openmrs_config)
    if patient is None:
        raise ValueError('CommCare patient was not found in OpenMRS')
    person_uuid = patient['person']['uuid']
    logger.debug('OpenMRS patient found: ', person_uuid)
    update_person_properties(requests, info, openmrs_config, person_uuid)

    name_uuid = patient['person']['preferredName']['uuid']
    update_person_name(requests, info, openmrs_config, person_uuid, name_uuid)

    address_uuid = patient['person']['preferredAddress']['uuid'] if patient['person']['preferredAddress'] else None
    if address_uuid:
        update_person_address(requests, info, openmrs_config, person_uuid, address_uuid)
    else:
        create_person_address(requests, info, openmrs_config, person_uuid)

    sync_person_attributes(requests, info, openmrs_config, person_uuid, patient['person']['attributes'])

    create_visits(requests, info, form_json, form_question_values, openmrs_config, person_uuid)

    return OpenmrsResponse(200, 'OK')
Exemple #5
0
def send_openmrs_data(requests, domain, form_json, openmrs_config,
                      case_trigger_infos):
    """
    Updates an OpenMRS patient and (optionally) creates visits.

    This involves several requests to the `OpenMRS REST Web Services`_. If any of those requests fail, we want to
    roll back previous changes to avoid inconsistencies in OpenMRS. To do this we define a workflow of tasks we
    want to do. Each workflow task has a rollback task. If a task fails, all previous tasks are rolled back in
    reverse order.

    :return: A response-like object that can be used by Repeater.handle_response(),
             RepeatRecord.handle_success() and RepeatRecord.handle_failure()


    .. _OpenMRS REST Web Services: https://wiki.openmrs.org/display/docs/REST+Web+Services+API+For+Clients
    """
    warnings = []
    errors = []
    for info in case_trigger_infos:
        assert isinstance(info, CaseTriggerInfo)
        try:
            patient = get_patient(requests, domain, info, openmrs_config)
        except (RequestException, HTTPError) as err:
            errors.append(
                _("Unable to create an OpenMRS patient for case "
                  f"{info.case_id!r}: {err}"))
            continue
        if patient is None:
            warnings.append(
                f"CommCare case '{info.case_id}' was not matched to a "
                f"patient in OpenMRS instance '{requests.base_url}'.")
            continue

        # case_trigger_infos are info about all of the cases
        # created/updated by the form. Execute a separate workflow to
        # update each patient.
        workflow = [
            # Update name first. If the current name in OpenMRS fails
            # validation, other API requests will be rejected.
            UpdatePersonNameTask(requests, info, openmrs_config,
                                 patient['person']),
            # Update identifiers second. If a current identifier fails
            # validation, other API requests will be rejected.
            SyncPatientIdentifiersTask(requests, info, openmrs_config,
                                       patient),
            # Now we should be able to update the rest.
            UpdatePersonPropertiesTask(requests, info, openmrs_config,
                                       patient['person']),
            SyncPersonAttributesTask(requests, info, openmrs_config,
                                     patient['person']['uuid'],
                                     patient['person']['attributes']),
        ]
        if patient['person']['preferredAddress']:
            workflow.append(
                UpdatePersonAddressTask(requests, info, openmrs_config,
                                        patient['person']))
        else:
            workflow.append(
                CreatePersonAddressTask(requests, info, openmrs_config,
                                        patient['person']))
        workflow.append(
            CreateVisitsEncountersObsTask(requests, domain, info, form_json,
                                          openmrs_config,
                                          patient['person']['uuid']), )

        errors.extend(execute_workflow(workflow))

    if errors:
        requests.notify_error(
            f'Errors encountered sending OpenMRS data: {errors}')
        # If the form included multiple patients, some workflows may
        # have succeeded, but don't say everything was OK if any
        # workflows failed. (Of course most forms will only involve one
        # case, so one workflow.)
        return OpenmrsResponse(
            400, 'Bad Request',
            "Errors: " + pformat_json([str(e) for e in errors]))

    if warnings:
        return OpenmrsResponse(
            201, "Accepted",
            "Warnings: " + pformat_json([str(e) for e in warnings]))

    return OpenmrsResponse(200, "OK")
Exemple #6
0
def send_openmrs_data(requests, domain, form_json, openmrs_config, case_trigger_infos, form_question_values):
    """
    Updates an OpenMRS patient and (optionally) creates visits.

    This involves several requests to the `OpenMRS REST Web Services`_. If any of those requests fail, we want to
    roll back previous changes to avoid inconsistencies in OpenMRS. To do this we define a workflow of tasks we
    want to do. Each workflow task has a rollback task. If a task fails, all previous tasks are rolled back in
    reverse order.

    :return: A response-like object that can be used by Repeater.handle_response


    .. _OpenMRS REST Web Services: https://wiki.openmrs.org/display/docs/REST+Web+Services+API+For+Clients
    """
    errors = []
    for info in case_trigger_infos:
        assert isinstance(info, CaseTriggerInfo)
        patient = get_patient(requests, domain, info, openmrs_config)
        if patient is None:
            errors.append('Warning: CommCare case "{}" was not found in OpenMRS'.format(info.case_id))
            continue

        # case_trigger_infos are info about all of the cases
        # created/updated by the form. Execute a separate workflow to
        # update each patient.
        workflow = [
            # Update name first. If the current name in OpenMRS fails
            # validation, other API requests will be rejected.
            UpdatePersonNameTask(requests, info, openmrs_config, patient['person']),
            # Update identifiers second. If a current identifier fails
            # validation, other API requests will be rejected.
            SyncPatientIdentifiersTask(requests, info, openmrs_config, patient),
            # Now we should be able to update the rest.
            UpdatePersonPropertiesTask(requests, info, openmrs_config, patient['person']),
            SyncPersonAttributesTask(
                requests, info, openmrs_config, patient['person']['uuid'], patient['person']['attributes']
            ),
        ]
        if patient['person']['preferredAddress']:
            workflow.append(
                UpdatePersonAddressTask(requests, info, openmrs_config, patient['person'])
            )
        else:
            workflow.append(
                CreatePersonAddressTask(requests, info, openmrs_config, patient['person'])
            )
        workflow.append(
            CreateVisitsEncountersObsTask(
                requests, domain, info, form_json, form_question_values, openmrs_config, patient['person']['uuid']
            ),
        )

        errors.extend(
            execute_workflow(workflow)
        )

    if errors:
        logger.error('Errors encountered sending OpenMRS data: %s', errors)
        # If the form included multiple patients, some workflows may
        # have succeeded, but don't say everything was OK if any
        # workflows failed. (Of course most forms will only involve one
        # case, so one workflow.)
        return OpenmrsResponse(400, 'Bad Request', pformat_json([str(e) for e in errors]))
    else:
        return OpenmrsResponse(200, 'OK', '')
Exemple #7
0
def send_openmrs_data(requests, domain, form_json, openmrs_config, case_trigger_infos, form_question_values):
    """
    Updates an OpenMRS patient and (optionally) creates visits.

    This involves several requests to the `OpenMRS REST Web Services`_. If any of those requests fail, we want to
    roll back previous changes to avoid inconsistencies in OpenMRS. To do this we define a workflow of tasks we
    want to do. Each workflow task has a rollback task. If a task fails, all previous tasks are rolled back in
    reverse order.

    :return: A response-like object that can be used by Repeater.handle_response


    .. _OpenMRS REST Web Services: https://wiki.openmrs.org/display/docs/REST+Web+Services+API+For+Clients
    """
    errors = []
    for info in case_trigger_infos:
        assert isinstance(info, CaseTriggerInfo)
        patient = get_patient(requests, domain, info, openmrs_config)
        if patient is None:
            errors.append('Warning: CommCare case "{}" was not found in OpenMRS'.format(info.case_id))
            continue

        # case_trigger_infos are info about all of the cases
        # created/updated by the form. Execute a separate workflow to
        # update each patient.
        workflow = [
            # Update name first. If the current name in OpenMRS fails
            # validation, other API requests will be rejected.
            UpdatePersonNameTask(requests, info, openmrs_config, patient['person']),
            # Update identifiers second. If a current identifier fails
            # validation, other API requests will be rejected.
            SyncPatientIdentifiersTask(requests, info, openmrs_config, patient),
            # Now we should be able to update the rest.
            UpdatePersonPropertiesTask(requests, info, openmrs_config, patient['person']),
            SyncPersonAttributesTask(
                requests, info, openmrs_config, patient['person']['uuid'], patient['person']['attributes']
            ),
        ]
        if patient['person']['preferredAddress']:
            workflow.append(
                UpdatePersonAddressTask(requests, info, openmrs_config, patient['person'])
            )
        else:
            workflow.append(
                CreatePersonAddressTask(requests, info, openmrs_config, patient['person'])
            )
        workflow.append(
            CreateVisitsEncountersObsTask(
                requests, domain, info, form_json, form_question_values, openmrs_config, patient['person']['uuid']
            ),
        )

        errors.extend(
            execute_workflow(workflow)
        )

    if errors:
        logger.error('Errors encountered sending OpenMRS data: %s', errors)
        # If the form included multiple patients, some workflows may
        # have succeeded, but don't say everything was OK if any
        # workflows failed. (Of course most forms will only involve one
        # case, so one workflow.)
        return OpenmrsResponse(400, 'Bad Request', pformat_json([str(e) for e in errors]))
    else:
        return OpenmrsResponse(200, 'OK', '')