davinci_pas_test_kit 0.12.0 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/lib/davinci_pas_test_kit/client_suite.rb +24 -0
  3. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_approval_submit_test.rb +32 -1
  4. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_denial_submit_test.rb +30 -4
  5. data/lib/davinci_pas_test_kit/{generated/v2.0.1/client_tests/client_pended_pas_inquiry_request_bundle_validation_test.rb → custom_groups/v2.0.1/client_tests/pas_client_inquire_request_bundle_validation_test.rb} +26 -20
  6. data/lib/davinci_pas_test_kit/{generated/v2.0.1/client_tests/client_denial_pas_response_bundle_validation_test.rb → custom_groups/v2.0.1/client_tests/pas_client_inquire_response_bundle_validation_test.rb} +34 -21
  7. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_submit_test.rb +130 -5
  8. data/lib/davinci_pas_test_kit/{generated/v2.0.1/client_tests/client_pas_request_bundle_validation_test.rb → custom_groups/v2.0.1/client_tests/pas_client_request_bundle_validation_test.rb} +28 -20
  9. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/{pas_client_approval_submit_response_attest.rb → pas_client_response_attest.rb} +26 -9
  10. data/lib/davinci_pas_test_kit/{generated/v2.0.1/client_tests/client_pended_pas_response_bundle_validation_test.rb → custom_groups/v2.0.1/client_tests/pas_client_response_bundle_validation_test.rb} +44 -20
  11. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_submit_must_support_test.rb +3 -0
  12. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_subscription_create_test.rb +52 -0
  13. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_subscription_pas_conformance_test.rb +49 -0
  14. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/error_tests/pas_submission_error_test.rb +1 -0
  15. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_approval_group.rb +21 -9
  16. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_authentication_group.rb +2 -2
  17. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_denial_group.rb +21 -22
  18. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/pas_client_pended_group.rb +97 -31
  19. data/lib/davinci_pas_test_kit/docs/client_suite_description_v201.md +213 -72
  20. data/lib/davinci_pas_test_kit/endpoints/claim_endpoint.rb +85 -134
  21. data/lib/davinci_pas_test_kit/endpoints/subscription_create_endpoint.rb +96 -0
  22. data/lib/davinci_pas_test_kit/endpoints/subscription_status_endpoint.rb +90 -0
  23. data/lib/davinci_pas_test_kit/generated/v2.0.1/claim/claim_operation_test.rb +1 -0
  24. data/lib/davinci_pas_test_kit/generated/v2.0.1/claiminquiryresponse/server_inquire_response_claiminquiryresponse_must_support_test.rb +1 -0
  25. data/lib/davinci_pas_test_kit/generated/v2.0.1/claimresponse/server_submit_response_claimresponse_must_support_test.rb +1 -0
  26. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_request_bundle/metadata.yml +0 -2
  27. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_request_bundle/server_pas_inquiry_request_bundle_validation_test.rb +3 -1
  28. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_inquiry_response_bundle/server_pas_inquiry_response_bundle_validation_test.rb +2 -1
  29. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_request_bundle/metadata.yml +0 -2
  30. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_request_bundle/server_pas_request_bundle_validation_test.rb +3 -1
  31. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_response_bundle/metadata.yml +0 -4
  32. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_response_bundle/server_pas_response_bundle_validation_test.rb +2 -1
  33. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_server_denial_use_case_group.rb +1 -1
  34. data/lib/davinci_pas_test_kit/generated/v2.0.1/pas_server_pended_use_case_group.rb +6 -5
  35. data/lib/davinci_pas_test_kit/generated/v2.0.1/server_suite.rb +1 -0
  36. data/lib/davinci_pas_test_kit/generator/group_generator.rb +9 -8
  37. data/lib/davinci_pas_test_kit/generator/group_metadata_extractor.rb +7 -3
  38. data/lib/davinci_pas_test_kit/generator/templates/suite.rb.erb +1 -0
  39. data/lib/davinci_pas_test_kit/generator/validation_test_generator.rb +19 -56
  40. data/lib/davinci_pas_test_kit/generator/value_extractor.rb +4 -1
  41. data/lib/davinci_pas_test_kit/generator.rb +1 -1
  42. data/lib/davinci_pas_test_kit/jobs/send_pas_subscription_notification.rb +136 -0
  43. data/lib/davinci_pas_test_kit/jobs/send_subscription_handshake.rb +139 -0
  44. data/lib/davinci_pas_test_kit/pas_bundle_validation.rb +12 -11
  45. data/lib/davinci_pas_test_kit/requirements/davinci-pas-test-kit_out_of_scope_requirements.csv +11 -0
  46. data/lib/davinci_pas_test_kit/requirements/davinci-pas-test-kit_requirements.csv +214 -0
  47. data/lib/davinci_pas_test_kit/requirements/generated/davinci-pas-test-kit_requirements_coverage.csv +214 -0
  48. data/lib/davinci_pas_test_kit/response_generator.rb +397 -0
  49. data/lib/davinci_pas_test_kit/tags.rb +9 -0
  50. data/lib/davinci_pas_test_kit/urls.rb +8 -0
  51. data/lib/davinci_pas_test_kit/user_input_response.rb +11 -8
  52. data/lib/davinci_pas_test_kit/validation_test.rb +0 -1
  53. data/lib/davinci_pas_test_kit/version.rb +2 -2
  54. data/lib/davinci_pas_test_kit.rb +1 -0
  55. data/lib/inferno_requirements_tools/ext/inferno_core/runnable.rb +22 -0
  56. data/lib/inferno_requirements_tools/tasks/requirements_coverage.rb +284 -0
  57. data/lib/requirements_config.yaml +17 -0
  58. metadata +36 -14
  59. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_denial_submit_response_attest.rb +0 -38
  60. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_inquire_response_attest.rb +0 -39
  61. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_inquire_test.rb +0 -35
  62. data/lib/davinci_pas_test_kit/custom_groups/v2.0.1/client_tests/pas_client_pended_submit_response_attest.rb +0 -39
  63. data/lib/davinci_pas_test_kit/generator/templates/validation_client.rb.erb +0 -50
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../tags'
4
+ require_relative '../urls'
5
+ require 'subscriptions_test_kit'
6
+
7
+ module DaVinciPASTestKit
8
+ module Jobs
9
+ class SendPASSubscriptionNotification
10
+ include Sidekiq::Job
11
+ include SubscriptionsTestKit::SubscriptionsR5BackportR4Client::SubscriptionSimulationUtils
12
+ include URLs
13
+
14
+ # override the one from URLs
15
+ def suite_id
16
+ @notification_suite_id
17
+ end
18
+
19
+ sidekiq_options retry: false
20
+
21
+ def perform(test_run_id, test_session_id, result_id, notification_bearer_token, notification_json, resume_token,
22
+ notification_suite_id)
23
+ @test_run_id = test_run_id
24
+ @test_session_id = test_session_id
25
+ @result_id = result_id
26
+ @notification_bearer_token = notification_bearer_token
27
+ @notification_json = notification_json
28
+ @resume_token = resume_token
29
+ @notification_suite_id = notification_suite_id
30
+
31
+ await_subscription_creation # NOTE: currently must exist - see PASClientPendedSubmitTest
32
+ sleep 1
33
+ return unless test_still_waiting?
34
+
35
+ sleep rand(5..10)
36
+ return unless test_still_waiting?
37
+
38
+ send_event_notification
39
+ end
40
+
41
+ def requests_repo
42
+ @requests_repo ||= Inferno::Repositories::Requests.new
43
+ end
44
+
45
+ def results_repo
46
+ @results_repo ||= Inferno::Repositories::Results.new
47
+ end
48
+
49
+ def subscription
50
+ @subscription ||= find_subscription(@test_session_id)
51
+ end
52
+
53
+ def subscription_notification_endpoint
54
+ subscription&.channel&.endpoint
55
+ end
56
+
57
+ def headers
58
+ @headers ||= subscription_headers.merge(content_type_header).merge(authorization_header)
59
+ end
60
+
61
+ def rest_hook_connection
62
+ @rest_hook_connection ||= Faraday.new(url: subscription_notification_endpoint, request: { open_timeout: 30 },
63
+ headers:)
64
+ end
65
+
66
+ def test_suite_connection
67
+ @test_suite_connection ||= Faraday.new(base_url)
68
+ end
69
+
70
+ def content_type_header
71
+ @content_type_header ||= { 'Content-Type' => actual_mime_type(subscription) }
72
+ end
73
+
74
+ def subscription_headers
75
+ @subscription_headers ||= subscription.channel&.header&.each_with_object({}) do |header, hash|
76
+ header_name, header_value = header.split(': ', 2)
77
+ hash[header_name] = header_value
78
+ end || {}
79
+ end
80
+
81
+ def authorization_header
82
+ @authorization_header ||=
83
+ @notification_bearer_token.present? ? { 'Authorization' => "Bearer #{@notification_bearer_token}" } : {}
84
+ end
85
+
86
+ def subscription_topic
87
+ @subscription_topic ||= subscription&.criteria
88
+ end
89
+
90
+ def subscription_full_url
91
+ @subscription_full_url ||= "#{fhir_subscription_url}/#{subscription.id}"
92
+ end
93
+
94
+ def test_still_waiting?
95
+ results_repo.find_waiting_result(test_run_id: @test_run_id)
96
+ end
97
+
98
+ def await_subscription_creation
99
+ sleep 0.5 until subscription.present? || !test_still_waiting?
100
+ end
101
+
102
+ def send_event_notification
103
+ event_json = derive_event_notification(@notification_json, subscription_full_url, subscription_topic, 1).to_json
104
+ response = send_notification(event_json)
105
+ persist_notification_request(response, [REST_HOOK_EVENT_NOTIFICATION_TAG])
106
+ end
107
+
108
+ def send_notification(request_body)
109
+ rest_hook_connection.post('', request_body)
110
+ rescue Faraday::Error => e
111
+ # Warning: This is a hack. If there is an error with the request such that we never get a response, we have
112
+ # no clean way to persist that information for the Inferno test to check later. The solution here
113
+ # is to persist the request anyway with a status of nil, using the error message as response body
114
+ Faraday::Response.new(response_body: e.message, url: rest_hook_connection.url_prefix.to_s)
115
+ end
116
+
117
+ def persist_notification_request(response, tags)
118
+ inferno_request_headers = headers.map { |name, value| { name:, value: } }
119
+ inferno_response_headers = response.headers&.map { |name, value| { name:, value: } }
120
+ requests_repo.create(
121
+ verb: 'POST',
122
+ url: response.env.url.to_s,
123
+ direction: 'outgoing',
124
+ status: response.status,
125
+ request_body: response.env.request_body,
126
+ response_body: response.env.response_body,
127
+ test_session_id: @test_session_id,
128
+ result_id: @result_id,
129
+ request_headers: inferno_request_headers,
130
+ response_headers: inferno_response_headers,
131
+ tags:
132
+ )
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../tags'
4
+ require 'subscriptions_test_kit'
5
+
6
+ module DaVinciPASTestKit
7
+ module Jobs
8
+ class SendSubscriptionHandshake
9
+ include Sidekiq::Job
10
+ include SubscriptionsTestKit::SubscriptionsR5BackportR4Client::SubscriptionSimulationUtils
11
+
12
+ sidekiq_options retry: false
13
+
14
+ def perform(test_run_id, test_session_id, result_id, subscription_id, subscription_url, client_endpoint,
15
+ bearer_token, notification_json, test_run_identifier, test_suite_base_url)
16
+ @test_run_id = test_run_id
17
+ @test_session_id = test_session_id
18
+ @result_id = result_id
19
+ @subscription_id = subscription_id
20
+ @subscription_url = subscription_url
21
+ @client_endpoint = client_endpoint
22
+ @bearer_token = bearer_token
23
+ @notification_json = notification_json.present? ? notification_json : default_notification_base_json
24
+ @test_run_identifier = test_run_identifier
25
+ @test_suite_base_url = test_suite_base_url
26
+
27
+ await_subscription_creation
28
+ sleep 1
29
+ return unless test_still_waiting?
30
+
31
+ send_handshake_notification
32
+ test_suite_connection.get(RESUME_PASS_PATH.delete_prefix('/'), { token: @test_run_identifier })
33
+ end
34
+
35
+ def default_notification_base_json
36
+ FHIR::Bundle.new(
37
+ timestamp: Time.now.utc.iso8601,
38
+ type: 'history',
39
+ entry: [
40
+ FHIR::Bundle::Entry.new(fullUrl: "urn:uuid:#{SecureRandom.uuid}",
41
+ resource: FHIR.from_contents(default_handshake_parameters_base_json))
42
+ ]
43
+ ).to_json
44
+ end
45
+
46
+ def default_handshake_parameters_base_json
47
+ '{ "parameter": [ { "name": "subscription", "valueReference": { "reference": "replace_with_subscription_ref" } }, { "name": "topic", "valueCanonical": "replace_with_topic_canonical" }, { "name": "status", "valueCode": "requested" }, { "name": "type", "valueCode": "handshake" }, { "name": "events-since-subscription-start", "valueString": "0" } ], "resourceType": "Parameters" }' # rubocop:disable Layout/LineLength
48
+ end
49
+
50
+ def requests_repo
51
+ @requests_repo ||= Inferno::Repositories::Requests.new
52
+ end
53
+
54
+ def results_repo
55
+ @results_repo ||= Inferno::Repositories::Results.new
56
+ end
57
+
58
+ def subscription
59
+ @subscription ||= find_subscription(@test_session_id)
60
+ end
61
+
62
+ def headers
63
+ @headers ||= subscription_headers.merge(content_type_header).merge(authorization_header)
64
+ end
65
+
66
+ def rest_hook_connection
67
+ @rest_hook_connection ||= Faraday.new(url: @client_endpoint, request: { open_timeout: 30 }, headers:)
68
+ end
69
+
70
+ def test_suite_connection
71
+ @test_suite_connection ||= Faraday.new(@test_suite_base_url)
72
+ end
73
+
74
+ def content_type_header
75
+ @content_type_header ||= { 'Content-Type' => actual_mime_type(subscription) }
76
+ end
77
+
78
+ def subscription_headers
79
+ return {} unless subscription.present?
80
+
81
+ @subscription_headers ||= subscription.channel&.header&.each_with_object({}) do |header, hash|
82
+ header_name, header_value = header.split(': ', 2)
83
+ hash[header_name] = header_value
84
+ end || {}
85
+ end
86
+
87
+ def subscription_topic
88
+ @subscription_topic ||= subscription&.criteria
89
+ end
90
+
91
+ def authorization_header
92
+ @authorization_header ||= @bearer_token.present? ? { 'Authorization' => "Bearer #{@bearer_token}" } : {}
93
+ end
94
+
95
+ def test_still_waiting?
96
+ results_repo.find_waiting_result(test_run_id: @test_run_id)
97
+ end
98
+
99
+ def await_subscription_creation
100
+ sleep 0.5 until subscription.present?
101
+ end
102
+
103
+ def send_handshake_notification
104
+ handshake_json = derive_handshake_notification(@notification_json, @subscription_url,
105
+ subscription_topic).to_json
106
+ response = send_notification(handshake_json)
107
+ persist_notification_request(response, [REST_HOOK_HANDSHAKE_NOTIFICATION_TAG])
108
+ response
109
+ end
110
+
111
+ def send_notification(request_body)
112
+ rest_hook_connection.post('', request_body)
113
+ rescue Faraday::Error => e
114
+ # Warning: This is a hack. If there is an error with the request such that we never get a response, we have
115
+ # no clean way to persist that information for the Inferno test to check later. The solution here
116
+ # is to persist the request anyway with a status of nil, using the error message as response body
117
+ Faraday::Response.new(response_body: e.message, url: rest_hook_connection.url_prefix.to_s)
118
+ end
119
+
120
+ def persist_notification_request(response, tags)
121
+ inferno_request_headers = headers.map { |name, value| { name:, value: } }
122
+ inferno_response_headers = response.headers&.map { |name, value| { name:, value: } }
123
+ requests_repo.create(
124
+ verb: 'POST',
125
+ url: response.env.url.to_s,
126
+ direction: 'outgoing',
127
+ status: response.status,
128
+ request_body: response.env.request_body,
129
+ response_body: response.env.response_body,
130
+ test_session_id: @test_session_id,
131
+ result_id: @result_id,
132
+ request_headers: inferno_request_headers,
133
+ response_headers: inferno_response_headers,
134
+ tags:
135
+ )
136
+ end
137
+ end
138
+ end
139
+ end
@@ -70,7 +70,7 @@ module DaVinciPASTestKit
70
70
  # referenced in the Claim resource are included in the bundle. It ensures that the first
