Class: DdeClient::DdeService
- Inherits:
-
Object
- Object
- DdeClient::DdeService
- Includes:
- ModelUtils
- Defined in:
- app/services/dde_client/dde_service.rb
Defined Under Namespace
Classes: DdeError
Constant Summary collapse
- Dde_CONFIG_PATH =
Rails.root.join('config', 'dde.yml')
- LOGGER =
Rails.logger
- PATIENT_SEARCH_RESULTS_LIMIT =
Limit all find queries for local patients to this
10
Instance Attribute Summary collapse
-
#visit_type ⇒ Object
Returns the value of attribute visit_type.
Class Method Summary collapse
Instance Method Summary collapse
-
#create_patient(patient) ⇒ Object
Registers local OpenMRS patient in Dde.
-
#create_patient_footprint(patient, date = nil, creator_id = nil) ⇒ Object
Pushes a footprint for patient in current visit_type to Dde.
-
#dde_patient_to_local_person(dde_patient) ⇒ Object
Converts a dde_patient object into an object that can be passed to the person_service to create or update a person.
- #find_patient_updates(local_patient_id) ⇒ Object
- #find_patients_by_name_and_gender(given_name, family_name, gender) ⇒ Object
- #find_patients_by_npid(npid) ⇒ Object
-
#import_patients_by_doc_id(doc_id) ⇒ Object
Import patients from Dde using doc id.
-
#import_patients_by_name_and_gender(given_name, family_name, gender) ⇒ Object
Similar to import_patients_by_npid but uses name and gender instead of npid.
-
#import_patients_by_npid(npid) ⇒ Object
Imports patients from Dde to the local database.
-
#initialize(visit_type:) ⇒ DdeService
constructor
A new instance of DdeService.
-
#match_patients_by_demographics(family_name:, given_name:, birthdate:, gender:, home_district:, home_traditional_authority:, home_village:, birthdate_estimated: 0) ⇒ Object
Matches patients using a bunch of demographics.
-
#merge_patients(primary_patients_ids, secondary_patient_ids) ⇒ Object
Trigger a merge of patients in Dde.
- #reassign_patient_npid(patient_ids) ⇒ Object
- #remaining_npids ⇒ Object
-
#save_remote_patient(remote_patient) ⇒ Object
Convert a Dde person to an openmrs person.
- #test_connection ⇒ Object
-
#update_local_patient(patient, update_npid: false) ⇒ Object
Updates local patient with demographics currently in Dde.
-
#update_patient(patient) ⇒ Object
Updates patient demographics in Dde.
- #void_patient(patient, reason) ⇒ Object
Methods included from ModelUtils
#concept, #concept_id_to_name, #concept_name, #concept_name_to_id, #drug, #encounter_type, #global_property, #order_type, #patient_identifier_type, #report_type, #user_property
Constructor Details
#initialize(visit_type:) ⇒ DdeService
Returns a new instance of DdeService.
18 19 20 21 22 |
# File 'app/services/dde_client/dde_service.rb', line 18 def initialize(visit_type:) raise InvalidParameterError, 'VisitType (visit_type_id) is required' unless visit_type @visit_type = visit_type end |
Instance Attribute Details
#visit_type ⇒ Object
Returns the value of attribute visit_type.
14 15 16 |
# File 'app/services/dde_client/dde_service.rb', line 14 def visit_type @visit_type end |
Class Method Details
.dde_enabled? ⇒ Boolean
24 25 26 27 28 29 30 31 32 33 |
# File 'app/services/dde_client/dde_service.rb', line 24 def self.dde_enabled? property = GlobalProperty.find_by_property('dde_enabled')&.property_value return false unless property case property when /true/i then true when /false/i then false else raise "Invalid value for property dde_enabled: #{property.property_value}" end end |
Instance Method Details
#create_patient(patient) ⇒ Object
Registers local OpenMRS patient in Dde
On success patient get two identifiers under the types ‘Dde person document ID’ and ‘National id’. The ‘Dde person document ID’ is the patient’s record ID in the local Dde instance and the ‘National ID’ is the national unique identifier for the patient.
55 56 57 |
# File 'app/services/dde_client/dde_service.rb', line 55 def create_patient(patient) push_local_patient_to_dde(patient) end |
#create_patient_footprint(patient, date = nil, creator_id = nil) ⇒ Object
Pushes a footprint for patient in current visit_type to Dde
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'app/services/dde_client/dde_service.rb', line 97 def create_patient_footprint(patient, date = nil, creator_id = nil) LOGGER.debug("Pushing footprint to Dde for patient ##{patient.patient_id}") doc_id = find_patient_doc_id(patient) unless doc_id LOGGER.debug("Patient ##{patient.patient_id} is not a Dde patient") return end response, status = dde_client.post('update_footprint', person_uuid: doc_id, location_id: Location.current_location_health_center.location_id, visit_type_id: visit_type.id, encounter_datetime: date || Date.tody, user_id: creator_id || User.current.user_id) LOGGER.warn("Failed to push patient footprint to Dde: #{status} - #{response}") unless status == 200 end |
#dde_patient_to_local_person(dde_patient) ⇒ Object
Converts a dde_patient object into an object that can be passed to the person_service to create or update a person.
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
# File 'app/services/dde_client/dde_service.rb', line 293 def dde_patient_to_local_person(dde_patient) attributes = dde_patient.fetch('attributes') # ActiveSupport::HashWithIndifferentAccess.new( # birthdate: dde_patient.fetch('birthdate'), # birthdate_estimated: dde_patient.fetch('birthdate_estimated'), # gender: dde_patient.fetch('gender'), # given_name: dde_patient.fetch('given_name'), # family_name: dde_patient.fetch('family_name'), # middle_name: dde_patient.fetch('middle_name'), # home_village: attributes.fetch('home_village'), # home_traditional_authority: attributes.fetch('home_traditional_authority'), # home_district: attributes.fetch('home_district'), # current_village: attributes.fetch('current_village'), # current_traditional_authority: attributes.fetch('current_traditional_authority'), # current_district: attributes.fetch('current_district') # # cell_phone_number: attributes.fetch('cellphone_number'), # # occupation: attributes.fetch('occupation') # ) { birthdate: dde_patient.fetch('birthdate'), birthdate_estimated: dde_patient.fetch('birthdate_estimated'), gender: dde_patient.fetch('gender'), names: [ { given_name: dde_patient.fetch('given_name'), family_name: dde_patient.fetch('family_name'), middle_name: dde_patient.fetch('middle_name') } ], addresses: [ { address1: attributes.fetch('home_district'), address3: attributes.fetch('current_district'), county_district: attributes.fetch('home_traditional_authority'), state_province: attributes.fetch('current_traditional_authority'), address2: attributes.fetch('home_village'), city_village: attributes.fetch('current_village') } ] } end |
#find_patient_updates(local_patient_id) ⇒ Object
191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'app/services/dde_client/dde_service.rb', line 191 def find_patient_updates(local_patient_id) dde_doc_id_type = PatientIdentifierType.where(name: 'Dde Person Document ID') doc_id = PatientIdentifier.find_by(patient_id: local_patient_id, identifier_type: dde_doc_id_type) &.identifier return nil unless doc_id remote_patient = find_remote_patients_by_doc_id(doc_id).first return nil unless remote_patient Matcher.find_differences(Person.find(local_patient_id), remote_patient) rescue DdeError => e Rails.logger.warn("Check for Dde patient updates failed: #{e.}") nil end |
#find_patients_by_name_and_gender(given_name, family_name, gender) ⇒ Object
178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'app/services/dde_client/dde_service.rb', line 178 def find_patients_by_name_and_gender(given_name, family_name, gender) locals = [] begin locals = patient_service.find_patients_by_name_and_gender(given_name, family_name, gender).limit(PATIENT_SEARCH_RESULTS_LIMIT) remotes = find_remote_patients_by_name_and_gender(given_name, family_name, gender) package_patients(locals, remotes) rescue StandardError => e Rails.logger.warn("Error packaging patients: #{e.}") package_patients(locals, []) end end |
#find_patients_by_npid(npid) ⇒ Object
171 172 173 174 175 176 |
# File 'app/services/dde_client/dde_service.rb', line 171 def find_patients_by_npid(npid) locals = patient_service.find_patients_by_npid(npid).limit(PATIENT_SEARCH_RESULTS_LIMIT) remotes = find_remote_patients_by_npid(npid) package_patients(locals, remotes, auto_push_singular_local: true) end |
#import_patients_by_doc_id(doc_id) ⇒ Object
Import patients from Dde using doc id
141 142 143 144 145 146 147 |
# File 'app/services/dde_client/dde_service.rb', line 141 def import_patients_by_doc_id(doc_id) doc_id_type = patient_identifier_type('Dde person document id') locals = patient_service.find_patients_by_identifier(doc_id, doc_id_type).limit(PATIENT_SEARCH_RESULTS_LIMIT) remotes = find_remote_patients_by_doc_id(doc_id) import_remote_patient(locals, remotes) end |
#import_patients_by_name_and_gender(given_name, family_name, gender) ⇒ Object
Similar to import_patients_by_npid but uses name and gender instead of npid
159 160 161 162 163 164 165 166 167 168 169 |
# File 'app/services/dde_client/dde_service.rb', line 159 def import_patients_by_name_and_gender(given_name, family_name, gender) locals = patient_service.find_patients_by_name_and_gender(given_name, family_name, gender).limit(PATIENT_SEARCH_RESULTS_LIMIT) remotes = begin find_remote_patients_by_name_and_gender(given_name, family_name, gender) rescue StandardError [] end import_remote_patient(locals, remotes) end |
#import_patients_by_npid(npid) ⇒ Object
Imports patients from Dde to the local database
150 151 152 153 154 155 156 |
# File 'app/services/dde_client/dde_service.rb', line 150 def import_patients_by_npid(npid) doc_id_type = patient_identifier_type('National id') locals = patient_service.find_patients_by_identifier(npid, doc_id_type).limit(PATIENT_SEARCH_RESULTS_LIMIT) remotes = find_remote_patients_by_npid(npid) import_remote_patient(locals, remotes) end |
#match_patients_by_demographics(family_name:, given_name:, birthdate:, gender:, home_district:, home_traditional_authority:, home_village:, birthdate_estimated: 0) ⇒ Object
Matches patients using a bunch of demographics
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'app/services/dde_client/dde_service.rb', line 207 def match_patients_by_demographics(family_name:, given_name:, birthdate:, gender:, home_district:, home_traditional_authority:, home_village:, birthdate_estimated: 0) response, status = dde_client.post( 'search/people', family_name: family_name, given_name: given_name, gender: gender, birthdate: birthdate, birthdate_estimated: !birthdate_estimated.zero?, attributes: { home_district: home_district, home_traditional_authority: , home_village: home_village } ) raise DdeError, "Dde patient search failed: #{status} - #{response}" unless status == 200 response.collect do |match| doc_id = match['person']['id'] patient = patient_service.find_patients_by_identifier( doc_id, patient_identifier_type('Dde person document id') ).first match['person']['patient_id'] = patient&.id match end end |
#merge_patients(primary_patients_ids, secondary_patient_ids) ⇒ Object
Trigger a merge of patients in Dde
236 237 238 |
# File 'app/services/dde_client/dde_service.rb', line 236 def merge_patients(primary_patients_ids, secondary_patient_ids) merging_service.merge_patients(primary_patients_ids, secondary_patient_ids) end |
#reassign_patient_npid(patient_ids) ⇒ Object
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'app/services/dde_client/dde_service.rb', line 240 def reassign_patient_npid(patient_ids) patient_id = patient_ids['patient_id'] doc_id = patient_ids['doc_id'] raise InvalidParameterError, 'patient_id and/or doc_id required' if patient_id.blank? && doc_id.blank? if doc_id.blank? # Only have patient id thus we have patient locally only return push_local_patient_to_dde(Patient.find(patient_ids['patient_id'])) end # NOTE: Fail patient retrieval as early as possible before making any # changes to Dde (ie if patient_id does not exist) patient = patient_id.blank? ? nil : Patient.find(patient_id) # We have a doc_id thus we can re-assign npid in Dde # Check if person if available in Dde if not add person using doc_id response, status = dde_client.post('search_by_doc_id', doc_id: doc_id) if !response.blank? && status.to_i == 200 response, status = dde_client.post('reassign_npid', doc_id: doc_id) elsif response.blank? && status.to_i == 200 return push_local_patient_to_dde(Patient.find(patient_ids['patient_id'])) end unless status == 200 && !response.empty? # The Dde's reassign_npid end point responds with a 200 - OK but returns # an empty object when patient with given doc_id is not found. raise DdeError, "Failed to reassign npid: Dde Response => #{status} - #{response}" end return save_remote_patient(response) unless patient merging_service.link_local_to_remote_patient(patient, response) end |
#remaining_npids ⇒ Object
59 60 61 62 63 64 |
# File 'app/services/dde_client/dde_service.rb', line 59 def remaining_npids response, status = dde_client.get("/location_npid_status?location_id=#{Location.current_location.id}") raise DdeError, "Failed to fetch remaining npids: #{status} - #{response}" unless status == 200 response end |
#save_remote_patient(remote_patient) ⇒ Object
Convert a Dde person to an openmrs person.
NOTE: This creates a person on the database.
278 279 280 281 282 283 284 285 286 287 288 |
# File 'app/services/dde_client/dde_service.rb', line 278 def save_remote_patient(remote_patient) LOGGER.debug "Converting Dde person to openmrs: #{remote_patient}" params = dde_patient_to_local_person(remote_patient) Person.transaction do person = person_service.create_person(params) patient = Patient.create(patient_id: person.id) merging_service.link_local_to_remote_patient(patient, remote_patient) end end |
#test_connection ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'app/services/dde_client/dde_service.rb', line 35 def test_connection response = { connection_available: false, message: 'No connection to Dde', status: 500 } begin result, status = dde_client response[:connection_available] = status == 200 response[:message] = result rescue StandardError => exception LOGGER.error "Failed to connect to Dde: #{exception.}" response[:message] = exception. end response end |
#update_local_patient(patient, update_npid: false) ⇒ Object
Updates local patient with demographics currently in Dde.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'app/services/dde_client/dde_service.rb', line 116 def update_local_patient(patient, update_npid: false) doc_id = patient_doc_id(patient) unless doc_id Rails.logger.warn("No Dde doc_id found for patient ##{patient.patient_id}") push_local_patient_to_dde(patient) return patient end dde_patient = find_remote_patients_by_doc_id(doc_id).first unless dde_patient Rails.logger.warn("Couldn't find patient ##{patient.patient_id} in Dde by doc_id ##{doc_id}") push_local_patient_to_dde(patient) return patient end if update_npid merging_service.link_local_to_remote_patient(patient, dde_patient) return patient end person_service.update_person(patient.person, dde_patient_to_local_person(dde_patient)) patient end |
#update_patient(patient) ⇒ Object
Updates patient demographics in Dde.
Local patient is not affected in anyway by the update
86 87 88 89 90 91 92 93 |
# File 'app/services/dde_client/dde_service.rb', line 86 def update_patient(patient) dde_patient = openmrs_to_dde_patient(patient) response, status = dde_client.post('update_person', dde_patient) raise DdeError, "Failed to update person in Dde: #{response}" unless status == 200 patient end |
#void_patient(patient, reason) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'app/services/dde_client/dde_service.rb', line 66 def void_patient(patient, reason) raise ArgumentError, "Can't request a Dde void for a non-voided patient" unless patient.voided? raise ArgumentError, 'void_reason is required' if reason.blank? doc_id = PatientIdentifier.unscoped .where(identifier_type: dde_doc_id_type, patient: patient) .order(:date_voided) .last &.identifier return patient unless doc_id response, status = dde_client.delete("void_person/#{doc_id}?void_reason=#{reason}") raise DdeError, "Failed to void person in Dde: #{status} - #{response}" unless status == 200 patient end |