Module: DaVinciPASTestKit::PasBundleValidation
- Includes:
- ValidationTest
- Included in:
- DaVinciPASV201::ClientDenialPasResponseBundleValidationTest, DaVinciPASV201::ClientPasRequestBundleValidationTest, DaVinciPASV201::ClientPendedPasInquiryRequestBundleValidationTest, DaVinciPASV201::ClientPendedPasResponseBundleValidationTest, DaVinciPASV201::PASClientDenialSubmitTest, DaVinciPASV201::PASClientPendedSubmitTest, DaVinciPASV201::ServerPasInquiryRequestBundleValidationTest, DaVinciPASV201::ServerPasInquiryResponseBundleValidationTest, DaVinciPASV201::ServerPasRequestBundleValidationTest, DaVinciPASV201::ServerPasResponseBundleValidationTest
- Defined in:
- lib/davinci_pas_test_kit/pas_bundle_validation.rb
Constant Summary collapse
- CLAIM_PROFILE =
'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-claim-update'- CLAIM_RESPONSE_PROFILE =
'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-claimresponse'- CLAIM_INQUIRY_PROFILE =
'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-claim-inquiry'- CLAIM_INQUIRY_RESPONSE_PROFILE =
'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-claiminquiryresponse'
Constants included from ValidationTest
ValidationTest::DAR_CODE_SYSTEM_URL, ValidationTest::DAR_EXTENSION_URL
Instance Method Summary collapse
- #absolute_url(reference, base_url) ⇒ Object
-
#add_declared_profiles(instance, bundle_entry, version) ⇒ Object
Adds declared profiles from an instance (meta.profile) to the resource target profile map.
-
#add_profile_to_instance(instance, profile_url, bundle_entry, version) ⇒ Object
Adds a specific profile URL to an instance in the resource target profile map.
-
#add_resource_target_profile_to_map(resource_full_url, resource, profile_url = nil) ⇒ Object
Adds a resource and its associated profile URL to the resource target profile map.
- #all_scratch_resources ⇒ Object
- #bundle_entry_map(bundle_entry) ⇒ Object
-
#bundle_resources_target_profile_map ⇒ Hash
Returns a hash map where the keys are resource full URLs and the values are a hash containing the resource object and an array of associated profile URLs.
-
#check_presence_of_referenced_resources(target_resource, base_url, resources_to_match) ⇒ Object
This method traverses references within a FHIR resource, ensuring that referenced resources are populated in the bundle.
-
#evaluate_fhirpath_expression(resource, expression) ⇒ Array
Evaluates a FHIRPath expression against a FHIR resource using an external FHIRPath validator.
-
#extract_base_url(absolute_url) ⇒ String
Extracts the base URL from an absolute URL by removing the resource type and ID.
-
#extract_profiles_to_validate_each_entry(bundle_entry, current_entry, current_entry_profile_url, version) ⇒ Object
Processes each entry in a FHIR bundle to extract resource and possible profiles to validate against.
-
#extract_resources_from_bundle(bundle: nil, response: nil, reply_handler: nil, max_pages: 20) ⇒ Object
Extracts resources from a bundle while following “next” links.
-
#find_profile_url(request_type) ⇒ Object
Resource Types to validate in request/ response bundle.
-
#find_referenced_instance_in_bundle(reference, enclosing_entry_fullurl, bundle_map) ⇒ Object
Finds a referenced instance in a FHIR bundle based on a reference and the full URL of the enclosing entry.
- #generate_non_conformance_message(item) ⇒ Object
-
#handle_claim_profile(reference_elements, current_entry_profile_url) ⇒ Object
Handles the special case for the Claim profile in a FHIR bundle.
-
#metadata_map(version) ⇒ Object
Mapping profile url to metadata.
- #perform_request_validation(bundle, profile_url, version, request_type) ⇒ Object
- #perform_response_validation(response_bundle, profile_url, version, request_type, request_bundle = nil) ⇒ Object
-
#process_instance_profiles(instance, bundle_entry, reference_element, version) ⇒ Object
Processes the profiles associated with a given instance in a FHIR bundle.
-
#process_reference_element(reference_element, current_entry, bundle_entry, bundle_map, version) ⇒ Object
Processes a given reference element definition from a FHIR bundle entry.
-
#resource_present_in_pa_request_and_response_msg(resource) ⇒ Object
Generates a message for a resource present in both the PA request and response bundles.
-
#resource_shall_appear_once_message(reference_resource_type, reference_resource_id, total_matches) ⇒ Object
Generates a message for a resource that appears more than once in a bundle.
- #save_bundles_and_entries_to_scratch(bundles) ⇒ Object
-
#valid_url_or_urn_uuid?(string) ⇒ Boolean
Checks if a string is a valid url or in the form “urn:uuid:[some guid]”.
-
#validate_bundle_entries_against_profiles(version) ⇒ Object
Validates bundle resource and each entry in the bundle against its target profiles.
- #validate_bundle_entries_full_url(bundle) ⇒ Object
-
#validate_pa_request_payload_structure(bundle, request_type) ⇒ Object
Validates the structure of a Prior Authorization (PA) request Bundle.
-
#validate_pa_response_body_structure(pa_response_bundle, pa_request_bundle) ⇒ Object
Validates the response body structure of a Prior Authorization (PA) response.
- #validate_pas_bundle_json(json, profile_url, version, request_type, bundle_type, skips: false, message: '') ⇒ Object
-
#validate_resources_conformance_against_profile(bundle, profile_url, version, request_type) ⇒ Object
Profile conformance of Prior Authorization (PA) resources.
-
#validate_uniqueness_of_supporting_info_sequences(claim) ⇒ Object
Checks the following requirement: The Claim.supportingInfo.sequence for each entry SHALL be unique within the Claim.
- #validation_error_messages ⇒ Object
Methods included from ValidationTest
#check_for_dar, #check_for_dar_code, #check_for_dar_extension, #perform_validation_test
Instance Method Details
#absolute_url(reference, base_url) ⇒ Object
406 407 408 409 410 411 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 406 def absolute_url(reference, base_url) return if reference.blank? return reference if base_url.blank? || reference.starts_with?('urn:uuid:') || URI(reference).absolute? "#{base_url}/#{reference}" end |
#add_declared_profiles(instance, bundle_entry, version) ⇒ Object
Adds declared profiles from an instance (meta.profile) to the resource target profile map. It recursively processes each entry for further profile extraction.
329 330 331 332 333 334 335 336 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 329 def add_declared_profiles(instance, bundle_entry, version) instance.resource&.&.profile&.each do |url| next if bundle_resources_target_profile_map[instance.fullUrl][:profile_urls].include?(url) bundle_resources_target_profile_map[instance.fullUrl][:profile_urls] << url extract_profiles_to_validate_each_entry(bundle_entry, instance, url, version) end end |
#add_profile_to_instance(instance, profile_url, bundle_entry, version) ⇒ Object
Adds a specific profile URL to an instance in the resource target profile map. It recursively processes the instance for further profilce extraction.
344 345 346 347 348 349 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 344 def add_profile_to_instance(instance, profile_url, bundle_entry, version) return if bundle_resources_target_profile_map[instance.fullUrl][:profile_urls].include?(profile_url) bundle_resources_target_profile_map[instance.fullUrl][:profile_urls] << profile_url extract_profiles_to_validate_each_entry(bundle_entry, instance, profile_url, version) end |
#add_resource_target_profile_to_map(resource_full_url, resource, profile_url = nil) ⇒ Object
Adds a resource and its associated profile URL to the resource target profile map. If the resource is already in the map, it adds the profile URL to the resource’s list of profile URLs.
199 200 201 202 203 204 205 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 199 def add_resource_target_profile_to_map(resource_full_url, resource, profile_url = nil) entry = bundle_resources_target_profile_map[resource_full_url] ||= { resource:, profile_urls: [] } return if profile_url.blank? || entry[:profile_urls].include?(profile_url) entry[:profile_urls] << profile_url end |
#all_scratch_resources ⇒ Object
14 15 16 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 14 def all_scratch_resources scratch_resources[:all] ||= [] end |
#bundle_entry_map(bundle_entry) ⇒ Object
360 361 362 363 364 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 360 def bundle_entry_map(bundle_entry) @bundle_entry_map ||= bundle_entry.each_with_object({}) do |entry, obj| obj[entry.fullUrl] = entry end end |
#bundle_resources_target_profile_map ⇒ Hash
Returns a hash map where the keys are resource full URLs and the values are a hash containing the resource object and an array of associated profile URLs.
190 191 192 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 190 def bundle_resources_target_profile_map @bundle_resources_target_profile_map ||= {} end |
#check_presence_of_referenced_resources(target_resource, base_url, resources_to_match) ⇒ Object
This method traverses references within a FHIR resource, ensuring that referenced resources are populated in the bundle. It also enforces that a referenced resource appears only once in the bundle, as required by the PAS IG.
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 481 def check_presence_of_referenced_resources(target_resource, base_url, resources_to_match) return if target_resource.blank? if target_resource.is_a?(FHIR::Reference) && target_resource.reference.present? ref = target_resource.reference return if ref.blank? absolute_ref = absolute_url(ref, base_url) resource_type, resource_id = ref.split('/') matching_resources = resources_to_match.find_all { |res| res.fullUrl == absolute_ref } if matching_resources.length != 1 << (resource_type, resource_id, matching_resources.length) end if matching_resources.length.positive? check_presence_of_referenced_resources(matching_resources.first, base_url, resources_to_match) end else target_resource.source_hash.each_key do |attr| value = target_resource.send(attr.to_sym) if value.is_a?(FHIR::Model) check_presence_of_referenced_resources(value, base_url, resources_to_match) elsif value.is_a?(Array) && value.all? { |elmt| elmt.is_a?(FHIR::Model) } value.each { |elmt| check_presence_of_referenced_resources(elmt, base_url, resources_to_match) } end end end end |
#evaluate_fhirpath_expression(resource, expression) ⇒ Array
Evaluates a FHIRPath expression against a FHIR resource using an external FHIRPath validator.
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 370 def evaluate_fhirpath_expression(resource, expression) return [] unless expression && resource logger = Logger.new($stdout) begin fhirpath_url = ENV.fetch('FHIRPATH_URL') path = "#{fhirpath_url}/evaluate?path=#{expression}" response = Faraday.post(path, resource.to_json, 'Content-Type' => 'application/json') if response.status.to_s.start_with? '2' result = JSON.parse(response.body) return result.map { |entry| entry.dig('element', 'reference') if entry['type'] == 'Reference' }.compact else logger.error "External FHIRPath service failed: #{response.status}" raise 'FHIRPath service not available' end rescue Faraday::Error => e logger.error "HTTP request failed: #{e.}" raise 'FHIRPath service not available' end [] end |
#extract_base_url(absolute_url) ⇒ String
Extracts the base URL from an absolute URL by removing the resource type and ID.
416 417 418 419 420 421 422 423 424 425 426 427 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 416 def extract_base_url(absolute_url) return '' if absolute_url.blank? uri = URI(absolute_url) return '' unless uri.scheme && uri.host # Split the path segments and remove the last two segments (resource type and id) path_segments = uri.path.split('/') base_path = path_segments[0...-2].join('/') "#{uri.scheme}://#{uri.host}#{base_path}" end |
#extract_profiles_to_validate_each_entry(bundle_entry, current_entry, current_entry_profile_url, version) ⇒ Object
Processes each entry in a FHIR bundle to extract resource and possible profiles to validate against. It recursively evaluates referenced instances and their profiles, expanding the validation scope.
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 235 def extract_profiles_to_validate_each_entry(bundle_entry, current_entry, current_entry_profile_url, version) return if current_entry.blank? # NOTE: the IG does not have the metadata for us-core profiles. = ("v#{version}")[current_entry_profile_url] return if .blank? bundle_map = bundle_entry_map(bundle_entry) reference_elements = .references # Special handling for Claim submit profile if current_entry_profile_url == CLAIM_PROFILE handle_claim_profile(reference_elements, current_entry_profile_url) end reference_elements.each do |reference_element| process_reference_element(reference_element, current_entry, bundle_entry, bundle_map, version) end end |
#extract_resources_from_bundle(bundle: nil, response: nil, reply_handler: nil, max_pages: 20) ⇒ Object
Extracts resources from a bundle while following “next” links.
This method extracts resources from a FHIR bundle, following “next” links in the bundle until the specified maximum number of pages is reached. It collects resources and invokes the reply_handler for each response.
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 522 def extract_resources_from_bundle( bundle: nil, response: nil, reply_handler: nil, max_pages: 20 ) page_count = 1 resources = [] until bundle.nil? || page_count == max_pages resources += bundle&.entry&.map { |entry| entry&.resource } next_bundle_link = bundle&.link&.find { |link| link.relation == 'next' }&.url reply_handler&.call(response) break if next_bundle_link.blank? page_count += 1 end resources end |
#find_profile_url(request_type) ⇒ Object
Resource Types to validate in request/ response bundle
430 431 432 433 434 435 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 430 def find_profile_url(request_type) { 'Claim' => request_type == 'submit' ? CLAIM_PROFILE : CLAIM_INQUIRY_PROFILE, 'ClaimResponse' => request_type == 'submit' ? CLAIM_RESPONSE_PROFILE : CLAIM_INQUIRY_RESPONSE_PROFILE } end |
#find_referenced_instance_in_bundle(reference, enclosing_entry_fullurl, bundle_map) ⇒ Object
Finds a referenced instance in a FHIR bundle based on a reference and the full URL of the enclosing entry.
399 400 401 402 403 404 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 399 def find_referenced_instance_in_bundle(reference, enclosing_entry_fullurl, bundle_map) base_url = extract_base_url(enclosing_entry_fullurl) key = absolute_url(reference, base_url) bundle_map[key] end |
#generate_non_conformance_message(item) ⇒ Object
224 225 226 227 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 224 def (item) "#{item[:resource].resourceType}/#{item[:resource].id} is not conformant to any of the " \ "target profiles: #{item[:profile_urls]}." end |
#handle_claim_profile(reference_elements, current_entry_profile_url) ⇒ Object
Handles the special case for the Claim profile in a FHIR bundle. It adds missing reference elements for the Claim profile. Claim.item.extension:requestedService value is a reference, but somehow not included in the metadata references.
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 261 def handle_claim_profile(reference_elements, current_entry_profile_url) return unless current_entry_profile_url == CLAIM_PROFILE claim_ref_element = { path: 'Claim.item.extension.value', profiles: [ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-medicationrequest', 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-servicerequest', 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-devicerequest', 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-nutritionorder' ] } reference_elements << claim_ref_element end |
#metadata_map(version) ⇒ Object
Mapping profile url to metadata
352 353 354 355 356 357 358 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 352 def (version) @metadata ||= YAML.load_file(File.join(__dir__, "generated/#{version}/metadata.yml"), aliases: true) @metadata_map ||= @metadata[:groups].each_with_object({}) do |group, obj| obj[group[:profile_url]] = Generator::GroupMetadata.new(group) end end |
#perform_request_validation(bundle, profile_url, version, request_type) ⇒ Object
30 31 32 33 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 30 def perform_request_validation(bundle, profile_url, version, request_type) validate_pa_request_payload_structure(bundle, request_type) validate_resources_conformance_against_profile(bundle, profile_url, version, request_type) end |
#perform_response_validation(response_bundle, profile_url, version, request_type, request_bundle = nil) ⇒ Object
35 36 37 38 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 35 def perform_response_validation(response_bundle, profile_url, version, request_type, request_bundle = nil) validate_pa_response_body_structure(response_bundle, request_bundle) if request_type == 'submit' validate_resources_conformance_against_profile(response_bundle, profile_url, version, request_type) end |
#process_instance_profiles(instance, bundle_entry, reference_element, version) ⇒ Object
Processes the profiles associated with a given instance in a FHIR bundle. It adds the instance’s profiles to the resource target profile map and handles recursive profile extraction. The profiles collected here are possible profiles the given instance may conform to. The conformance validation will ensure that the resource is comformant to at least one of the target profiles.
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 303 def process_instance_profiles(instance, bundle_entry, reference_element, version) add_resource_target_profile_to_map(instance.fullUrl, instance.resource) # Add the declared profile conformance add_declared_profiles(instance, bundle_entry, version) reference_element[:profiles].each do |profile_url| # NOTE: the IG does not have the metadata for us-core profiles. = ("v#{version}")[profile_url] resource_type = instance.resource.resourceType next unless &.resource == resource_type || profile_url.include?(resource_type) add_profile_to_instance(instance, profile_url, bundle_entry, version) # NOTE: The algorithm assumes OR semantics for profile conformance, where the resource needs to conform to # at least one of the collected profiles. However, it may not cover all scenarios, such as cases # where AND semantics are required for multiple profile conformance. Also, it does not address complex # situations where profile requirements may conflict or have dependencies across referenced instances. # Therefore, this algorithm may not provide complete validation for all scenarios, and additional checks may be # necessary depending on the use case. end end |
#process_reference_element(reference_element, current_entry, bundle_entry, bundle_map, version) ⇒ Object
Processes a given reference element definition from a FHIR bundle entry. It evaluates FHIRPath expressions and processes each referenced instance and its profiles.
284 285 286 287 288 289 290 291 292 293 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 284 def process_reference_element(reference_element, current_entry, bundle_entry, bundle_map, version) reference_element_values = evaluate_fhirpath_expression(current_entry.resource, reference_element[:path]) referenced_instances = reference_element_values.map do |value| find_referenced_instance_in_bundle(value, current_entry.fullUrl, bundle_map) end.compact referenced_instances.each do |instance| process_instance_profiles(instance, bundle_entry, reference_element, version) end end |
#resource_present_in_pa_request_and_response_msg(resource) ⇒ Object
Generates a message for a resource present in both the PA request and response bundles.
This method generates an error message when a resource appears in both the PA request and response bundles but does not have the same fullUrl or identifiers.
565 566 567 568 569 570 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 565 def resource_present_in_pa_request_and_response_msg(resource) " Resource #{resource.resourceType}/#{resource.id} is an entry in both the PA Request Bundle and the Response Bundle, but they do not have the same fullUrl or identifiers " end |
#resource_shall_appear_once_message(reference_resource_type, reference_resource_id, total_matches) ⇒ Object
Generates a message for a resource that appears more than once in a bundle.
This method generates an error message when a referenced resource appears more than once in a FHIR bundle, which is not allowed.
552 553 554 555 556 557 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 552 def (reference_resource_type, reference_resource_id, total_matches) " The referenced #{reference_resource_type}/#{reference_resource_id} resource SHALL only appear once in the Bundle, but found #{total_matches}. " end |
#save_bundles_and_entries_to_scratch(bundles) ⇒ Object
18 19 20 21 22 23 24 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 18 def save_bundles_and_entries_to_scratch(bundles) bundles.each do |bundle| all_scratch_resources << bundle all_scratch_resources.concat(bundle.entry.map(&:resource)) all_scratch_resources.uniq! end end |
#valid_url_or_urn_uuid?(string) ⇒ Boolean
Checks if a string is a valid url or in the form “urn:uuid:[some guid]”
468 469 470 471 472 473 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 468 def valid_url_or_urn_uuid?(string) url_regex = /\A#{URI::DEFAULT_PARSER.make_regexp(%w[http https])}\z/ urn_uuid_regex = /\Aurn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/i string&.match?(url_regex) || string&.match?(urn_uuid_regex) end |
#validate_bundle_entries_against_profiles(version) ⇒ Object
Validates bundle resource and each entry in the bundle against its target profiles. It logs a message for each conformant entry and collects error messages for non-conformant entries. Asserts that there are no validation errors.
211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 211 def validate_bundle_entries_against_profiles(version) bundle_resources_target_profile_map.each_value do |item| resource = item[:resource] base_profile = FHIR::Definitions.resource_definition(resource.resourceType).url success_profile = item[:profile_urls].find do |url| profile_to_validate = url == base_profile ? url : "#{url}|#{version}" resource_is_valid?(resource:, profile_url: profile_to_validate) end << (item) unless success_profile end end |
#validate_bundle_entries_full_url(bundle) ⇒ Object
457 458 459 460 461 462 463 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 457 def validate_bundle_entries_full_url(bundle) msg = "[Bundle/#{bundle.id}]: Bundle.entry.fullUrl values SHALL be a valid url or in the form " \ "'urn:uuid:[some guid]'." bundle.entry.each do |entry| << msg unless valid_url_or_urn_uuid?(entry.fullUrl) end end |
#validate_pa_request_payload_structure(bundle, request_type) ⇒ Object
Validates the structure of a Prior Authorization (PA) request Bundle.
This method performs various checks on the PA request payload, including validating the FHIR bundle structure, checking the resource type, and validating the resources referenced in the Claim resource are included in the bundle. It ensures that the first entry in the Bundle is a Claim resource and additional entries are populated with referenced resources, following the traversal of references. Duplicate resources are handled as required( appearing only once in the bundle entry).
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 75 def validate_pa_request_payload_structure(bundle, request_type) bundle_entry_resources = bundle.entry.map(&:resource) first_entry = bundle_entry_resources.first base_url = extract_base_url(bundle.entry.first&.fullUrl) check_presence_of_referenced_resources(first_entry, base_url, bundle.entry) if request_type == 'submit' unless first_entry.is_a?(FHIR::Claim) << "[Bundle/#{bundle.id}]: The first bundle entry must be a Claim" end validate_uniqueness_of_supporting_info_sequences(first_entry) validate_bundle_entries_full_url(bundle) else claim_resource = bundle_entry_resources.find { |resource| resource.resourceType == 'Claim' } if claim_resource.blank? << "[Bundle/#{bundle.id}]: Claim must be present for inquiry request" end # The inquiry operation must contain a requesting provider organization, # a payer organization, and a patient for the inquiry patient_reference = claim_resource&.patient&.reference provider_reference = claim_resource&.provider&.reference payer_reference = claim_resource&.insurer&.reference if patient_reference.blank? << "[Bundle/#{bundle.id}]: The Claim for inquiry operation must reference a patient." end if provider_reference.blank? << "[Bundle/#{bundle.id}]: The claim for inquiry operation must reference " \ 'a requesting provider organization.' end if payer_reference.blank? << "[Bundle/#{bundle.id}]: The Claim for inquiry operation must contain " \ 'a payer organization.' end end end |
#validate_pa_response_body_structure(pa_response_bundle, pa_request_bundle) ⇒ Object
Validates the response body structure of a Prior Authorization (PA) response.
This method performs validation of the PA response bundle structure. It follows the PAS IG requirement that the FHIR Bundle generated from the response starts with a ClaimResponse entry. For response of $submit request: Additional Bundle entries are populated with resources referenced by the ClaimResponse or descendant references, ensuring that only one resource is created for a given combination of content. Resources echoed back from the request are validated to ensure the same fullUrl and resource identifiers as in the request are used.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 130 def validate_pa_response_body_structure(pa_response_bundle, pa_request_bundle) first_entry = pa_response_bundle.entry.first.resource unless first_entry.is_a?(FHIR::ClaimResponse) << "[Bundle/#{pa_response_bundle.id}]: The first bundle entry must be a ClaimResponse" end base_url = extract_base_url(pa_response_bundle.entry.last&.fullUrl) check_presence_of_referenced_resources(first_entry, base_url, pa_response_bundle.entry) # Testing: When echoing back resources that are the same as were present in the prior authorization request, # the system SHALL ensure that the same fullUrl and resource identifiers are used in the response as appeared # in the request # pa_request_bundle = FHIR.from_contents(pa_request_bundle) # pa_response_bundle.entry.each do |entry| # res = entry.resource # request_entry = pa_request_bundle.entry.find do |ent| # ent.resource.resourceType == res.resourceType && ent.resource.id == res.id # end # next unless request_entry.present? # assert( # request_entry.fullUrl == entry.fullUrl && request_entry.resource.identifier == res.identifier, # resource_present_in_pa_request_and_response_msg(res) # ) # end end |
#validate_pas_bundle_json(json, profile_url, version, request_type, bundle_type, skips: false, message: '') ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 40 def validate_pas_bundle_json(json, profile_url, version, request_type, bundle_type, skips: false, message: '') assert_valid_json(json) bundle = FHIR.from_contents(json) assert bundle.present?, 'Not a FHIR resource' assert_resource_type(:bundle, resource: bundle) if bundle_type == 'request_bundle' perform_request_validation(bundle, profile_url, version, request_type) else perform_response_validation(bundle, profile_url, version, request_type) end .each do |msg| << { type: 'error', message: msg } end msg = 'Bundle response returned and/or entry resources are not conformant. Check messages for issues found.' assert .blank?, msg rescue Inferno::Exceptions::AssertionException => e msg = "#{} #{e.}".strip raise e.class, msg unless skips skip msg end |
#validate_resources_conformance_against_profile(bundle, profile_url, version, request_type) ⇒ Object
Profile conformance of Prior Authorization (PA) resources.
This method performs conformance validation on the PA bundle and bundle entries. The request/response bundle and includes resources are validated against their respective profile.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 168 def validate_resources_conformance_against_profile(bundle, profile_url, version, request_type) add_resource_target_profile_to_map('bundle', bundle, profile_url) bundle_entry = bundle.entry root_entry = bundle_entry.find do |entry| entry.resource.resourceType == 'Claim' || entry.resource.resourceType == 'ClaimResponse' end if root_entry.present? root_resource_profile_url = find_profile_url(request_type)[root_entry.resource.resourceType] add_resource_target_profile_to_map(root_entry.fullUrl, root_entry.resource, root_resource_profile_url) extract_profiles_to_validate_each_entry(bundle_entry, root_entry, root_resource_profile_url, version) end validate_bundle_entries_against_profiles(version) end |
#validate_uniqueness_of_supporting_info_sequences(claim) ⇒ Object
Checks the following requirement: The Claim.supportingInfo.sequence for each entry SHALL be unique within the Claim.
Since the cardinality for Claim.supportingInfo is 0..*, we will check the uniqueness if Array not empty.
443 444 445 446 447 448 449 450 451 452 453 454 455 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 443 def validate_uniqueness_of_supporting_info_sequences(claim) return unless claim.is_a?(FHIR::Claim) supporting_info = claim.supportingInfo return unless supporting_info.present? sequences = supporting_info.map(&:sequence) is_unique = sequences.uniq.length == sequences.length return if is_unique << "[Claim/#{claim.id}]: The sequence element for each supportingInfo entry SHALL be " \ 'unique within the Claim.' end |
#validation_error_messages ⇒ Object
26 27 28 |
# File 'lib/davinci_pas_test_kit/pas_bundle_validation.rb', line 26 def @validation_error_messages ||= [] end |