71
71
  # entry in the Bundle is a Claim resource and additional entries are populated
72
72
  # with referenced resources, following the traversal of references.
73
- # Duplicate resources are handled as required( appearing only once
73
+ # Duplicate resources are handled as required (appearing only once
74
74
  # in the bundle entry).
75
75
  def validate_pa_request_payload_structure(bundle, request_type)
76
76
  bundle_entry_resources = bundle.entry.map(&:resource)
@@ -171,7 +171,7 @@ module DaVinciPASTestKit
171
171
  bundle_entry = bundle.entry
172
172
 
173
173
  root_entry = bundle_entry.find do |entry|
174
- entry.resource.resourceType == 'Claim' || entry.resource.resourceType == 'ClaimResponse'
174
+ ['Claim', 'ClaimResponse'].include?(entry.resource.resourceType)
175
175
  end
176
176
 
177
177
  if root_entry.present?
@@ -299,7 +299,7 @@ module DaVinciPASTestKit
299
299
  # Processes the profiles associated with a given instance in a FHIR bundle.
300
300
  # It adds the instance's profiles to the resource target profile map and handles recursive profile extraction.
301
301
  # The profiles collected here are possible profiles the given instance may conform to.
302
- # The conformance validation will ensure that the resource is comformant to at least one of the target profiles.
302
+ # The conformance validation will ensure that the resource is conformant to at least one of the target profiles.
303
303
  # @param instance [Object] The instance whose profiles are to be processed.
