Beispiel #1
0
 def test_wrap_subclass(self):
     """
     PatientFinder.wrap() should return the type of subclass determined by "doc_type"
     """
     finder = PatientFinder.wrap({
         'doc_type': 'WeightedPropertyPatientFinder',
         'searchable_properties': [],
         'property_weights': [],
     })
     self.assertIsInstance(finder, WeightedPropertyPatientFinder)
Beispiel #2
0
 def test_create_missing_default(self):
     """
     PatientFinder.create_missing should default to false
     """
     finder = PatientFinder.wrap({
         'doc_type': 'WeightedPropertyPatientFinder',
         'searchable_properties': [],
         'property_weights': [],
     })
     self.assertFalse(finder.create_missing)
Beispiel #3
0
 def test_create_missing_default(self):
     """
     PatientFinder.create_missing should default to false
     """
     finder = PatientFinder.wrap({
         'doc_type': 'WeightedPropertyPatientFinder',
         'searchable_properties': [],
         'property_weights': [],
     })
     self.assertFalse(finder.create_missing)
Beispiel #4
0
 def test_wrap_subclass(self):
     """
     PatientFinder.wrap() should return the type of subclass determined by "doc_type"
     """
     finder = PatientFinder.wrap({
         'doc_type': 'WeightedPropertyPatientFinder',
         'searchable_properties': [],
         'property_weights': [],
     })
     self.assertIsInstance(finder, WeightedPropertyPatientFinder)
Beispiel #5
0
 def test_create_missing_true(self):
     finder = PatientFinder.wrap({
         'doc_type': 'WeightedPropertyPatientFinder',
         'searchable_properties': [],
         'property_weights': [],
         'create_missing': True,
     })
     self.assertEqual(finder.create_missing, {
         "external_data_type": OPENMRS_DATA_TYPE_BOOLEAN,
         "value": 'True',
     })
Beispiel #6
0
 def test_create_missing_default(self):
     """
     PatientFinder.create_missing should default to false
     """
     finder = PatientFinder.wrap({
         'doc_type': 'WeightedPropertyPatientFinder',
         'searchable_properties': [],
         'property_weights': [],
     })
     self.assertEqual(finder.create_missing, {
         "external_data_type": OPENMRS_DATA_TYPE_BOOLEAN,
         "value": 'False',
     })
Beispiel #7
0
 def test_create_missing_true(self):
     finder = PatientFinder.wrap({
         'doc_type': 'WeightedPropertyPatientFinder',
         'searchable_properties': [],
         'property_weights': [],
         'create_missing': True,
     })
     self.assertEqual(
         finder.create_missing,
         ConstantString(
             external_data_type=OPENMRS_DATA_TYPE_BOOLEAN,
             commcare_data_type=None,
             direction=None,
             doc_type='ConstantString',
             value='True',
         )
     )
Beispiel #8
0
                    identifier = response.json()['identifiers'][0]
                except (ValueError, IndexError, KeyError):
                    raise OpenmrsException()
            except OpenmrsException:
                requests.notify_exception(
                    'OpenMRS idgen module returned an unexpected response',
                    details=
                    (f'OpenMRS idgen module at "{response.url}" '
                     f'returned an unexpected response {response.status_code}: \r\n'
                     f'{response.content}'))
    return identifier


def find_or_create_patient(requests, domain, info, openmrs_config):
    case = CaseAccessors(domain).get_case(info.case_id)
    patient_finder = PatientFinder.wrap(
        openmrs_config.case_config.patient_finder)
    if patient_finder is None:
        return
    patients = patient_finder.find_patients(requests, case,
                                            openmrs_config.case_config)
    if len(patients) == 1:
        patient, = patients
    elif not patients and patient_finder.create_missing.get_value(info):
        patient = create_patient(requests, info, openmrs_config.case_config)
    else:
        # If PatientFinder can't narrow down the number of candidate
        # patients, don't guess. Just admit that we don't know.
        return None
    try:
        save_match_ids(case, openmrs_config.case_config, patient)
    except DuplicateCaseMatch as err:
