davinci_pas_test_kit 0.15.0 → 0.15.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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/config/presets/pas_client_example.json +2 -2
  3. data/config/presets/pas_client_v201_run_against_pas_server.json +2 -2
  4. data/config/presets/pas_client_v221_run_against_pas_server.json +3 -3
  5. data/config/presets/pas_ri.json +6 -6
  6. data/config/presets/pas_server_v201_run_against_pas_client.json.erb +6 -6
  7. data/config/presets/pas_server_v221_run_against_pas_client.json.erb +10 -10
  8. data/lib/davinci_pas_test_kit/client/abstract_gather_must_support_test.rb +2 -48
  9. data/lib/davinci_pas_test_kit/client/client_input_descriptions.rb +29 -0
  10. data/lib/davinci_pas_test_kit/client/endpoints/claim_endpoint.rb +25 -9
  11. data/lib/davinci_pas_test_kit/client/user_input_response.rb +25 -6
  12. data/lib/davinci_pas_test_kit/client/v2.0.1/client_suite.rb +1 -1
  13. data/lib/davinci_pas_test_kit/client/v2.2.1/client_suite.rb +1 -1
  14. data/lib/davinci_pas_test_kit/cross_suite/fhirpath_utils.rb +13 -3
  15. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/beneficiary/metadata.yml +4 -0
  16. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/claim_inquiry/metadata.yml +15 -0
  17. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/claim_update/metadata.yml +17 -0
  18. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/claiminquiryresponse/metadata.yml +15 -0
  19. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/claimresponse/metadata.yml +15 -0
  20. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/communication_request/metadata.yml +4 -0
  21. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/coverage/metadata.yml +1 -0
  22. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/device_request/metadata.yml +2 -0
  23. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/encounter/metadata.yml +3 -0
  24. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/insurer/metadata.yml +1 -0
  25. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/medication_request/metadata.yml +2 -0
  26. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/metadata.yml +143 -0
  27. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/nutrition_order/metadata.yml +2 -0
  28. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/pas_inquiry_request_bundle/metadata.yml +2 -0
  29. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/pas_inquiry_response_bundle/metadata.yml +2 -0
  30. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/pas_request_bundle/metadata.yml +2 -0
  31. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/pas_response_bundle/metadata.yml +2 -0
  32. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/practitioner/metadata.yml +1 -0
  33. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/practitioner_role/metadata.yml +1 -0
  34. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/requestor/metadata.yml +1 -0
  35. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/service_request/metadata.yml +3 -0
  36. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/subscriber/metadata.yml +4 -0
  37. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/task/metadata.yml +1 -0
  38. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/beneficiary/metadata.yml +1 -0
  39. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/claim_inquiry/metadata.yml +23 -0
  40. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/claim_update/metadata.yml +31 -0
  41. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/claiminquiryresponse/metadata.yml +42 -0
  42. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/claimresponse/metadata.yml +42 -0
  43. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/communication_request/metadata.yml +4 -0
  44. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/coverage/metadata.yml +1 -0
  45. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/device_request/metadata.yml +2 -0
  46. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/encounter/metadata.yml +3 -0
  47. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/insurer/metadata.yml +1 -0
  48. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/medication_request/metadata.yml +2 -0
  49. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/metadata.yml +265 -0
  50. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/nutrition_order/metadata.yml +2 -0
  51. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/pas_inquiry_request_bundle/metadata.yml +2 -0
  52. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/pas_inquiry_response_bundle/metadata.yml +2 -0
  53. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/pas_request_bundle/metadata.yml +2 -0
  54. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/pas_response_bundle/metadata.yml +2 -0
  55. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/practitioner/metadata.yml +1 -0
  56. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/practitioner_role/metadata.yml +1 -0
  57. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/requestor/metadata.yml +1 -0
  58. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/service_request/metadata.yml +3 -0
  59. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/subscriber/metadata.yml +1 -0
  60. data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/task/metadata.yml +4 -0
  61. data/lib/davinci_pas_test_kit/cross_suite/pas_bundle_validation.rb +97 -39
  62. data/lib/davinci_pas_test_kit/cross_suite/pas_constants.rb +6 -0
  63. data/lib/davinci_pas_test_kit/cross_suite/pas_datatype_constraints.rb +166 -0
  64. data/lib/davinci_pas_test_kit/cross_suite/response_selection_utils.rb +26 -10
  65. data/lib/davinci_pas_test_kit/cross_suite/validator_suppressions.rb +206 -146
  66. data/lib/davinci_pas_test_kit/docs/demo/PAS Client Suite Demonstration.postman_collection.json +4 -4
  67. data/lib/davinci_pas_test_kit/generator/must_support_test_generator.rb +6 -0
  68. data/lib/davinci_pas_test_kit/generator/pas_must_support_metadata_extractor.rb +1 -2
  69. data/lib/davinci_pas_test_kit/generator/server_must_support_group_generator.rb +23 -0
  70. data/lib/davinci_pas_test_kit/generator/server_suite_generator.rb +6 -0
  71. data/lib/davinci_pas_test_kit/generator/templates/must_support.rb.erb +3 -2
  72. data/lib/davinci_pas_test_kit/generator/templates/server_must_support_group.rb.erb +22 -0
  73. data/lib/davinci_pas_test_kit/generator/templates/server_suite.rb.erb +4 -5
  74. data/lib/davinci_pas_test_kit/generator/templates/use_case_group.rb.erb +3 -0
  75. data/lib/davinci_pas_test_kit/generator/use_case_group_generator.rb +14 -8
  76. data/lib/davinci_pas_test_kit/requirements/generated/davinci_pas_server_suite_v221_requirements_coverage.csv +28 -28
  77. data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_server_approval_use_case_group.rb +1 -0
  78. data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_server_denial_use_case_group.rb +1 -0
  79. data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_server_pended_use_case_group.rb +1 -0
  80. data/lib/davinci_pas_test_kit/server/generated/v2.0.1/server_suite.rb +4 -5
  81. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/claiminquiryresponse/server_inquire_response_must_support_claiminquiryresponse_test.rb +2 -0
  82. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/claimresponse/server_submit_response_must_support_claimresponse_test.rb +2 -0
  83. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_server_approval_use_case_group.rb +2 -0
  84. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_server_denial_use_case_group.rb +2 -0
  85. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_server_must_support_group.rb +12 -0
  86. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_server_pended_use_case_group.rb +5 -0
  87. data/lib/davinci_pas_test_kit/server/generated/v2.2.1/server_suite.rb +4 -5
  88. data/lib/davinci_pas_test_kit/server/server_response_bundle_validation_test.rb +14 -5
  89. data/lib/davinci_pas_test_kit/server/v2.2.1/claim_inquiry/server_claim_inquiry_response_tests.rb +89 -0
  90. data/lib/davinci_pas_test_kit/server/v2.2.1/pas_error_group.rb +2 -0
  91. data/lib/davinci_pas_test_kit/server/v2.2.1/pas_server_claim_inquiry_responses_group.rb +17 -0
  92. data/lib/davinci_pas_test_kit/server/v2.2.1/pas_server_no_custom_extensions_test.rb +241 -0
  93. data/lib/davinci_pas_test_kit/server/v2.2.1/pas_server_subscription_capability_statement_test.rb +40 -0
  94. data/lib/davinci_pas_test_kit/server/v2.2.1/pas_server_subscription_setup.rb +14 -9
  95. data/lib/davinci_pas_test_kit/server/v2.2.1/server_replaced_pa_inquire_reference_input_test.rb +63 -0
  96. data/lib/davinci_pas_test_kit/server/v2.2.1/server_replaced_pa_inquire_reference_test.rb +109 -0
  97. data/lib/davinci_pas_test_kit/version.rb +2 -2
  98. metadata +9 -2
