module NHS::ImmunisationsAPI
Public Class Methods
Source
# File app/lib/nhs/immunisations_api.rb, line 26 def create_immunisation(vaccination_record) unless Flipper.enabled?(:imms_api_integration) Rails.logger.info( "Not recording vaccination record to immunisations API as the" \ " feature flag is disabled: #{vaccination_record.id}" ) return end check_vaccination_record_for_create_or_update(vaccination_record) Rails.logger.info( "Recording vaccination record to immunisations API:" \ " #{vaccination_record.id}" ) response, duration = execute_and_time do NHS::API.connection.post( "/immunisation-fhir-api/FHIR/R4/Immunization", vaccination_record.fhir_record.to_json, "Content-Type" => "application/fhir+json" ) end Rails.logger.info( "Create response returned with status #{response.status} in #{duration}s" ) if response.status == 201 vaccination_record.update_columns( nhs_immunisations_api_id: extract_nhs_id(response.headers.fetch("location")), nhs_immunisations_api_synced_at: Time.current, nhs_immunisations_api_primary_source: true, # We would normally retrieve this from the API response, but the NHS # Immunisations API does not return this to us, yet. nhs_immunisations_api_etag: 1 ) else raise "Error recording vaccination record #{vaccination_record.id} to" \ " Immunisations API: unexpected response status" \ " #{response.status}" end rescue Faraday::ClientError => e if (diagnostics = extract_error_diagnostics(e&.response)).present? raise "Error recording vaccination record #{vaccination_record.id} to" \ " Immunisations API: #{diagnostics}" else raise end end
Source
# File app/lib/nhs/immunisations_api.rb, line 202 def delete_immunisation(vaccination_record) unless Flipper.enabled?(:imms_api_integration) Rails.logger.info( "Not deleting vaccination record from immunisations API as the" \ " feature flag is disabled: #{vaccination_record.id}" ) return end if vaccination_record.nhs_immunisations_api_id.blank? raise "Vaccination record #{vaccination_record.id} missing NHS Immunisation ID" end Rails.logger.info( "Deleting vaccination record from immunisations API:" \ " #{vaccination_record.id}" ) nhs_id = vaccination_record.nhs_immunisations_api_id response, duration = execute_and_time do NHS::API.connection.delete( "/immunisation-fhir-api/FHIR/R4/Immunization/#{nhs_id}", nil, { "Accept" => "application/fhir+json", "E-Tag" => vaccination_record.nhs_immunisations_api_etag } ) end Rails.logger.info( "Delete response returned with status #{response.status} in #{duration}s" ) if response.status == 204 # It's not entirely clear if the e-tag should be changed here, but # experiments show (by deleting and then re-creating a vaccination # record with an "update") that it appears that the e-tag is incremented # on the reviving update. vaccination_record.nhs_immunisations_api_id = nil vaccination_record.nhs_immunisations_api_primary_source = nil vaccination_record.nhs_immunisations_api_synced_at = Time.current vaccination_record.save!(touch: false) else raise "Error deleting vaccination record #{vaccination_record.id} from" \ " Immunisations API: unexpected response status" \ " #{response.status}" end rescue Faraday::ClientError => e if (diagnostics = extract_error_diagnostics(e&.response)).present? raise "Error deleting vaccination record #{vaccination_record.id} from" \ " Immunisations API: #{diagnostics}" else raise end end
Source
# File app/lib/nhs/immunisations_api.rb, line 126 def read_immunisation(vaccination_record) nhs_immunisations_api_id = vaccination_record.nhs_immunisations_api_id read_immunisation_by_nhs_immunisations_api_id(nhs_immunisations_api_id) end
Source
# File app/lib/nhs/immunisations_api.rb, line 79 def read_immunisation_by_nhs_immunisations_api_id(nhs_immunisations_api_id) unless Flipper.enabled?(:imms_api_integration) Rails.logger.info( "Not reading vaccination record by NHS Immunisations API ID from immunisations API as the" \ " feature flag is disabled: #{nhs_immunisations_api_id}" ) return end if nhs_immunisations_api_id.blank? raise "ID #{nhs_immunisations_api_id} is blank" end Rails.logger.info( "Reading vaccination record from immunisations API by NHS Immunisations API ID:" \ " #{nhs_immunisations_api_id}" ) response, duration = execute_and_time do NHS::API.connection.get( "/immunisation-fhir-api/FHIR/R4/Immunization/#{nhs_immunisations_api_id}", nil, { "Accept" => "application/fhir+json" } ) end Rails.logger.info( "Read response returned with status #{response.status} in #{duration}s" ) if response.status == 200 FHIR.from_contents(response.body.to_json) else raise "Error reading vaccination record from" \ " Immunisations API by NHS Immunisations API ID #{nhs_immunisations_api_id}: unexpected response" \ " status #{response.status}" end rescue Faraday::ClientError => e if (diagnostics = extract_error_diagnostics(e&.response)).present? raise "Error reading vaccination record from" \ " Immunisations API by NHS Immunisations API ID #{nhs_immunisations_api_id}: #{diagnostics}" else raise end end
Source
# File app/lib/nhs/immunisations_api.rb, line 265 def search_immunisations(patient, programmes:, date_from: nil, date_to: nil) unless Flipper.enabled?(:imms_api_integration) Rails.logger.info( "Not searching for vaccination records in the immunisations API as the" \ "feature flag is disabled: Patient #{patient.id}" ) return end unless should_perform_search_for_patient?(patient) Rails.logger.warn( "Not searching for vaccination records for patient #{patient.id} as" \ " all their teams are upload-only teams" ) return end if programmes.empty? raise "Cannot search for vaccination records in the immunisations API; no programmes provided." end Rails.logger.info( "Searching for vaccination records in immunisations API for patient: #{patient.id}" ) params = { "patient.identifier" => "https://fhir.nhs.uk/Id/nhs-number|#{patient.nhs_number}", "-immunization.target" => programmes .flat_map { it.variants.map(&:snomed_target_disease_name) } .sort .join(","), "-date.from" => date_from&.strftime("%F"), "-date.to" => date_to&.strftime("%F") }.compact response, duration = execute_and_time do NHS::API.connection.get( "/immunisation-fhir-api/FHIR/R4/Immunization", params, "Content-Type" => "application/fhir+json" ) end Rails.logger.info( "Search response returned with status #{response.status} in #{duration}s" ) if response.status == 200 # To create fixtures for testing # File.write("tmp/search_response.json", response.body.to_json) # Rails.logger.debug "Successfully saved" bundle = FHIR.from_contents(response.body.to_json) check_bundle_link_params(bundle, params) check_operation_outcome_entry(bundle) bundle else raise "Error searching for vaccination records for patient #{patient.id} in" \ " Immunisations API: unexpected response status" \ " #{response.status}" end rescue Faraday::ClientError => e if (diagnostics = extract_error_diagnostics(e&.response)).present? raise "Error searching for vaccination records for patient #{patient.id} in" \ " Immunisations API: #{diagnostics}" else raise end end
Source
# File app/lib/nhs/immunisations_api.rb, line 261 def should_perform_search_for_patient?(patient) patient.teams.any?(&:has_point_of_care_access?) end
Source
# File app/lib/nhs/immunisations_api.rb, line 11 def sync_immunisation(vaccination_record) case next_sync_action(vaccination_record) when :create create_immunisation(vaccination_record) when :update update_immunisation(vaccination_record) when :delete delete_immunisation(vaccination_record) else Rails.logger.info( "Vaccination record does not require syncing: #{vaccination_record.id}" ) end end
Source
# File app/lib/nhs/immunisations_api.rb, line 131 def update_immunisation(vaccination_record) unless Flipper.enabled?(:imms_api_integration) Rails.logger.info( "Not updating vaccination record to immunisations API as the" \ " feature flag is disabled: #{vaccination_record.id}" ) return end check_vaccination_record_for_create_or_update(vaccination_record) if vaccination_record.nhs_immunisations_api_id.blank? raise "Vaccination record #{vaccination_record.id} missing NHS Immunisation ID" end if vaccination_record.nhs_immunisations_api_etag.blank? raise "Vaccination record #{vaccination_record.id} missing ETag" end Rails.logger.info( "Updating vaccination record in immunisations API:" \ " #{vaccination_record.id}" ) nhs_id = vaccination_record.nhs_immunisations_api_id response, duration = execute_and_time do NHS::API.connection.put( "/immunisation-fhir-api/FHIR/R4/Immunization/#{nhs_id}", vaccination_record.fhir_record.to_json, { "Content-Type" => "application/fhir+json", "E-Tag" => vaccination_record.nhs_immunisations_api_etag } ) end Rails.logger.info( "Update response returned with status #{response.status} in #{duration}s" ) if response.status == 200 vaccination_record.update_columns( nhs_immunisations_api_synced_at: Time.current, # This simplistic approach is based on the assumption that the NHS # Immunisations API will always simply increment the ETag. Alternative # approaches are to perform a GET after this POST to get the ETag, or # to update our record before we do this POST, which would mean we # don't need to store the ETag at all. # # However at this time it's our understanding that the API will always # increment the ETag, and, practically speaking, it's very unlikely # that our record would be updated by someone else. Hence this simple # approach. nhs_immunisations_api_etag: vaccination_record.nhs_immunisations_api_etag.to_i + 1 ) else raise "Error updating vaccination record #{vaccination_record.id} to" \ " Immunisations API: unexpected response status" \ " #{response.status}" end rescue Faraday::ClientError => e if (diagnostics = extract_error_diagnostics(e&.response)).present? raise "Error updating vaccination record #{vaccination_record.id} to" \ " Immunisations API: #{diagnostics}" else raise end end