class OpenmrsCaseConfig(DocumentSchema):

    # "patient_identifiers": {
    #     "e2b966d0-1d5f-11e0-b929-000c29ad1d07": {
    #         "case_property": "nid"
    #     },
    #     "uuid": {
    #         "case_property": "openmrs_uuid",
    #     }
    # }
    patient_identifiers = DictProperty()

    # The patient_identifiers that are considered reliable
    # "match_on_ids": ["uuid", "e2b966d0-1d5f-11e0-b929-000c29ad1d07",
    match_on_ids = ListProperty()

    # "person_properties": {
    #     "gender": {
    #         "case_property": "gender"
    #     },
    #     "birthdate": {
    #         "case_property": "dob"
    #     }
    # }
    person_properties = DictProperty()

    # "patient_finder": {
    #     "doc_type": "WeightedPropertyPatientFinder",
    #     "searchable_properties": ["nid", "family_name"],
    #     "property_weights": [
    #         {"case_property": "nid", "weight": 0.9},
    #         // if "match_type" is not given it defaults to "exact"
    #         {"case_property": "family_name", "weight": 0.4},
    #         {
    #             "case_property": "given_name",
    #             "weight": 0.3,
    #             "match_type": "levenshtein",
    #             // levenshtein function takes edit_distance / len
    #             "match_params": [0.2]
    #             // i.e. 0.2 (20%) is one edit for every 5 characters
    #             // e.g. "Riyaz" matches "Riaz" but not "Riazz"
    #         },
    #         {"case_property": "city", "weight": 0.2},
    #         {
    #             "case_property": "dob",
    #             "weight": 0.3,
    #             "match_type": "days_diff",
    #             // days_diff matches based on days difference from given date
    #             "match_params": [364]
    #         }
    #     ]
    # }
    patient_finder = PatientFinder(required=False)

    # "person_preferred_name": {
    #     "givenName": {
    #         "case_property": "given_name"
    #     },
    #     "middleName": {
    #         "case_property": "middle_name"
    #     },
    #     "familyName": {
    #         "case_property": "family_name"
    #     }
    # }
    person_preferred_name = DictProperty()

    # "person_preferred_address": {
    #     "address1": {
    #         "case_property": "address_1"
    #     },
    #     "address2": {
    #         "case_property": "address_2"
    #     },
    #     "cityVillage": {
    #         "case_property": "city"
    #     }
    # }
    person_preferred_address = DictProperty()

    # "person_attributes": {
    #     "c1f4239f-3f10-11e4-adec-0800271c1b75": {
    #         "case_property": "caste"
    #     },
    #     "c1f455e7-3f10-11e4-adec-0800271c1b75": {
    #         "case_property": "class",
    #         "value_map": {
    #             "sc": "c1fcd1c6-3f10-11e4-adec-0800271c1b75",
    #             "general": "c1fc20ab-3f10-11e4-adec-0800271c1b75",
    #             "obc": "c1fb51cc-3f10-11e4-adec-0800271c1b75",
    #             "other_caste": "c207073d-3f10-11e4-adec-0800271c1b75",
    #             "st": "c20478b6-3f10-11e4-adec-0800271c1b75"
    #         }
    #     }
    # }
    person_attributes = DictProperty()

    # Create cases when importing via the Atom feed
    import_creates_cases = BooleanProperty(default=True)
    # If we ever need to disable updating cases, ``import_updates_cases``
    # could be added here. Similarly, we could replace
    # ``patient_finder.create_missing`` with ``export_creates_patients``
    # and ``export_updates_patients``

    @classmethod
    def wrap(cls, data):
        if 'id_matchers' in data:
            # Convert legacy id_matchers to patient_identifiers. e.g.
            #     [{'doc_type': 'IdMatcher'
            #       'identifier_type_id': 'e2b966d0-1d5f-11e0-b929-000c29ad1d07',
            #       'case_property': 'nid'}]
            # to
            #     {'e2b966d0-1d5f-11e0-b929-000c29ad1d07': {'doc_type': 'CaseProperty', 'case_property': 'nid'}},
            patient_identifiers = {
                m['identifier_type_id']: {
                    'doc_type': 'CaseProperty',
                    'case_property': m['case_property']
                }
                for m in data['id_matchers']
            }
            data['patient_identifiers'] = patient_identifiers
            data['match_on_ids'] = list(patient_identifiers)
            data.pop('id_matchers')
        # Set default data types for known properties
        for property_, value_source in chain(
                data.get('person_properties', {}).items(),
                data.get('person_preferred_name', {}).items(),
                data.get('person_preferred_address', {}).items(),
        ):
            data_type = OPENMRS_PROPERTIES[property_]
            value_source.setdefault('external_data_type', data_type)
        return super(OpenmrsCaseConfig, cls).wrap(data)
