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)
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)
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', })
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', })
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', ) )
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)
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)