@@ -0,0 +1,89 @@
1
+ require_relative '../../../parameters_helper'
2
+ require_relative '../../../cross_suite/pas_constants'
3
+ require_relative '../../../cross_suite/tags'
4
+
5
+ module DaVinciPASTestKit
6
+ module DaVinciPASV221
7
+ module ServerClaimInquiryResponseValidation
8
+ include ParametersHelper
9
+
10
+ def inquiry_response_requests
11
+ load_tagged_requests(INQUIRE_TAG)
12
+ end
13
+
14
+ def response_bundles
15
+ inquiry_response_requests.flat_map do |request|
16
+ parsed_resource = parsed_response_resource(request)
17
+ next [] unless parsed_resource.is_a?(FHIR::Parameters)
18
+
19
+ extract_bundles_from_pas_inquiry_response_parameters(parsed_resource)
20
+ end
21
+ end
22
+
23
+ def parsed_response_resource(request)
24
+ return if request&.response_body.blank?
25
+
26
+ FHIR.from_contents(request.response_body)
27
+ rescue StandardError
28
+ nil
29
+ end
30
+
31
+ def claim_inquiry_responses
32
+ response_bundles.flat_map { |bundle| Array(bundle.entry).filter_map { |entry| entry&.resource } }
33
+ .grep(FHIR::ClaimResponse)
34
+ end
35
+
36
+ def claim_reference?(claim_response)
37
+ claim_response.request&.reference.present?
38
+ end
39
+
40
+ def data_absent_reason?(claim_response)
41
+ Array(claim_response.request&.extension).any? do |extension|
42
+ extension.url == PASConstants::DATA_ABSENT_REASON_EXTENSION_URL && extension.valueCode.present?
43
+ end
44
+ end
45
+
46
+ def claim_reference_or_data_absent_reason?(claim_response)
47
+ claim_reference?(claim_response) || data_absent_reason?(claim_response)
48
+ end
49
+
50
+ def claim_response_label(claim_response, index)
51
+ claim_response.id.present? ? "ClaimResponse/#{claim_response.id}" : "ClaimResponse at index #{index + 1}"
52
+ end
53
+ end
54
+
55
+ class PASServerClaimInquiryResponseClaimReferenceTest < Inferno::Test
56
+ include ServerClaimInquiryResponseValidation
57
+
58
+ id :pas_server_v221_claim_inquiry_response_claim_reference_test
59
+ title 'Server returns Claim Inquiry Responses with a Claim reference or Data Absent Reason'
60
+ description %(
61
+ The PAS IG [requires](https://hl7.org/fhir/us/davinci-pas/2.2.1/en/conformancedetails.html#ci-c-spec-44)
62
+ each Claim Inquiry Response to either reference the Claim that triggered adjudication or carry
63
+ a Data Absent Reason extension explaining why the Claim cannot be referenced.
64
+
65
+ This test examines ClaimResponse resources returned by prior `$inquire` requests and verifies that
66
+ each one includes either `ClaimResponse.request.reference` or the
67
+ `data-absent-reason` extension on `ClaimResponse.request`.
68
+ )
69
+ verifies_requirements 'hl7.fhir.us.davinci-pas_2.2.1@spec-44'
70
+
71
+ run do
72
+ claim_responses = claim_inquiry_responses
73
+ skip_if claim_responses.empty?,
74
+ 'No Claim Inquiry Response ClaimResponse resources were returned by prior $inquire requests.'
75
+
76
+ nonconformant = claim_responses.each_with_index.filter_map do |claim_response, index|
77
+ next if claim_reference_or_data_absent_reason?(claim_response)
78
+
79
+ claim_response_label(claim_response, index)
80
+ end
81
+
82
+ assert nonconformant.empty?,
83
+ 'The following Claim Inquiry Response resources did not include either ' \
84
+ '`ClaimResponse.request.reference` or a Data Absent Reason extension on ' \
85
+ "`ClaimResponse.request`: #{nonconformant.join(', ')}."
86
+ end
87
+ end
88
+ end
89
+ end
@@ -13,6 +13,8 @@ module DaVinciPASTestKit
13
13
  id :pas_v221_error_group
14
14
  run_as_group
15
15
 
16
+ verifies_requirements 'hl7.fhir.us.davinci-pas_2.2.1@spec-39'
17
+
16
18
  test from: :pas_server_v221_prior_auth_submission_error
17
19
  test from: :pas_server_v221_prior_auth_inquiry_error
18
20
  end
@@ -0,0 +1,17 @@
1
+ require_relative 'claim_inquiry/server_claim_inquiry_response_tests'
2
+
3
+ module DaVinciPASTestKit
4
+ module DaVinciPASV221
5
+ class PASServerClaimInquiryResponsesGroup < Inferno::TestGroup
6
+ id :pas_server_v221_claim_inquiry_responses
7
+ title 'Additional $inquire Response Requirements'
8
+ description %(
9
+ Verify additional PAS Claim Inquiry Response rules against the ClaimResponse resources returned
10
+ by prior `$inquire` interactions. This group uses the inquiry responses already collected during
11
+ the server suite, including the Must Support inquiry workflow.
12
+ )
13
+
14
+ test from: :pas_server_v221_claim_inquiry_response_claim_reference_test
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,241 @@
1
+ require_relative '../../cross_suite/tags'
2
+
3
+ module DaVinciPASTestKit
4
+ module DaVinciPASV221
5
+ class PasNoCustomExtensionsTest < Inferno::Test
6
+ US_CORE_EXTENSION_URLS = [
7
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex',
8
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-direct',
9
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity',
10
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-race',
11
+ 'http://hl7.org/fhir/us/core/StructureDefinition/uscdi-requirement',
12
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-extension-questionnaire-uri',
13
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-genderIdentity',
14
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-jurisdiction',
15
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-sex',
16
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-tribal-affiliation',
17
+ 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-medication-adherence',
18
+ 'http://hl7.org/fhir/StructureDefinition/condition-assertedDate'
19
+ ].freeze
20
+
21
+ CRD_EXTENSION_URLS = [
22
+ 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/ext-coverage-information',
23
+ 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/ext-billing-options',
24
+ 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/ext-request-category',
25
+ 'http://hl7.org/fhir/StructureDefinition/codeOptions',
26
+ 'http://hl7.org/fhir/StructureDefinition/alternate-reference',
27
+ 'http://hl7.org/fhir/5.0/StructureDefinition/extension-CommunicationRequest.payload.content',
28
+ 'http://hl7.org/fhir/5.0/StructureDefinition/extension-Task.requestedPeriod',
29
+ 'http://hl7.org/fhir/5.0/StructureDefinition/extension-Task.requestedPerformer',
30
+ 'http://hl7.org/fhir/5.0/StructureDefinition/extension-Task.performer',
31
+ 'http://hl7.org/fhir/StructureDefinition/request-doNotPerform',
32
+ 'http://hl7.org/fhir/5.0/StructureDefinition/extension-Task.input.value',
33
+ 'http://hl7.org/fhir/5.0/StructureDefinition/extension-Task.output.value',
34
+ 'http://hl7.org/fhir/5.0/StructureDefinition/extension-Task.statusReason'
35
+ ].freeze
36
+
37
+ HREX_EXTENSION_URLS = [
38
+ 'http://hl7.org/fhir/us/davinci-hrex/StructureDefinition/extension-CoverageDavinciWellknownLocation'
39
+ ].freeze
40
+
41
+ DTR_EXTENSION_URLS = [
42
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/activeRole',
43
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/alternativeExpression',
44
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/containedReference',
45
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/information-origin',
46
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/intendedUse',
47
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/qr-context',
48
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/estimated-completion-time',
49
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/questionnaireAudience',
50
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/qr-coverage',
51
+ 'http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/request-specific'
52
+ ].freeze
53
+
54
+ PAS_EXTENSION_URLS = [
55
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-TransmissionIdentifiers',
56
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-administrationReferenceNumber',
57
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-admissionDates',
58
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-authorizationNumber',
59
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-authorizedProviderType',
60
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-careTeamClaimScope',
61
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-certificationType',
62
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-claimResponseReviewer',
63
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-communicatedDiagnosis',
64
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-conditionCode',
65
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-contentModifier',
66
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-diagnosisRecordedDate',
67
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-dischargeDate',
68
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-documentInformation',
69
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-epsdtIndicator',
70
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-errorElement',
71
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-errorFollowupAction',
72
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-errorPath',
73
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-homeHealthCareInformation',
74
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-identifierJurisdiction',
75
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-identifierSubDepartment',
76
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-infoChanged',
77
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemAuthorizedDetail',
78
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemAuthorizedProvider',
79
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemCategory',
80
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemCertificationEffectiveDate',
81
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemCertificationExpirationDate',
82
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemCertificationIssueDate',
83
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemPreAuthIssueDate',
84
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemPreAuthPeriod',
85
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemRequestedServiceDate',
86
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-itemTraceNumber',
87
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-levelOfServiceCode',
88
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-militaryStatus',
89
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-nursingHomeLevelOfCare',
90
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-nursingHomeResidentialStatus',
91
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-patientStatus',
92
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-productOrServiceCodeEnd',
93
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-requestedService',
94
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-revenueCode',
95
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-revenueUnitRateLimit',
96
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewAction',
97
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewActionCode',
98
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-serviceItemRequestType',
99
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-serviceLineNumber',
100
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-timingcalendarpattern',
101
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-timingdeliverypattern',
102
+ 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/modifierextension-infoCancelled',
103
+ 'http://hl7.org/fhir/5.0/StructureDefinition/extension-Claim.encounter',
104
+ 'http://hl7.org/fhir/StructureDefinition/data-absent-reason',
105
+ 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-filter-criteria',
106
+ 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-heartbeat-period',
107
+ 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-timeout',
108
+ 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-max-count',
109
+ 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-channel-type',
110
+ 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-payload-content',
111
+ 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/capabilitystatement-subscriptiontopic-canonical'
112
+ ].freeze
113
+
114
+ SDC_EXTENSION_URLS = [
115
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerExpression',
116
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerOptionsToggleExpression',
117
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-assemble-expectation',
118
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-assembleContext',
119
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-assembleDefinitionRoot',
120
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-assembledFrom',
121
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression',
122
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-candidateExpression',
123
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-choiceColumn',
124
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-collapsible',
125
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-columnCount',
126
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-contextExpression',
127
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-definitionExtract',
128
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-definitionExtractValue',
129
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression',
130
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-endpoint',
131
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-entryMode',
132
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-extractAllocateId',
133
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression',
134
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject',
135
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemAnswerMedia',
136
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemExtractionContext',
137
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemMedia',
138
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemPopulationContext',
139
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-keyboard',
140
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-launchContext',
141
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-lookupQuestionnaire',
142
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-maxQuantity',
143
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-minQuantity',
144
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observation-extract-category',
145
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationExtract',
146
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationExtractEntry',
147
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod',
148
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-openLabel',
149
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay',
150
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-performerType',
151
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-preferredTerminologyServer',
152
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-questionnaireAdaptive',
153
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-shortText',
154
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-sourceQueries',
155
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-sourceStructureMap',
156
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-subQuestionnaire',
157
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-targetStructureMap',
158
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-templateExtract',
159
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-templateExtractBundle',
160
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-templateExtractContext',
161
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-templateExtractValue',
162
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-unitOpen',
163
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-unitSupplementalSystem',
164
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-width',
165
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaireresponse-isSubject',
166
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-rendering-criticalExtension',
167
+ 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-servicerequest-questionnaire'
168
+ ].freeze
169
+
170
+ VALID_EXTENSION_URLS = (US_CORE_EXTENSION_URLS + CRD_EXTENSION_URLS + HREX_EXTENSION_URLS \
171
+ + SDC_EXTENSION_URLS + DTR_EXTENSION_URLS + PAS_EXTENSION_URLS).freeze
172
+
173
+ id :pas_server_v221_no_custom_extensions_test
174
+ title 'Server processes $submit without custom extensions'
175
+ description %(
176
+ This test verifies that the server is capable of responding to a client
177
+ without the use of any custom extensions. It inspects each successful
178
+ PAS submission, and if it finds one which doesn't use any extensions
179
+ not defined by FHIR, US Core, PAS, CRD, DTR, or HRex it passes.
180
+ )
181
+
182
+ verifies_requirements 'hl7.fhir.us.davinci-pas_2.2.1@conf-11'
183
+
184
+ run do
185
+ requests = load_tagged_requests(SUBMIT_TAG)
186
+ skip_if requests.blank?, 'No requests were made in a previous test as expected.'
187
+
188
+ successful_requests = requests.select { |request| request.status == 200 }
189
+ skip_if successful_requests.empty?, 'All service requests were unsuccessful.'
190
+
191
+ bundles = successful_requests.filter_map { |request| bundle_from_request(request) }
192
+ skip_if bundles.empty?, 'No PAS Request Bundles were found in successful submissions.'
193
+
194
+ request_with_no_custom_extensions = bundles.any? { |bundle| no_custom_extensions?(bundle) }
195
+
196
+ pass_if request_with_no_custom_extensions
197
+
198
+ custom_extensions_string =
199
+ bundles
200
+ .flat_map { |bundle| custom_extensions(bundle) }
201
+ .uniq
202
+ .map { |extension| "\n- `#{extension}`" }
203
+ .join
204
+
205
+ skip 'No requests were made without custom extensions. The following custom extensions were found: ' \
206
+ "#{custom_extensions_string}"
207
+ end
208
+
209
+ def bundle_from_request(request)
210
+ resource = FHIR.from_contents(request.request_body)
211
+ resource if resource.is_a?(FHIR::Bundle)
212
+ rescue JSON::ParserError
213
+ nil
214
+ end
215
+
216
+ def no_custom_extensions?(bundle)
217
+ bundle.each_element do |value, _metadata, path|
218
+ next unless value.is_a?(FHIR::Extension)
219
+
220
+ next if path.to_s.scan('extension').length > 1
221
+
222
+ return false unless VALID_EXTENSION_URLS.include?(value.url.to_s)
223
+ end
224
+
225
+ true
226
+ end
227
+
228
+ def custom_extensions(bundle)
229
+ [].tap do |custom_extensions|
230
+ bundle.each_element do |value, _metadata, path|
231
+ next unless value.is_a?(FHIR::Extension)
232
+
233
+ next if path.to_s.scan('extension').length > 1
234
+
235
+ custom_extensions << value.url.to_s unless VALID_EXTENSION_URLS.include?(value.url.to_s)
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,40 @@
1
+ module DaVinciPASTestKit
2
+ module DaVinciPASV221
3
+ class PASServerSubscriptionCapabilityStatementTest < Inferno::Test
4
+ id :pas_server_v221_subscription_capability_statement_test
5
+ title 'Server Capability Statement declares Subscription create, update, and delete support'
6
+ description %(
7
+ The PAS IG [requires](https://hl7.org/fhir/us/davinci-pas/2.2.1/en/specification.html#ci-c-spec-55)
8
+ servers that support subscriptions to expose that support in their CapabilityStatement. This test retrieves
9
+ the CapabilityStatement and verifies that its server-mode Subscription resource declares the create, update,
10
+ and delete interactions.
11
+ )
12
+
13
+ verifies_requirements 'hl7.fhir.us.davinci-pas_2.2.1@spec-55'
14
+
15
+ REQUIRED_INTERACTIONS = ['create', 'update', 'delete'].freeze
16
+
17
+ run do
18
+ fhir_get_capability_statement
19
+
20
+ assert_response_status(200)
21
+ assert_resource_type(:capability_statement)
22
+ assert_valid_resource
23
+
24
+ server_rest = resource.rest.find { |rest| rest.mode == 'server' }
25
+ assert server_rest.present?, 'CapabilityStatement is missing a `rest` entry with `mode` set to `server`.'
26
+
27
+ subscription_resource = server_rest.resource.find { |entry| entry.type == 'Subscription' }
28
+ assert subscription_resource.present?,
29
+ 'CapabilityStatement is missing a `Subscription` resource entry in its server-mode `rest` section.'
30
+
31
+ supported_interactions = subscription_resource.interaction.map(&:code)
32
+
33
+ missing_interactions = REQUIRED_INTERACTIONS - supported_interactions
34
+
35
+ assert missing_interactions.empty?,
36
+ "Missing interactions in the subscription: #{missing_interactions.join(', ')}"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,4 +1,5 @@
1
1
  require 'subscriptions_test_kit'
2
+ require_relative 'pas_server_subscription_capability_statement_test'
2
3
  require_relative 'pas_server_subscription_input_conformance'
3
4
 
4
5
  module DaVinciPASTestKit
@@ -15,6 +16,8 @@ module DaVinciPASTestKit
15
16
  input_order :server_endpoint, :smart_credentials, :access_token, :subscription_resource
16
17
  run_as_group
17
18
 
19
+ test from: :pas_server_v221_subscription_capability_statement_test
20
+
18
21
  test from: :pas_server_v221_subscription_input_conformance do
19
22
  input :subscription_resource,
20
23
  title: 'Pended Prior Authorization Subscription',
@@ -26,15 +29,17 @@ module DaVinciPASTestKit
26
29
  modify the Subscription before submission, e.g., to point to Inferno's notification endpoint.
27
30
  )
28
31
  end
29
- test from: :subscriptions_r4_server_notification_delivery,
30
- title: 'Send Subscription and Receive Handshake Notification from Server',
31
- description: %(
32
- This test sends a request to create the Subscription resource to the Subscriptions Backport FHIR Server.
33
- If successful, it then waits for a handshake
34
- [notification](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/notifications.html#notifications).
35
- Other types of notifications, including heartbeat and event notifications, will be accepted by Inferno
36
- but ignored by this test group.
37
- )
32
+ test from: :subscriptions_r4_server_notification_delivery do
33
+ title 'Send Subscription and Receive Handshake Notification from Server'
34
+ description %(
35
+ This test sends a request to create the Subscription resource to the Subscriptions Backport FHIR Server.
36
+ If successful, it then waits for a handshake
37
+ [notification](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/notifications.html#notifications).
38
+ Other types of notifications, including heartbeat and event notifications, will be accepted by Inferno
39
+ but ignored by this test group.
40
+ )
41
+ verifies_requirements(*(verifies_requirements + ['hl7.fhir.us.davinci-pas_2.2.1@spec-54']))
42
+ end
38
43
  test from: :subscriptions_r4_server_creation_response_conformance
39
44
  test from: :subscriptions_r4_server_handshake_conformance
40
45
  end
@@ -0,0 +1,63 @@
1
+ require_relative '../../cross_suite/pas_constants'
2
+
3
+ module DaVinciPASTestKit
4
+ module DaVinciPASV221
5
+ class PASServerReplacedPAInquireReferenceInputTest < Inferno::Test
6
+ include PASConstants
7
+
8
+ id :pas_server_v221_replaced_pa_inquire_reference_input_test
9
+ title 'Provided $inquire Request contains a replaced prior authorization reference'
10
+ description %(
11
+ Provide one or more PAS Inquiry Request Bundles, at least one of which contains
12
+ an authorization number or administration reference number.
13
+ )
14
+
15
+ simulation_verification
16
+
17
+ input :must_support_pa_inquire_request_payload,
18
+ title: 'Additional $inquire Request Payloads',
19
+ description: 'Insert an additional request bundle or a list of bundles (e.g. [bundle_1, bundle_2])'
20
+
21
+ run do
22
+ skip_if must_support_pa_inquire_request_payload.blank?,
23
+ 'No inquiry request body was provided.'
24
+
25
+ assert_valid_json(
26
+ must_support_pa_inquire_request_payload,
27
+ 'Provide a valid JSON PAS Inquiry Request Bundle.'
28
+ )
29
+
30
+ parsed_payload = JSON.parse(must_support_pa_inquire_request_payload)
31
+ request_payloads = Array.wrap(parsed_payload)
32
+
33
+ assert request_payloads.present?,
34
+ 'No inquiry Request Bundles were provided.'
35
+
36
+ request_bundles = request_payloads.map do |request_payload|
37
+ FHIR.from_contents(request_payload.to_json)
38
+ end
39
+
40
+ assert request_bundles.all?(FHIR::Bundle),
41
+ 'Each inquiry request body must be a FHIR Bundle.'
42
+
43
+ assert request_bundles.any? { |request_bundle| reference_numbers(request_bundle).present? },
44
+ 'The inquiry requests did not contain an authorization number or ' \
45
+ 'administration reference number.'
46
+ end
47
+
48
+ def reference_numbers(bundle)
49
+ bundle.entry.flat_map do |entry|
50
+ resource = entry.resource
51
+ next [] unless resource.respond_to?(:item)
52
+
53
+ resource.item.flat_map do |item|
54
+ item.extension.filter_map do |extension|
55
+ extension.valueString if REFERENCE_NUMBER_EXTENSIONS.value?(extension.url) &&
56
+ extension.valueString.present?
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,109 @@
1
+ require_relative '../../parameters_helper'
2
+ require_relative '../../cross_suite/pas_constants'
3
+
4
+ module DaVinciPASTestKit
5
+ module DaVinciPASV221
6
+ class PASServerReplacedPAInquireReferenceTest < Inferno::Test
7
+ include ParametersHelper
8
+ include PASConstants
9
+
10
+ id :pas_server_v221_replaced_pa_inquire_reference_test
11
+ title 'Server returns a different reference number for a replaced prior authorization'
12
+ description %(
13
+ This test submits a tester provided Request Bundle containing a
14
+ reference number. The request should result in a response that returns a
15
+ different reference number, indicating that the original prior authorization
16
+ has been replaced.
17
+ )
18
+
19
+ verifies_requirements 'hl7.fhir.us.davinci-pas_2.2.1@spec-47'
20
+
21
+ makes_request :pa_inquire_request
22
+
23
+ input :must_support_pa_inquire_request_payload,
24
+ title: 'Additional $inquire Request Payloads',
25
+ description: 'Insert an additional request bundle or a list of bundles (e.g. [bundle_1, bundle_2])'
26
+
27
+ run do
28
+ skip_if must_support_pa_inquire_request_payload.blank?,
29
+ 'No inquiry request body was provided.'
30
+
31
+ assert_valid_json(
32
+ must_support_pa_inquire_request_payload,
33
+ 'Provide a valid JSON PAS Inquiry Request Bundle.'
34
+ )
35
+ parsed_payload = JSON.parse(must_support_pa_inquire_request_payload)
36
+ request_payloads = Array.wrap(parsed_payload)
37
+
38
+ reference_comparisons = request_payloads.map do |request_payload|
39
+ request_resource = FHIR.from_contents(request_payload.to_json)
40
+
41
+ submitted_references = extract_references([request_resource])
42
+
43
+ fhir_operation(
44
+ '/Claim/$inquire',
45
+ body: request_resource,
46
+ name: :pa_inquire_request
47
+ )
48
+
49
+ assert_response_status(200)
50
+
51
+ response_bundles =
52
+ if resource.is_a?(FHIR::Parameters)
53
+ extract_bundles_from_pas_inquiry_response_parameters(resource)
54
+ elsif resource.is_a?(FHIR::Bundle)
55
+ [resource]
56
+ else
57
+ assert false, '$inquire response is neither Parameters or Bundle'
58
+ end
59
+
60
+ assert response_bundles.any?,
61
+ 'The $inquire response did not contain a response Bundle.'
62
+
63
+ returned_references = extract_references(response_bundles)
64
+
65
+ different_reference?(submitted_references, returned_references)
66
+ end
67
+
68
+ assert reference_comparisons.any?,
69
+ 'Expected an inquiry response to contain a different authorization number or ' \
70
+ 'administration reference number, but it did not.'
71
+ end
72
+
73
+ def extract_references(bundles)
74
+ bundles.each_with_object(
75
+ Hash.new { |hash, url| hash[url] = [] }
76
+ ) do |bundle, references|
77
+ next unless bundle.is_a?(FHIR::Bundle)
78
+
79
+ bundle.entry.each do |entry|
80
+ resource = entry.resource
81
+ next unless resource.respond_to?(:item)
82
+
83
+ resource.item.each do |item|
84
+ item.extension.each do |extension|
85
+ next unless REFERENCE_NUMBER_EXTENSIONS.value?(extension.url)
86
+ next if extension.valueString.blank?
87
+
88
+ references[extension.url] << extension.valueString
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ def different_reference?(submitted, returned)
96
+ REFERENCE_NUMBER_EXTENSIONS.each_value.any? do |extension_url|
97
+ submitted_values = submitted[extension_url]
98
+ returned_values = returned[extension_url]
99
+
100
+ next false if submitted_values.empty? || returned_values.empty?
101
+
102
+ returned_values.any? do |returned_value|
103
+ submitted_values.exclude?(returned_value)
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DaVinciPASTestKit
4
- VERSION = '0.15.0'
5
- LAST_UPDATED = '2025-07-13'
4
+ VERSION = '0.15.2'
5
+ LAST_UPDATED = '2026-09-08'
6
6
  end