Beispiel #10
0
class OpenmrsCaseConfig(DocumentSchema):

    # "patient_identifiers": {
    #     "e2b966d0-1d5f-11e0-b929-000c29ad1d07": {
    #         "doc_type": "CaseProperty",
    #         "case_property": "nid"
    #     },
    #     "uuid": {
    #         "doc_type": "CaseProperty",
    #         "case_property": "openmrs_uuid",
    #     }
    # }
    patient_identifiers = SchemaDictProperty(ValueSource)

    # The patient_identifiers that are considered reliable
    # "match_on_ids": ["uuid", "e2b966d0-1d5f-11e0-b929-000c29ad1d07",
    match_on_ids = ListProperty()

    # "person_properties": {
    #     "gender": {
    #         "doc_type": "CaseProperty",
    #         "case_property": "gender"
    #     },
    #     "birthdate": {
    #         "doc_type": "CaseProperty",
    #         "case_property": "dob"
    #     }
    # }
    person_properties = SchemaDictProperty(ValueSource)

    # "patient_finder": {
    #     "doc_type": "WeightedPropertyPatientFinder",
    #     "searchable_properties": ["nid", "family_name"],
    #     "property_weights": [
    #         {"case_property": "nid", "weight": 0.9},
    #         {"case_property": "family_name", "weight": 0.4},
    #         {"case_property": "given_name", "weight": 0.3},
    #         {"case_property": "city", "weight": 0.2},
    #         {"case_property": "dob", "weight": 0.3}
    #     ]
    # }
    patient_finder = PatientFinder(required=False)

    # "person_preferred_name": {
    #     "givenName": {
    #         "doc_type": "CaseProperty",
    #         "case_property": "given_name"
    #     },
    #     "middleName": {
    #         "doc_type": "CaseProperty",
    #         "case_property": "middle_name"
    #     },
    #     "familyName": {
    #         "doc_type": "CaseProperty",
    #         "case_property": "family_name"
    #     }
    # }
    person_preferred_name = SchemaDictProperty(ValueSource)

    # "person_preferred_address": {
    #     "address1": {
    #         "doc_type": "CaseProperty",
    #         "case_property": "address_1"
    #     },
    #     "address2": {
    #         "doc_type": "CaseProperty",
    #         "case_property": "address_2"
    #     },
    #     "cityVillage": {
    #         "doc_type": "CaseProperty",
    #         "case_property": "city"
    #     }
    # }
    person_preferred_address = SchemaDictProperty(ValueSource)

    # "person_attributes": {
    #     "c1f4239f-3f10-11e4-adec-0800271c1b75": {
    #         "doc_type": "CaseProperty",
    #         "case_property": "caste"
    #     },
    #     "c1f455e7-3f10-11e4-adec-0800271c1b75": {
    #         "doc_type": "CasePropertyMap",
    #         "case_property": "class",
    #         "value_map": {
    #             "sc": "c1fcd1c6-3f10-11e4-adec-0800271c1b75",
    #             "general": "c1fc20ab-3f10-11e4-adec-0800271c1b75",
    #             "obc": "c1fb51cc-3f10-11e4-adec-0800271c1b75",
    #             "other_caste": "c207073d-3f10-11e4-adec-0800271c1b75",
    #             "st": "c20478b6-3f10-11e4-adec-0800271c1b75"
    #         }
    #     }
    # }
    person_attributes = SchemaDictProperty(ValueSource)

    @classmethod
    def wrap(cls, data):
        if 'id_matchers' in data:
            # Convert id_matchers to patient_identifiers. e.g.
            #     [{'doc_type': 'IdMatcher'
            #       'identifier_type_id': 'e2b966d0-1d5f-11e0-b929-000c29ad1d07',
            #       'case_property': 'nid'}]
            # to
            #     {'e2b966d0-1d5f-11e0-b929-000c29ad1d07': {'doc_type': 'CaseProperty', 'case_property': 'nid'}},
            patient_identifiers = {
                m['identifier_type_id']: {
                    'doc_type': 'CaseProperty',
                    'case_property': m['case_property']
                }
                for m in data['id_matchers']
            }
            data['patient_identifiers'] = patient_identifiers
            data['match_on_ids'] = list(patient_identifiers)
            data.pop('id_matchers')
        return super(OpenmrsCaseConfig, cls).wrap(data)