304
304
  # @param bundle_entry [Array] The bundle.entry contents.
305
305
  # @param reference_element [Hash] The reference element related to the instance.
@@ -331,7 +331,9 @@ module DaVinciPASTestKit
331
331
  # @param bundle_entry [Array] The bundle.entry contents.
332
332
  # @param version [String] The IG version.
333
333
  def add_declared_profiles(instance, bundle_entry, version)
334
- instance.resource&.meta&.profile&.each do |url|
334
+ return unless instance.resource.present?
335
+
336
+ instance.resource.meta&.profile&.each do |url|
335
337
  next if bundle_resources_target_profile_map[instance.fullUrl][:profile_urls].include?(url)
336
338
 
337
339
  bundle_resources_target_profile_map[instance.fullUrl][:profile_urls] << url
@@ -340,7 +342,7 @@ module DaVinciPASTestKit
340
342
  end
341
343
 
342
344
  # Adds a specific profile URL to an instance in the resource target profile map.
343
- # It recursively processes the instance for further profilce extraction.
345
+ # It recursively processes the instance for further profile extraction.
344
346
  # @param instance [Object] The instance to which the profile URL is added.
345
347
  # @param profile_url [String] The profile URL to be added.
346
348
  # @param bundle_entry [Array] The bundle.entry contents.
@@ -453,7 +455,7 @@ module DaVinciPASTestKit
453
455
  # as required by the PAS IG.
454
456
  # @param target_resource [FHIR::Model] The FHIR resource to traverse and validate.
455
457
  # @param base_url [String] The server base url.
456
- # @param resources_to_match [Array<FHIR:Bundel:Entry] The list of FHIR bundle entries to match references against.
458
+ # @param resources_to_match [Array<FHIR:Bundle:Entry] The list of FHIR bundle entries to match references against.
457
459
  def check_presence_of_referenced_resources(target_resource, base_url, resources_to_match)
458
460
  return if target_resource.blank?
459
461
 
@@ -462,11 +464,10 @@ module DaVinciPASTestKit
462
464
  return if ref.blank?
463
465
 
464
466
  absolute_ref = absolute_url(ref, base_url)
465
- resource_type, resource_id = ref.split('/')
466
467
  matching_resources = resources_to_match.find_all { |res| res.fullUrl == absolute_ref }
467
468
 
468
469
  if matching_resources.length != 1
469
- validation_error_messages << resource_shall_appear_once_message(resource_type, resource_id,
470
+ validation_error_messages << resource_shall_appear_once_message(absolute_ref,
470
471
  matching_resources.length)
471
472
  end
472
473
 
@@ -525,10 +526,10 @@ module DaVinciPASTestKit
525
526
  #
526
527
  # This method generates an error message when a referenced resource appears more than once
527
528
  # in a FHIR bundle, which is not allowed.
528
- def resource_shall_appear_once_message(reference_resource_type, reference_resource_id, total_matches)
529
+ def resource_shall_appear_once_message(absolute_ref, total_matches)
529
530
  "
530
- The referenced #{reference_resource_type}/#{reference_resource_id} resource
531
- SHALL only appear once in the Bundle, but found #{total_matches}.
531
+ The referenced #{absolute_ref} resource
532
+ SHALL appear exactly once in the Bundle, but found #{total_matches}.
532
533
  "
533
534
  end
534
535
 
@@ -0,0 +1,11 @@
1
+ Req Set,ID,Reason,Details
2
+ hl7.fhir.us.davinci-pas_2.0.1,12,Not Tested,Details of X12 messages will not be tested by Inferno.
3
+ hl7.fhir.us.davinci-pas_2.0.1,13,Not Tested,Details of X12 messages will not be tested by Inferno.
4
+ hl7.fhir.us.davinci-pas_2.0.1,14,Not Tested,Details of X12 messages will not be tested by Inferno.
5
+ hl7.fhir.us.davinci-pas_2.0.1,15,Not Tested,Details of X12 messages will not be tested by Inferno.
6
+ hl7.fhir.us.davinci-pas_2.0.1,96,Not Tested,Details of X12 messages will not be tested by Inferno.
7
+ hl7.fhir.us.davinci-pas_2.0.1,108,Not Verifiable,The specification does not provide clear details on the indicated responses (unclear diagram)
8
+ hl7.fhir.us.davinci-pas_2.0.1,109,Not Verifiable,The specification does not provide clear details on the indicated responses (unclear diagram)
9
+ hl7.fhir.us.davinci-pas_2.0.1,124,Not Tested,The rules for determining matching claims are specified in a proprietary X12 specification.
10
+ hl7.fhir.us.davinci-pas_2.0.1,132,Not Tested,How to request a subset of information is not detailed in the specification and lives in priopietary X12 specifications and mappings.
11
+ hl7.fhir.us.davinci-pas_2.0.1,191,Not Tested,Details of payer business rules will not be tested by Inferno.