davinci_pas_test_kit 0.15.2 → 0.16.0
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.
- checksums.yaml +4 -4
- data/config/presets/g33_br_provider.json +13 -0
- data/lib/davinci_pas_test_kit/client/abstract_approval_submit_test.rb +28 -17
- data/lib/davinci_pas_test_kit/client/abstract_denial_submit_test.rb +26 -16
- data/lib/davinci_pas_test_kit/client/abstract_gather_must_support_test.rb +43 -26
- data/lib/davinci_pas_test_kit/client/abstract_modification_submit_test.rb +29 -19
- data/lib/davinci_pas_test_kit/client/abstract_response_attest.rb +75 -6
- data/lib/davinci_pas_test_kit/client/abstract_subscription_create_test.rb +26 -9
- data/lib/davinci_pas_test_kit/client/abstract_subscription_update_delete_test.rb +91 -0
- data/lib/davinci_pas_test_kit/client/client_bundle_validation_helper.rb +245 -0
- data/lib/davinci_pas_test_kit/client/client_input_descriptions.rb +91 -25
- data/lib/davinci_pas_test_kit/client/endpoints/claim_endpoint.rb +108 -68
- data/lib/davinci_pas_test_kit/client/endpoints/endpoint_session_identification.rb +24 -0
- data/lib/davinci_pas_test_kit/client/endpoints/expired_token.rb +40 -0
- data/lib/davinci_pas_test_kit/client/endpoints/subscription_create_endpoint.rb +7 -12
- data/lib/davinci_pas_test_kit/client/endpoints/subscription_delete_endpoint.rb +13 -0
- data/lib/davinci_pas_test_kit/client/endpoints/subscription_read_endpoint.rb +13 -0
- data/lib/davinci_pas_test_kit/client/endpoints/subscription_status_endpoint.rb +15 -20
- data/lib/davinci_pas_test_kit/client/endpoints/subscription_update_endpoint.rb +13 -0
- data/lib/davinci_pas_test_kit/client/endpoints/token_endpoint.rb +16 -0
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/beneficiary/client_inquire_request_must_support_beneficiary_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/beneficiary/client_inquire_response_must_support_beneficiary_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/beneficiary/client_submit_request_must_support_beneficiary_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/beneficiary/client_submit_response_must_support_beneficiary_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/claim_inquiry/client_inquire_request_must_support_claim_inquiry_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/claim_update/client_submit_request_must_support_claim_update_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/claiminquiryresponse/client_inquire_response_must_support_claiminquiryresponse_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/claimresponse/client_submit_response_must_support_claimresponse_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/communication_request/client_submit_response_must_support_communication_request_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/coverage/client_inquire_request_must_support_coverage_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/coverage/client_submit_request_must_support_coverage_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/encounter/client_submit_request_must_support_encounter_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/insurer/client_inquire_request_must_support_insurer_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/insurer/client_inquire_response_must_support_insurer_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/insurer/client_submit_request_must_support_insurer_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/insurer/client_submit_response_must_support_insurer_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/pas_client_inquire_must_support_group.rb +1 -1
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/pas_client_inquire_response_must_support_group.rb +9 -31
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/pas_client_submit_must_support_group.rb +1 -1
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/pas_client_submit_response_must_support_group.rb +10 -32
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/pas_inquiry_request_bundle/client_inquire_request_must_support_pas_inquiry_request_bundle_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/pas_inquiry_response_bundle/client_inquire_response_must_support_pas_inquiry_response_bundle_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/pas_request_bundle/client_submit_request_must_support_pas_request_bundle_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/pas_response_bundle/client_submit_response_must_support_pas_response_bundle_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/practitioner/client_inquire_request_must_support_practitioner_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/practitioner/client_inquire_response_must_support_practitioner_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/practitioner/client_submit_request_must_support_practitioner_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/practitioner/client_submit_response_must_support_practitioner_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/practitioner_role/client_inquire_request_must_support_practitioner_role_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/practitioner_role/client_inquire_response_must_support_practitioner_role_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/practitioner_role/client_submit_request_must_support_practitioner_role_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/practitioner_role/client_submit_response_must_support_practitioner_role_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/requestor/client_inquire_request_must_support_requestor_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/requestor/client_inquire_response_must_support_requestor_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/requestor/client_submit_request_must_support_requestor_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/requestor/client_submit_response_must_support_requestor_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/subscriber/client_inquire_request_must_support_subscriber_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/subscriber/client_submit_request_must_support_subscriber_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/beneficiary/client_inquire_response_must_support_beneficiary_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/beneficiary/client_submit_response_must_support_beneficiary_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/claim_inquiry/client_inquire_request_must_support_claim_inquiry_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/claim_update/client_submit_request_must_support_claim_update_test.rb +3 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/claiminquiryresponse/client_inquire_response_must_support_claiminquiryresponse_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/claimresponse/client_submit_response_must_support_claimresponse_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/communication_request/client_submit_response_must_support_communication_request_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/insurer/client_inquire_response_must_support_insurer_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/insurer/client_submit_response_must_support_insurer_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/pas_client_inquire_must_support_group.rb +8 -6
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/pas_client_inquire_response_must_support_group.rb +9 -31
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/pas_client_submit_must_support_group.rb +13 -9
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/pas_client_submit_response_must_support_group.rb +10 -32
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/pas_inquiry_response_bundle/client_inquire_response_must_support_pas_inquiry_response_bundle_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/pas_response_bundle/client_submit_response_must_support_pas_response_bundle_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/practitioner/client_inquire_response_must_support_practitioner_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/practitioner/client_submit_response_must_support_practitioner_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/practitioner_role/client_inquire_response_must_support_practitioner_role_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/practitioner_role/client_submit_response_must_support_practitioner_role_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/requestor/client_inquire_response_must_support_requestor_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/requestor/client_submit_response_must_support_requestor_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/jobs/send_pas_subscription_notification.rb +64 -3
- data/lib/davinci_pas_test_kit/client/pas_client_subscription_pas_conformance_test.rb +4 -3
- data/lib/davinci_pas_test_kit/client/registration/abstract_configuration_other_display_test.rb +6 -4
- data/lib/davinci_pas_test_kit/client/registration/abstract_configuration_smart_display_test.rb +8 -4
- data/lib/davinci_pas_test_kit/client/registration/abstract_configuration_udap_display_test.rb +9 -4
- data/lib/davinci_pas_test_kit/client/registration/abstract_other_auth_attest_test.rb +5 -4
- data/lib/davinci_pas_test_kit/client/request_count_gating.rb +14 -0
- data/lib/davinci_pas_test_kit/client/response_generator.rb +50 -9
- data/lib/davinci_pas_test_kit/client/session_identification.rb +26 -7
- data/lib/davinci_pas_test_kit/client/subscription_notification_trigger.rb +80 -0
- data/lib/davinci_pas_test_kit/client/subscription_setup_requirement.rb +59 -0
- data/lib/davinci_pas_test_kit/client/user_input_response.rb +27 -6
- data/lib/davinci_pas_test_kit/client/v2.0.1/client_suite.rb +30 -15
- data/lib/davinci_pas_test_kit/client/v2.0.1/must_support/pas_client_must_support_request_profiles_test.rb +2 -2
- data/lib/davinci_pas_test_kit/client/v2.0.1/pas_client_approval_group.rb +8 -7
- data/lib/davinci_pas_test_kit/client/v2.0.1/pas_client_auth_smart_group.rb +4 -4
- data/lib/davinci_pas_test_kit/client/v2.0.1/pas_client_auth_udap_group.rb +4 -4
- data/lib/davinci_pas_test_kit/client/v2.0.1/pas_client_denial_group.rb +8 -7
- data/lib/davinci_pas_test_kit/client/v2.0.1/pas_client_must_support_group.rb +38 -52
- data/lib/davinci_pas_test_kit/client/v2.0.1/pas_client_pended_group.rb +28 -22
- data/lib/davinci_pas_test_kit/client/v2.0.1/pas_client_registration_group.rb +2 -2
- data/lib/davinci_pas_test_kit/client/v2.0.1/pas_client_subscription_setup_group.rb +2 -2
- data/lib/davinci_pas_test_kit/client/v2.0.1/pas_client_workflows_group.rb +2 -2
- data/lib/davinci_pas_test_kit/client/v2.0.1/workflows/pas_client_inquire_request_bundle_validation_test.rb +15 -21
- data/lib/davinci_pas_test_kit/client/v2.0.1/workflows/pas_client_inquire_response_bundle_validation_test.rb +29 -29
- data/lib/davinci_pas_test_kit/client/v2.0.1/workflows/pas_client_pended_submit_test.rb +49 -40
- data/lib/davinci_pas_test_kit/client/v2.0.1/workflows/pas_client_request_bundle_validation_test.rb +15 -21
- data/lib/davinci_pas_test_kit/client/v2.0.1/workflows/pas_client_response_bundle_validation_test.rb +29 -29
- data/lib/davinci_pas_test_kit/client/v2.2.1/attestations/attestation_instructions.rb +10 -0
- data/lib/davinci_pas_test_kit/client/v2.2.1/attestations/client_data_element_expectations_attestation_test.rb +44 -0
- data/lib/davinci_pas_test_kit/client/v2.2.1/attestations/client_provider_review_attestation_test.rb +45 -0
- data/lib/davinci_pas_test_kit/client/v2.2.1/attestations/client_security_attestation_test.rb +42 -0
- data/lib/davinci_pas_test_kit/client/v2.2.1/attestations/client_subscription_error_recovery_attestation_test.rb +42 -0
- data/lib/davinci_pas_test_kit/client/v2.2.1/client_suite.rb +64 -12
- data/lib/davinci_pas_test_kit/client/v2.2.1/error_handling/pas_client_operation_failure_submit_test.rb +20 -10
- data/lib/davinci_pas_test_kit/client/v2.2.1/error_handling/pas_client_operation_outcome_validation_test.rb +11 -5
- data/lib/davinci_pas_test_kit/client/v2.2.1/error_handling/pas_client_processing_error_response_validation_test.rb +21 -12
- data/lib/davinci_pas_test_kit/client/v2.2.1/error_handling/pas_client_processing_error_submit_test.rb +19 -8
- data/lib/davinci_pas_test_kit/client/v2.2.1/must_support/must_support_with_attestation_option.rb +90 -40
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_approval_group.rb +12 -11
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_attestations_group.rb +32 -0
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_auth_smart_group.rb +4 -4
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_auth_udap_group.rb +4 -4
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_claim_updates_group.rb +24 -6
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_denial_group.rb +12 -10
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_modification_group.rb +13 -14
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_must_support_group.rb +55 -59
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_operation_failure_group.rb +8 -5
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_pended_group.rb +53 -41
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_processing_error_group.rb +9 -7
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_registration_group.rb +2 -2
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_subscription_setup_group.rb +9 -4
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_subscription_update_delete_group.rb +57 -0
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_workflows_group.rb +22 -2
- data/lib/davinci_pas_test_kit/client/v2.2.1/subscription/pas_client_subscription_create_test.rb +2 -1
- data/lib/davinci_pas_test_kit/client/v2.2.1/subscription/pas_client_subscription_put_update_pas_conformance_test.rb +49 -0
- data/lib/davinci_pas_test_kit/client/v2.2.1/subscription/pas_client_subscription_update_delete_test.rb +12 -0
- data/lib/davinci_pas_test_kit/client/v2.2.1/workflows/pas_client_claim_update_referenced_resources_test.rb +5 -6
- data/lib/davinci_pas_test_kit/client/v2.2.1/workflows/pas_client_claim_update_submit_tests.rb +82 -56
- data/lib/davinci_pas_test_kit/client/v2.2.1/workflows/pas_client_inquire_request_bundle_validation_test.rb +17 -20
- data/lib/davinci_pas_test_kit/client/v2.2.1/workflows/pas_client_inquire_response_bundle_validation_test.rb +59 -27
- data/lib/davinci_pas_test_kit/client/v2.2.1/workflows/pas_client_modification_verification_test.rb +0 -3
- data/lib/davinci_pas_test_kit/client/v2.2.1/workflows/pas_client_pended_send_notification_test.rb +138 -0
- data/lib/davinci_pas_test_kit/client/v2.2.1/workflows/pas_client_pended_submit_test.rb +32 -85
- data/lib/davinci_pas_test_kit/client/v2.2.1/workflows/pas_client_request_bundle_validation_test.rb +16 -21
- data/lib/davinci_pas_test_kit/client/v2.2.1/workflows/pas_client_response_bundle_validation_test.rb +27 -27
- data/lib/davinci_pas_test_kit/cross_suite/generated/v2.0.1/task/metadata.yml +0 -4
- data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/metadata.yml +0 -1
- data/lib/davinci_pas_test_kit/cross_suite/generated/v2.2.1/task/metadata.yml +0 -4
- data/lib/davinci_pas_test_kit/cross_suite/pas_bundle_validation.rb +489 -289
- data/lib/davinci_pas_test_kit/cross_suite/pas_constants.rb +7 -0
- data/lib/davinci_pas_test_kit/cross_suite/pas_subscription_verification.rb +8 -4
- data/lib/davinci_pas_test_kit/cross_suite/referenced_resource_presence_validation.rb +141 -0
- data/lib/davinci_pas_test_kit/cross_suite/response_selection_utils.rb +13 -11
- data/lib/davinci_pas_test_kit/cross_suite/tags.rb +11 -6
- data/lib/davinci_pas_test_kit/cross_suite/validator_configuration.rb +16 -0
- data/lib/davinci_pas_test_kit/cross_suite/validator_suppressions.rb +4 -0
- data/lib/davinci_pas_test_kit/docs/demo/PAS Client Suite Demonstration.postman_collection.json +3 -3
- data/lib/davinci_pas_test_kit/ext/inferno_core/runnable.rb +1 -0
- data/lib/davinci_pas_test_kit/generator/client_must_support_group_generator.rb +47 -16
- data/lib/davinci_pas_test_kit/generator/must_support_target_profiles.rb +17 -0
- data/lib/davinci_pas_test_kit/generator/must_support_test_generator.rb +8 -2
- data/lib/davinci_pas_test_kit/generator/profile_metadata.rb +1 -1
- data/lib/davinci_pas_test_kit/generator/server_suite_generator.rb +4 -9
- data/lib/davinci_pas_test_kit/generator/templates/client_must_support_group.rb.erb +22 -3
- data/lib/davinci_pas_test_kit/generator/templates/client_must_support_response_group.rb.erb +7 -16
- data/lib/davinci_pas_test_kit/generator/templates/must_support.rb.erb +8 -8
- data/lib/davinci_pas_test_kit/generator/templates/server_suite.rb.erb +6 -7
- data/lib/davinci_pas_test_kit/generator/use_case_group_generator.rb +5 -5
- data/lib/davinci_pas_test_kit/parameters_helper.rb +13 -5
- data/lib/davinci_pas_test_kit/pas_notification_conformance_test.rb +2 -2
- data/lib/davinci_pas_test_kit/requirements/davinci_pas_test_kit_requirements.csv +14 -7
- data/lib/davinci_pas_test_kit/requirements/generated/davinci_pas_client_suite_v201_requirements_coverage.csv +21 -21
- data/lib/davinci_pas_test_kit/requirements/generated/davinci_pas_client_suite_v221_requirements_coverage.csv +30 -26
- data/lib/davinci_pas_test_kit/requirements/generated/davinci_pas_server_suite_v221_requirements_coverage.csv +12 -6
- data/lib/davinci_pas_test_kit/requirements/hl7.fhir.us.davinci-pas_2.2.1_requirements.xlsx +0 -0
- data/lib/davinci_pas_test_kit/server/claim_operation_logic.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/beneficiary/server_inquire_request_must_support_beneficiary_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/beneficiary/server_inquire_response_must_support_beneficiary_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/beneficiary/server_submit_request_must_support_beneficiary_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/beneficiary/server_submit_response_must_support_beneficiary_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/claim_inquiry/server_inquire_request_must_support_claim_inquiry_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/claim_update/server_submit_request_must_support_claim_update_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/claiminquiryresponse/server_inquire_response_must_support_claiminquiryresponse_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/claimresponse/server_submit_response_must_support_claimresponse_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/communication_request/server_submit_response_must_support_communication_request_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/coverage/server_inquire_request_must_support_coverage_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/coverage/server_submit_request_must_support_coverage_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/encounter/server_submit_request_must_support_encounter_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/insurer/server_inquire_request_must_support_insurer_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/insurer/server_inquire_response_must_support_insurer_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/insurer/server_submit_request_must_support_insurer_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/insurer/server_submit_response_must_support_insurer_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_inquiry_request_bundle/server_inquire_request_must_support_pas_inquiry_request_bundle_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_inquiry_response_bundle/server_inquire_response_must_support_pas_inquiry_response_bundle_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_request_bundle/server_submit_request_must_support_pas_request_bundle_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_response_bundle/server_submit_response_must_support_pas_response_bundle_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_server_approval_use_case_group.rb +3 -3
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_server_denial_use_case_group.rb +3 -3
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/pas_server_pended_use_case_group.rb +6 -6
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/practitioner/server_inquire_request_must_support_practitioner_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/practitioner/server_inquire_response_must_support_practitioner_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/practitioner/server_submit_request_must_support_practitioner_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/practitioner/server_submit_response_must_support_practitioner_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/practitioner_role/server_inquire_request_must_support_practitioner_role_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/practitioner_role/server_inquire_response_must_support_practitioner_role_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/practitioner_role/server_submit_request_must_support_practitioner_role_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/practitioner_role/server_submit_response_must_support_practitioner_role_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/requestor/server_inquire_request_must_support_requestor_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/requestor/server_inquire_response_must_support_requestor_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/requestor/server_submit_request_must_support_requestor_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/requestor/server_submit_response_must_support_requestor_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/server_suite.rb +6 -7
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/subscriber/server_inquire_request_must_support_subscriber_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/subscriber/server_submit_request_must_support_subscriber_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/task/server_inquire_response_must_support_task_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.0.1/task/server_submit_response_must_support_task_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/beneficiary/server_inquire_request_must_support_beneficiary_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/beneficiary/server_inquire_response_must_support_beneficiary_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/beneficiary/server_submit_request_must_support_beneficiary_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/beneficiary/server_submit_response_must_support_beneficiary_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/claim_inquiry/server_inquire_request_must_support_claim_inquiry_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/claim_update/server_submit_request_must_support_claim_update_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/claiminquiryresponse/server_inquire_response_must_support_claiminquiryresponse_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/claimresponse/server_submit_response_must_support_claimresponse_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/communication_request/server_submit_response_must_support_communication_request_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/coverage/server_inquire_request_must_support_coverage_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/coverage/server_submit_request_must_support_coverage_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/encounter/server_submit_request_must_support_encounter_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/insurer/server_inquire_request_must_support_insurer_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/insurer/server_inquire_response_must_support_insurer_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/insurer/server_submit_request_must_support_insurer_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/insurer/server_submit_response_must_support_insurer_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_inquiry_request_bundle/server_inquire_request_must_support_pas_inquiry_request_bundle_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_inquiry_response_bundle/server_inquire_response_must_support_pas_inquiry_response_bundle_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_request_bundle/server_submit_request_must_support_pas_request_bundle_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_response_bundle/server_submit_response_must_support_pas_response_bundle_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_server_approval_use_case_group.rb +3 -3
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_server_denial_use_case_group.rb +3 -3
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/pas_server_pended_use_case_group.rb +4 -4
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/practitioner/server_inquire_request_must_support_practitioner_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/practitioner/server_inquire_response_must_support_practitioner_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/practitioner/server_submit_request_must_support_practitioner_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/practitioner/server_submit_response_must_support_practitioner_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/practitioner_role/server_inquire_request_must_support_practitioner_role_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/practitioner_role/server_inquire_response_must_support_practitioner_role_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/practitioner_role/server_submit_request_must_support_practitioner_role_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/practitioner_role/server_submit_response_must_support_practitioner_role_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/requestor/server_inquire_request_must_support_requestor_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/requestor/server_inquire_response_must_support_requestor_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/requestor/server_submit_request_must_support_requestor_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/requestor/server_submit_response_must_support_requestor_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/server_suite.rb +6 -7
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/subscriber/server_inquire_request_must_support_subscriber_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/subscriber/server_submit_request_must_support_subscriber_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/task/server_inquire_response_must_support_task_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/generated/v2.2.1/task/server_submit_response_must_support_task_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/pas_claim_response_decision_test.rb +2 -2
- data/lib/davinci_pas_test_kit/server/server_request_bundle_validation_test.rb +4 -6
- data/lib/davinci_pas_test_kit/server/server_response_bundle_validation_test.rb +4 -6
- data/lib/davinci_pas_test_kit/server/v2.0.1/must_support/pas_server_must_support_request_profiles_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/v2.0.1/pas_server_subscription_setup.rb +1 -1
- data/lib/davinci_pas_test_kit/server/v2.2.1/must_support/pas_server_must_support_request_profiles_test.rb +1 -1
- data/lib/davinci_pas_test_kit/server/v2.2.1/pas_server_claim_updates_group.rb +1 -1
- data/lib/davinci_pas_test_kit/server/v2.2.1/pas_server_subscription_setup.rb +1 -1
- data/lib/davinci_pas_test_kit/version.rb +2 -2
- metadata +31 -13
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/task/client_inquire_response_must_support_task_test.rb +0 -45
- data/lib/davinci_pas_test_kit/client/generated/v2.0.1/task/client_submit_response_must_support_task_test.rb +0 -45
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/task/client_inquire_response_must_support_task_test.rb +0 -55
- data/lib/davinci_pas_test_kit/client/generated/v2.2.1/task/client_submit_response_must_support_task_test.rb +0 -55
- data/lib/davinci_pas_test_kit/client/v2.2.1/pas_client_error_handling_group.rb +0 -20
|
@@ -4,85 +4,35 @@ require_relative '../parameters_helper'
|
|
|
4
4
|
require_relative 'validation_test'
|
|
5
5
|
require_relative 'pas_constants'
|
|
6
6
|
require_relative 'pas_datatype_constraints'
|
|
7
|
+
require_relative 'referenced_resource_presence_validation'
|
|
8
|
+
require_relative 'validator_configuration'
|
|
7
9
|
|
|
8
10
|
module DaVinciPASTestKit
|
|
9
11
|
module PasBundleValidation
|
|
10
12
|
include DaVinciPASTestKit::ValidationTest
|
|
11
13
|
include DaVinciPASTestKit::PasDatatypeConstraints
|
|
14
|
+
include DaVinciPASTestKit::ReferencedResourcePresenceValidation
|
|
12
15
|
include ParametersHelper
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
'Location' => 'us-core-location',
|
|
34
|
-
'Medication' => 'us-core-medication',
|
|
35
|
-
'MedicationDispense' => 'us-core-medicationdispense',
|
|
36
|
-
'MedicationRequest' => 'us-core-medicationrequest',
|
|
37
|
-
'Organization' => 'us-core-organization',
|
|
38
|
-
'Patient' => 'us-core-patient',
|
|
39
|
-
'Practitioner' => 'us-core-practitioner',
|
|
40
|
-
'PractitionerRole' => 'us-core-practitionerrole',
|
|
41
|
-
'Procedure' => 'us-core-procedure',
|
|
42
|
-
'Provenance' => 'us-core-provenance',
|
|
43
|
-
'QuestionnaireResponse' => 'us-core-questionnaireresponse',
|
|
44
|
-
'RelatedPerson' => 'us-core-relatedperson',
|
|
45
|
-
'ServiceRequest' => 'us-core-servicerequest',
|
|
46
|
-
'Specimen' => 'us-core-specimen'
|
|
47
|
-
}.freeze
|
|
48
|
-
|
|
49
|
-
US_CORE_CONDITION_ENCOUNTER_DIAGNOSIS_PROFILE_ID = 'us-core-condition-encounter-diagnosis'
|
|
50
|
-
US_CORE_CONDITION_PROBLEMS_HEALTH_CONCERNS_PROFILE_ID = 'us-core-condition-problems-health-concerns'
|
|
51
|
-
US_CORE_DIAGNOSTIC_REPORT_LAB_PROFILE_ID = 'us-core-diagnosticreport-lab'
|
|
52
|
-
US_CORE_DIAGNOSTIC_REPORT_NOTE_PROFILE_ID = 'us-core-diagnosticreport-note'
|
|
53
|
-
US_CORE_OBSERVATION_CLINICAL_RESULT_PROFILE_ID = 'us-core-observation-clinical-result'
|
|
54
|
-
US_CORE_OBSERVATION_LAB_PROFILE_ID = 'us-core-observation-lab'
|
|
55
|
-
US_CORE_OBSERVATION_SCREENING_ASSESSMENT_PROFILE_ID = 'us-core-observation-screening-assessment'
|
|
56
|
-
US_CORE_SIMPLE_OBSERVATION_PROFILE_ID = 'us-core-simple-observation'
|
|
57
|
-
US_CORE_SMOKING_STATUS_PROFILE_ID = 'us-core-smokingstatus'
|
|
58
|
-
US_CORE_VITAL_SIGNS_PROFILE_ID = 'us-core-vital-signs'
|
|
59
|
-
|
|
60
|
-
US_CORE_OBSERVATION_CODE_PROFILE_IDS = {
|
|
61
|
-
'11341-5' => 'us-core-observation-occupation',
|
|
62
|
-
'86645-9' => 'us-core-observation-pregnancyintent',
|
|
63
|
-
'82810-3' => 'us-core-observation-pregnancystatus',
|
|
64
|
-
'76690-7' => 'us-core-observation-sexual-orientation',
|
|
65
|
-
'8289-1' => 'head-occipital-frontal-circumference-percentile',
|
|
66
|
-
'59576-9' => 'pediatric-bmi-for-age',
|
|
67
|
-
'77606-2' => 'pediatric-weight-for-height',
|
|
68
|
-
'85354-9' => 'us-core-blood-pressure',
|
|
69
|
-
'39156-5' => 'us-core-bmi',
|
|
70
|
-
'8302-2' => 'us-core-body-height',
|
|
71
|
-
'8310-5' => 'us-core-body-temperature',
|
|
72
|
-
'29463-7' => 'us-core-body-weight',
|
|
73
|
-
'9843-4' => 'us-core-head-circumference',
|
|
74
|
-
'8867-4' => 'us-core-heart-rate',
|
|
75
|
-
'59408-5' => 'us-core-pulse-oximetry',
|
|
76
|
-
'2708-6' => 'us-core-pulse-oximetry',
|
|
77
|
-
'9279-1' => 'us-core-respiratory-rate',
|
|
78
|
-
'72166-2' => 'us-core-smokingstatus'
|
|
79
|
-
}.freeze
|
|
80
|
-
|
|
81
|
-
def validation_error_messages
|
|
82
|
-
@validation_error_messages ||= []
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def perform_bundle_validation(bundle, operation, type, ig_version, request_bundle = nil)
|
|
17
|
+
###########################################################################
|
|
18
|
+
# Public API
|
|
19
|
+
###########################################################################
|
|
20
|
+
|
|
21
|
+
# @return [Array<Hash>] The messages (of every severity) found while validating this
|
|
22
|
+
# bundle, each a { type:, message: } hash. Callers that only care about failure should
|
|
23
|
+
# check for a message with type: 'error' rather than just whether this is present -
|
|
24
|
+
# see validation_messages.
|
|
25
|
+
# @param validator [Symbol] the name of the FHIR resource validator to use for profile
|
|
26
|
+
# validation. Use perform_no_custom_extensions_validation for Bundles Inferno sends.
|
|
27
|
+
# @param echoed_from [FHIR::Bundle, String, nil] the request Bundle the response answers. When
|
|
28
|
+
# given, entry resources echoed back from it that carry no extensions beyond those they had in
|
|
29
|
+
# it are validated with the :default validator rather than `validator`, since the extensions
|
|
30
|
+
# came from the system under test.
|
|
31
|
+
def perform_bundle_validation(bundle, operation, type, ig_version, request_bundle = nil, validator: :default,
|
|
32
|
+
echoed_from: nil)
|
|
33
|
+
@validation_messages = []
|
|
34
|
+
@profile_validator = validator
|
|
35
|
+
@echoed_from_bundle = parse_bundle(echoed_from)
|
|
86
36
|
target_profile = PASConstants.bundle_profile_url_for_operation_and_type(operation, type)
|
|
87
37
|
request_type = "#{operation}_#{type}"
|
|
88
38
|
if type == 'request'
|
|
@@ -90,66 +40,260 @@ module DaVinciPASTestKit
|
|
|
90
40
|
else
|
|
91
41
|
perform_response_validation(bundle, target_profile, ig_version.delete_prefix('v'), request_type, request_bundle)
|
|
92
42
|
end
|
|
43
|
+
validation_messages
|
|
93
44
|
end
|
|
94
45
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
46
|
+
# Validates a Bundle that Inferno sends to the system under test, which may be tester-provided,
|
|
47
|
+
# using NO_CUSTOM_EXTENSIONS_VALIDATOR so that custom extensions aren't allowed. Resources echoed
|
|
48
|
+
# back from the system under test's Bundle may keep the extensions they had in it.
|
|
49
|
+
# @param type [String] 'request' or 'response' - see perform_bundle_validation.
|
|
50
|
+
# @param echoed_from [FHIR::Bundle, String, nil] the Bundle from the system under test that this
|
|
51
|
+
# one answers, e.g. the request for a response, or nil if there is none - see
|
|
52
|
+
# perform_bundle_validation.
|
|
53
|
+
# @return [Array<Hash>] see perform_bundle_validation.
|
|
54
|
+
def perform_no_custom_extensions_validation(bundle, operation, type, ig_version, echoed_from:)
|
|
55
|
+
perform_bundle_validation(bundle, operation, type, ig_version,
|
|
56
|
+
validator: NO_CUSTOM_EXTENSIONS_VALIDATOR, echoed_from:)
|
|
98
57
|
end
|
|
99
58
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
59
|
+
# Validates a Parameters resource that Inferno sends to wrap Bundles (e.g., a v2.2.1 $inquire
|
|
60
|
+
# response) against the base Parameters definition, since PAS doesn't profile it, using
|
|
61
|
+
# NO_CUSTOM_EXTENSIONS_VALIDATOR. Issues within the wrapped resources are dropped, since those are
|
|
62
|
+
# validated separately - see perform_no_custom_extensions_validation.
|
|
63
|
+
# @param parameters [FHIR::Parameters]
|
|
64
|
+
# @return [Array<Hash>] the messages found, each a { type:, message: } hash.
|
|
65
|
+
def perform_no_custom_extensions_parameters_validation(parameters)
|
|
66
|
+
response_details = []
|
|
67
|
+
resource_is_valid?(resource: parameters, validator: NO_CUSTOM_EXTENSIONS_VALIDATOR,
|
|
68
|
+
add_messages_to_runnable: false,
|
|
69
|
+
validator_response_details: response_details)
|
|
70
|
+
validator_issues_to_messages(response_details.reject do |issue|
|
|
71
|
+
issue.filtered || issue.location&.match?(/\AParameters\.parameter\[\d+\](\.part\[\d+\])*\.resource/)
|
|
72
|
+
end)
|
|
103
73
|
end
|
|
104
74
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
75
|
+
###########################################################################
|
|
76
|
+
# Internal Validation Methods
|
|
77
|
+
###########################################################################
|
|
78
|
+
|
|
79
|
+
# Every message (of every severity, not just errors) collected while validating the
|
|
80
|
+
# current bundle. Passing-profile messages and per-issue profile-conformance messages
|
|
81
|
+
# (see validate_bundle_entries_against_profiles) may be warnings or info, not just
|
|
82
|
+
# errors, which is why this isn't error-only despite most entries being added via
|
|
83
|
+
# add_validation_error.
|
|
84
|
+
def validation_messages
|
|
85
|
+
@validation_messages ||= []
|
|
86
|
+
end
|
|
109
87
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
88
|
+
# Appends a plain error string to validation_messages as a { type:, message: } hash,
|
|
89
|
+
# for the many checks in this file that only ever produce errors (as opposed to
|
|
90
|
+
# validate_bundle_entries_against_profiles, which already has typed messages from the
|
|
91
|
+
# validator and concats them directly).
|
|
92
|
+
def add_validation_error(message)
|
|
93
|
+
validation_messages << { type: 'error', message: }
|
|
94
|
+
end
|
|
115
95
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
96
|
+
# The name of the FHIR resource validator used for profile validation of the current
|
|
97
|
+
# bundle - see perform_bundle_validation.
|
|
98
|
+
def profile_validator
|
|
99
|
+
@profile_validator || :default
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# How to validate one entry resource in the current bundle. Resources echoed back from the request
|
|
103
|
+
# (see perform_bundle_validation's echoed_from) may keep the extensions they had in it: those that
|
|
104
|
+
# add no extensions of their own use the :default validator, and the others use the specified
|
|
105
|
+
# validator with the issues it reports about their extensions explained or dropped - see
|
|
106
|
+
# echoed_extension_issue_messages.
|
|
107
|
+
# @param full_url [String] the fullUrl of the entry containing the resource.
|
|
108
|
+
# @param resource [FHIR::Model] the entry resource.
|
|
109
|
+
# @return [Array(Symbol, Array, FHIR::Bundle::Entry)] the name of the validator to use, the
|
|
110
|
+
# [element path, extension] pairs (see extensions_in) of the request resource the resource echoes,
|
|
111
|
+
# and the request entry it echoes. The last two are nil if it doesn't echo one (or the validator is
|
|
112
|
+
# :default, which allows any extension).
|
|
113
|
+
def entry_validation_settings(full_url, resource)
|
|
114
|
+
return [profile_validator, nil, nil] if profile_validator == :default
|
|
115
|
+
|
|
116
|
+
request_entry = echoed_request_entry(full_url, resource)
|
|
117
|
+
return [profile_validator, nil, nil] if request_entry.blank?
|
|
118
|
+
|
|
119
|
+
echoed_extensions = extensions_in(validated_hash(request_entry.resource))
|
|
120
|
+
all_echoed = extensions_in(validated_hash(resource)).all? { |extension| echoed_extensions.include?(extension) }
|
|
121
|
+
[all_echoed ? :default : profile_validator, echoed_extensions, request_entry]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def echoed_request_entry(full_url, resource)
|
|
125
|
+
return if @echoed_from_bundle.blank?
|
|
126
|
+
|
|
127
|
+
response_entry = FHIR::Bundle::Entry.new(fullUrl: full_url, resource:)
|
|
128
|
+
@echoed_from_bundle.entry.find { |entry| echoed_resource?(entry, response_entry) }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# The resource as the validator receives it (Inferno sends its source_contents), as a hash. Unlike
|
|
132
|
+
# to_hash, this keeps the extensions on primitive elements (e.g., `_birthDate`).
|
|
133
|
+
def validated_hash(resource)
|
|
134
|
+
JSON.parse(resource.source_contents)
|
|
135
|
+
rescue StandardError
|
|
136
|
+
resource.to_hash
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# An extension is echoed if it appears, with the same content and at the same element path, in the
|
|
140
|
+
# request resource. Paths leave out array indexes so reordered repeating elements still match.
|
|
141
|
+
# Reference values are ignored because Inferno rewrites them when it echoes resources in responses
|
|
142
|
+
# it generates.
|
|
143
|
+
# @return [Array<Array(String, Hash)>] [element path, extension] pairs for every extension (at any
|
|
144
|
+
# depth, including modifierExtensions) in the value.
|
|
145
|
+
def extensions_in(value, path = '')
|
|
146
|
+
case value
|
|
147
|
+
when Hash
|
|
148
|
+
value.flat_map do |key, child|
|
|
149
|
+
child_path = path.empty? ? key : "#{path}.#{key}"
|
|
150
|
+
own = if %w[extension modifierExtension].include?(key)
|
|
151
|
+
Array(child).map { |extension| [child_path, without_references(extension)] }
|
|
152
|
+
else
|
|
153
|
+
[]
|
|
154
|
+
end
|
|
155
|
+
own + extensions_in(child, child_path)
|
|
128
156
|
end
|
|
157
|
+
when Array
|
|
158
|
+
value.flat_map { |child| extensions_in(child, path) }
|
|
129
159
|
else
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
160
|
+
[]
|
|
161
|
+
end
|
|
162
|
+
end
|
|
133
163
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
164
|
+
def without_references(value)
|
|
165
|
+
case value
|
|
166
|
+
when Hash
|
|
167
|
+
value.except('reference').transform_values { |child| without_references(child) }
|
|
168
|
+
when Array
|
|
169
|
+
value.map { |child| without_references(child) }
|
|
170
|
+
else
|
|
171
|
+
value
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# An info message identifying an echoed resource, which of its identifying fields matched the request
|
|
176
|
+
# entry it echoes (see echoed_resource?), and the extensions it is allowed to keep because they are
|
|
177
|
+
# unchanged from the request - see entry_validation_settings.
|
|
178
|
+
def echoed_resource_message(full_url, resource, echoed_extensions, request_entry)
|
|
179
|
+
kept_urls = extensions_in(validated_hash(resource))
|
|
180
|
+
.select { |extension| echoed_extensions.include?(extension) }
|
|
181
|
+
.map { |_path, extension| extension['url'] }.uniq
|
|
182
|
+
message = "#{resource.resourceType} #{full_url} echoes the #{resource.resourceType} in the request " \
|
|
183
|
+
"(#{echo_match_details(full_url, resource, request_entry)})"
|
|
184
|
+
message += if kept_urls.present?
|
|
185
|
+
", so these extensions unchanged from the request are allowed in it: #{kept_urls.join(', ')}."
|
|
186
|
+
else
|
|
187
|
+
'.'
|
|
188
|
+
end
|
|
189
|
+
{ type: 'info', message: }
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Which identifying fields of an echoed resource match the request entry it echoes and which differ,
|
|
193
|
+
# e.g., "matched by id; fullUrl differs". Fields blank in both are left out.
|
|
194
|
+
def echo_match_details(full_url, resource, request_entry)
|
|
195
|
+
fields = {
|
|
196
|
+
'fullUrl' => [request_entry.fullUrl, full_url],
|
|
197
|
+
'id' => [request_entry.resource.id, resource.id],
|
|
198
|
+
'identifiers' => [identifiers_of(request_entry.resource), identifiers_of(resource)]
|
|
199
|
+
}.reject { |_name, values| values.all?(&:blank?) }
|
|
200
|
+
matched, differing = fields.keys.partition do |name|
|
|
201
|
+
request_value, response_value = fields[name]
|
|
202
|
+
request_value == response_value
|
|
203
|
+
end
|
|
204
|
+
details = "matched by #{matched.to_sentence}"
|
|
205
|
+
details += "; #{differing.to_sentence} #{differing.one? ? 'differs' : 'differ'}" if differing.present?
|
|
206
|
+
details
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Messages for the validator issues about an echoed resource. An issue that an extension isn't allowed
|
|
210
|
+
# (see unknown_extension_issue?) is:
|
|
211
|
+
# - dropped if the extension is echoed, i.e., in echoed_extensions.
|
|
212
|
+
# - reworded otherwise, to say whether the request resource has an extension with that url at the
|
|
213
|
+
# same element, but with different content, or doesn't.
|
|
214
|
+
# Other issues are kept as is.
|
|
215
|
+
# @param resource_hash [Hash] the validated resource, as a hash.
|
|
216
|
+
def echoed_extension_issue_messages(issues, resource_hash, echoed_extensions)
|
|
217
|
+
issues.filter_map do |issue|
|
|
218
|
+
path, extension = extension_at_location(resource_hash, issue.location)
|
|
219
|
+
url = extension&.dig('url')
|
|
220
|
+
next validator_issue_message(issue) unless unknown_extension_issue?(issue, url)
|
|
221
|
+
next if echoed_extensions.include?([path, without_references(extension)])
|
|
222
|
+
|
|
223
|
+
details =
|
|
224
|
+
if echoed_extensions.any? { |echoed_path, echoed| echoed_path == path && echoed['url'] == url }
|
|
225
|
+
"echoed extension #{url} contained a different value than in the source resource."
|
|
226
|
+
else
|
|
227
|
+
"extension #{url} in an echoed resource is not in the source resource at this element."
|
|
228
|
+
end
|
|
229
|
+
validator_issue_message(issue, details:)
|
|
139
230
|
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# True if the issue is the validator's error for an extension it doesn't know, so doesn't allow
|
|
234
|
+
# (Extension_EXT_Unknown_NotHere), as the strict validator reports for custom extensions. Other
|
|
235
|
+
# issues about extensions, e.g., known extensions with invalid values, are reported as is.
|
|
236
|
+
def unknown_extension_issue?(issue, url)
|
|
237
|
+
url.present? && issue.raw_issue['message'] == "The extension #{url} could not be found so is not allowed here"
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# True if the issue is the :default validator's note that an echoed extension is unknown
|
|
241
|
+
# (Extension_EXT_Unknown) - see echoed_resource_message.
|
|
242
|
+
def echoed_unknown_extension_note?(issue, resource_hash, echoed_extensions)
|
|
243
|
+
path, extension = extension_at_location(resource_hash, issue.location)
|
|
244
|
+
url = extension&.dig('url')
|
|
245
|
+
url.present? && issue.raw_issue['message'] == "Unknown extension #{url}" &&
|
|
246
|
+
echoed_extensions.include?([path, without_references(extension)])
|
|
247
|
+
end
|
|
140
248
|
|
|
141
|
-
|
|
142
|
-
|
|
249
|
+
# Resolves a validator issue location such as `Patient.name[0].extension[1]` against the resource.
|
|
250
|
+
# Extensions on primitive elements are located by the element's name (e.g.,
|
|
251
|
+
# `Patient.birthDate.extension[0]`) but held in its `_` sibling (e.g., `_birthDate`) in JSON.
|
|
252
|
+
# @return [Array(String, Hash), nil] the extension's index-free element path (as in extensions_in)
|
|
253
|
+
# and the extension, or nil if the location isn't an extension in the resource.
|
|
254
|
+
def extension_at_location(resource_hash, location)
|
|
255
|
+
value = resource_hash
|
|
256
|
+
names = location.to_s.split('.').drop(1).map do |segment|
|
|
257
|
+
name, index = segment.match(/\A(\w+)(?:\[(\d+)\])?\z/)&.captures
|
|
258
|
+
return nil if name.nil? || !value.is_a?(Hash)
|
|
259
|
+
|
|
260
|
+
name = "_#{name}" if primitive_element?(value, name)
|
|
261
|
+
value = value[name]
|
|
262
|
+
value = value[index.to_i] if index.present? && value.is_a?(Array)
|
|
263
|
+
name
|
|
143
264
|
end
|
|
144
|
-
|
|
145
|
-
assert validation_error_messages.blank?, msg
|
|
146
|
-
rescue Inferno::Exceptions::AssertionException => e
|
|
147
|
-
msg = "#{message} #{e.message}".strip
|
|
148
|
-
raise e.class, msg unless skips
|
|
265
|
+
return unless %w[extension modifierExtension].include?(names.last) && value.is_a?(Hash)
|
|
149
266
|
|
|
150
|
-
|
|
267
|
+
[names.join('.'), value]
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# True if the element is a primitive (or repeating primitive) with a `_` sibling holding its
|
|
271
|
+
# extensions, in the JSON object `parent`.
|
|
272
|
+
def primitive_element?(parent, name)
|
|
273
|
+
parent.key?("_#{name}") && Array.wrap(parent[name]).none?(Hash)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def parse_bundle(bundle)
|
|
277
|
+
bundle = FHIR.from_contents(bundle) if bundle.is_a?(String)
|
|
278
|
+
bundle if bundle.is_a?(FHIR::Bundle)
|
|
279
|
+
rescue StandardError
|
|
280
|
+
nil
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def perform_request_validation(bundle, profile_url, version, request_type)
|
|
284
|
+
validate_pa_request_payload_structure(bundle, request_type)
|
|
285
|
+
validate_resources_conformance_against_profile(bundle, profile_url, version, request_type)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def perform_response_validation(response_bundle, profile_url, version, request_type, request_bundle = nil)
|
|
289
|
+
validate_pa_response_body_structure(response_bundle, request_bundle) if request_type.start_with?('submit')
|
|
290
|
+
validate_resources_conformance_against_profile(response_bundle, profile_url, version, request_type)
|
|
151
291
|
end
|
|
152
292
|
|
|
293
|
+
###########################################################################
|
|
294
|
+
# Structure Validation
|
|
295
|
+
###########################################################################
|
|
296
|
+
|
|
153
297
|
# Validates the structure of a Prior Authorization (PA) request Bundle.
|
|
154
298
|
#
|
|
155
299
|
# @param bundle [FHIR::Bundle] The FHIR Bundle of the PA request.
|
|
@@ -167,18 +311,22 @@ module DaVinciPASTestKit
|
|
|
167
311
|
base_url = extract_base_url(bundle.entry.first&.fullUrl)
|
|
168
312
|
|
|
169
313
|
check_presence_of_referenced_resources(first_entry, base_url, bundle.entry)
|
|
314
|
+
.each { |msg| add_validation_error(msg) }
|
|
170
315
|
|
|
171
|
-
|
|
316
|
+
# request_type is the compound 'submit_request' / 'inquire_request' built by
|
|
317
|
+
# perform_bundle_validation - start_with? also accepts a bare 'submit', consistent with
|
|
318
|
+
# find_profile_url and validate_resources_conformance_against_profile below.
|
|
319
|
+
if request_type.start_with?('submit')
|
|
172
320
|
unless first_entry.is_a?(FHIR::Claim)
|
|
173
|
-
|
|
321
|
+
add_validation_error("[Bundle/#{bundle.id}]: The first bundle entry must be a Claim")
|
|
174
322
|
end
|
|
175
323
|
|
|
176
324
|
validate_uniqueness_of_supporting_info_sequences(first_entry)
|
|
177
325
|
validate_bundle_entries_full_url(bundle)
|
|
178
326
|
else
|
|
179
|
-
claim_resource = bundle_entry_resources.find { |resource| resource
|
|
327
|
+
claim_resource = bundle_entry_resources.find { |resource| resource&.resourceType == 'Claim' }
|
|
180
328
|
if claim_resource.blank?
|
|
181
|
-
|
|
329
|
+
add_validation_error("[Bundle/#{bundle.id}]: Claim must be present for inquiry request")
|
|
182
330
|
end
|
|
183
331
|
|
|
184
332
|
# The inquiry operation must contain a requesting provider organization,
|
|
@@ -188,16 +336,15 @@ module DaVinciPASTestKit
|
|
|
188
336
|
payer_reference = claim_resource&.insurer&.reference
|
|
189
337
|
|
|
190
338
|
if patient_reference.blank?
|
|
191
|
-
|
|
192
|
-
"[Bundle/#{bundle.id}]: The Claim for inquiry operation must reference a patient."
|
|
339
|
+
add_validation_error("[Bundle/#{bundle.id}]: The Claim for inquiry operation must reference a patient.")
|
|
193
340
|
end
|
|
194
341
|
if provider_reference.blank?
|
|
195
|
-
|
|
196
|
-
|
|
342
|
+
add_validation_error("[Bundle/#{bundle.id}]: The claim for inquiry operation must reference " \
|
|
343
|
+
'a requesting provider organization.')
|
|
197
344
|
end
|
|
198
345
|
if payer_reference.blank?
|
|
199
|
-
|
|
200
|
-
|
|
346
|
+
add_validation_error("[Bundle/#{bundle.id}]: The Claim for inquiry operation must contain " \
|
|
347
|
+
'a payer organization.')
|
|
201
348
|
end
|
|
202
349
|
end
|
|
203
350
|
end
|
|
@@ -217,14 +364,14 @@ module DaVinciPASTestKit
|
|
|
217
364
|
# to ensure the same fullUrl and resource identifiers as in the
|
|
218
365
|
# request are used.
|
|
219
366
|
def validate_pa_response_body_structure(pa_response_bundle, pa_request_bundle)
|
|
220
|
-
first_entry = pa_response_bundle.entry.first
|
|
367
|
+
first_entry = pa_response_bundle.entry.first&.resource
|
|
221
368
|
unless first_entry.is_a?(FHIR::ClaimResponse)
|
|
222
|
-
|
|
223
|
-
"[Bundle/#{pa_response_bundle.id}]: The first bundle entry must be a ClaimResponse"
|
|
369
|
+
add_validation_error("[Bundle/#{pa_response_bundle.id}]: The first bundle entry must be a ClaimResponse")
|
|
224
370
|
end
|
|
225
371
|
|
|
226
372
|
base_url = extract_base_url(pa_response_bundle.entry.last&.fullUrl)
|
|
227
373
|
check_presence_of_referenced_resources(first_entry, base_url, pa_response_bundle.entry)
|
|
374
|
+
.each { |msg| add_validation_error(msg) }
|
|
228
375
|
|
|
229
376
|
validate_echoed_response_resources(pa_response_bundle, pa_request_bundle)
|
|
230
377
|
end
|
|
@@ -246,10 +393,10 @@ module DaVinciPASTestKit
|
|
|
246
393
|
|
|
247
394
|
next if echoed_resource_identifiers_match?(request_entry, response_entry)
|
|
248
395
|
|
|
249
|
-
|
|
396
|
+
add_validation_error(resource_present_in_pa_request_and_response_msg(response_resource))
|
|
250
397
|
end
|
|
251
398
|
rescue StandardError
|
|
252
|
-
|
|
399
|
+
add_validation_error('Unable to compare PAS request and response Bundle resources for echoed identifiers.')
|
|
253
400
|
end
|
|
254
401
|
|
|
255
402
|
def echoed_resource?(request_entry, response_entry)
|
|
@@ -262,7 +409,8 @@ module DaVinciPASTestKit
|
|
|
262
409
|
# do not have all matching identifiers. Blank fields do not identify echoed resources.
|
|
263
410
|
(request_entry.fullUrl.present? && request_entry.fullUrl == response_entry.fullUrl) ||
|
|
264
411
|
(request_resource.id.present? && request_resource.id == response_resource.id) ||
|
|
265
|
-
(request_resource.
|
|
412
|
+
(identifiers_of(request_resource).present? &&
|
|
413
|
+
identifiers_of(request_resource) == identifiers_of(response_resource))
|
|
266
414
|
end
|
|
267
415
|
|
|
268
416
|
def echoed_resource_identifiers_match?(request_entry, response_entry)
|
|
@@ -271,9 +419,18 @@ module DaVinciPASTestKit
|
|
|
271
419
|
|
|
272
420
|
request_entry.fullUrl == response_entry.fullUrl &&
|
|
273
421
|
request_resource.id == response_resource.id &&
|
|
274
|
-
request_resource
|
|
422
|
+
identifiers_of(request_resource) == identifiers_of(response_resource)
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Nil for resource types without an identifier element (e.g., Binary, Parameters).
|
|
426
|
+
def identifiers_of(resource)
|
|
427
|
+
resource.identifier if resource.respond_to?(:identifier)
|
|
275
428
|
end
|
|
276
429
|
|
|
430
|
+
###########################################################################
|
|
431
|
+
# Bundle entry profile validation
|
|
432
|
+
###########################################################################
|
|
433
|
+
|
|
277
434
|
# Profile conformance of Prior Authorization (PA) resources.
|
|
278
435
|
#
|
|
279
436
|
# @param bundle [FHIR::Bundle] The FHIR bundle representing the PA request/response.
|
|
@@ -291,7 +448,7 @@ module DaVinciPASTestKit
|
|
|
291
448
|
bundle_entry = bundle.entry
|
|
292
449
|
|
|
293
450
|
root_entry = bundle_entry.find do |entry|
|
|
294
|
-
['Claim', 'ClaimResponse'].include?(entry.resource
|
|
451
|
+
['Claim', 'ClaimResponse'].include?(entry.resource&.resourceType)
|
|
295
452
|
end
|
|
296
453
|
|
|
297
454
|
if root_entry.present?
|
|
@@ -333,12 +490,21 @@ module DaVinciPASTestKit
|
|
|
333
490
|
# Validates bundle resource and each entry in the bundle against its target profiles.
|
|
334
491
|
# Validation messages are collected per profile rather than logged directly, so a
|
|
335
492
|
# resource with multiple candidate profiles only reports errors when it fails all of
|
|
336
|
-
# them. When a profile passes, only that profile's (non-error) messages are
|
|
493
|
+
# them. When a profile passes, only that profile's (non-error) messages are kept. Either
|
|
494
|
+
# way, messages go into validation_messages rather than straight to the runnable's
|
|
495
|
+
# `messages` - see perform_bundle_validation - so callers see every message this method
|
|
496
|
+
# finds, not just the summary line for a resource that conformed to nothing.
|
|
337
497
|
# @param version [String] The version of the IG.
|
|
338
498
|
def validate_bundle_entries_against_profiles(version)
|
|
339
499
|
bundle_resources_target_profile_map.each do |key, item|
|
|
340
500
|
resource = item[:resource]
|
|
341
501
|
base_profile = FHIR::Definitions.resource_definition(resource.resourceType).url
|
|
502
|
+
unless key == 'bundle'
|
|
503
|
+
validator, echoed_extensions, request_entry = entry_validation_settings(key, resource)
|
|
504
|
+
if request_entry.present?
|
|
505
|
+
validation_messages << echoed_resource_message(key, resource, echoed_extensions, request_entry)
|
|
506
|
+
end
|
|
507
|
+
end
|
|
342
508
|
messages_by_profile = {}
|
|
343
509
|
|
|
344
510
|
success_profile = item[:profile_urls].find do |url|
|
|
@@ -346,9 +512,10 @@ module DaVinciPASTestKit
|
|
|
346
512
|
if key == 'bundle'
|
|
347
513
|
collect_bundle_profile_messages(resource, profile_url_for_validation(url, base_profile, version))
|
|
348
514
|
elsif url == BASE_R4_PROFILE
|
|
349
|
-
collect_resource_profile_messages(resource)
|
|
515
|
+
collect_resource_profile_messages(resource, validator:, echoed_extensions:)
|
|
350
516
|
else
|
|
351
|
-
collect_resource_profile_messages(resource, profile_url_for_validation(url, base_profile, version)
|
|
517
|
+
collect_resource_profile_messages(resource, profile_url_for_validation(url, base_profile, version),
|
|
518
|
+
validator:, echoed_extensions:) +
|
|
352
519
|
datatype_constraint_messages(resource, profile_url_without_version(url), version)
|
|
353
520
|
end
|
|
354
521
|
messages_by_profile[url] = profile_messages
|
|
@@ -356,10 +523,10 @@ module DaVinciPASTestKit
|
|
|
356
523
|
end
|
|
357
524
|
|
|
358
525
|
if success_profile
|
|
359
|
-
|
|
526
|
+
validation_messages.concat(messages_by_profile[success_profile])
|
|
360
527
|
else
|
|
361
|
-
messages_by_profile.each_value { |profile_messages|
|
|
362
|
-
|
|
528
|
+
messages_by_profile.each_value { |profile_messages| validation_messages.concat(profile_messages) }
|
|
529
|
+
add_validation_error(generate_non_conformance_message(item))
|
|
363
530
|
end
|
|
364
531
|
end
|
|
365
532
|
end
|
|
@@ -367,7 +534,17 @@ module DaVinciPASTestKit
|
|
|
367
534
|
def profile_url_for_validation(url, base_profile, version)
|
|
368
535
|
url = url.to_s
|
|
369
536
|
return url if url.include?('|') || profile_url_without_version(url) == base_profile
|
|
370
|
-
|
|
537
|
+
|
|
538
|
+
if us_core_profile_url?(url)
|
|
539
|
+
profile_id = url.delete_prefix("#{US_CORE_PROFILE_BASE}/")
|
|
540
|
+
# US Core 3.1.1's single Condition profile was split by category in later versions,
|
|
541
|
+
# so only 3.1.1 defines it.
|
|
542
|
+
return "#{url}|#{PASConstants::US_CORE_VERSION_3_1_1}" if profile_id == US_CORE_CONDITION_PROFILE_ID
|
|
543
|
+
|
|
544
|
+
# A declared US Core profile gets the selected version only when that version defines it;
|
|
545
|
+
# otherwise it stays unversioned so the validator resolves it to a version that does.
|
|
546
|
+
return us_core_profile_available?(profile_id) ? "#{url}|#{us_core_version}" : url
|
|
547
|
+
end
|
|
371
548
|
|
|
372
549
|
"#{url}|#{version}"
|
|
373
550
|
end
|
|
@@ -406,6 +583,12 @@ module DaVinciPASTestKit
|
|
|
406
583
|
version.to_s.delete_prefix('v').match?(/\A2\.2(\.|\z)/)
|
|
407
584
|
end
|
|
408
585
|
|
|
586
|
+
# The US Core version whose profiles the fallback validates against: the session's
|
|
587
|
+
# US Core Version suite option when the suite offers it, otherwise 6.1.0.
|
|
588
|
+
def us_core_version
|
|
589
|
+
suite_options[:us_core_version].presence || PASConstants::DEFAULT_US_CORE_VERSION
|
|
590
|
+
end
|
|
591
|
+
|
|
409
592
|
def us_core_profile_urls_for_resource(resource)
|
|
410
593
|
profile_ids =
|
|
411
594
|
case resource.resourceType
|
|
@@ -419,10 +602,20 @@ module DaVinciPASTestKit
|
|
|
419
602
|
Array(US_CORE_SINGLE_PROFILE_IDS_BY_RESOURCE[resource.resourceType])
|
|
420
603
|
end
|
|
421
604
|
|
|
422
|
-
us_core_profile_urls(profile_ids)
|
|
605
|
+
profile_urls = us_core_profile_urls(profile_ids.select { |profile_id| us_core_profile_available?(profile_id) })
|
|
606
|
+
# US Core 3.1.1 has no Simple Observation profile, so the base resource takes its place as the
|
|
607
|
+
# catch-all at the end of the Observation candidates.
|
|
608
|
+
if profile_ids.include?(US_CORE_SIMPLE_OBSERVATION_PROFILE_ID) &&
|
|
609
|
+
!us_core_profile_available?(US_CORE_SIMPLE_OBSERVATION_PROFILE_ID)
|
|
610
|
+
profile_urls << BASE_R4_PROFILE
|
|
611
|
+
end
|
|
612
|
+
profile_urls
|
|
423
613
|
end
|
|
424
614
|
|
|
425
615
|
def us_core_condition_profile_ids(resource)
|
|
616
|
+
# US Core 3.1.1 has a single Condition profile; later versions split it by category.
|
|
617
|
+
return [US_CORE_CONDITION_PROFILE_ID] if us_core_version == PASConstants::US_CORE_VERSION_3_1_1
|
|
618
|
+
|
|
426
619
|
if category_code_present?(resource, 'encounter-diagnosis', system: TERMINOLOGY_CONDITION_CATEGORY_SYSTEM)
|
|
427
620
|
[US_CORE_CONDITION_ENCOUNTER_DIAGNOSIS_PROFILE_ID]
|
|
428
621
|
else
|
|
@@ -439,8 +632,9 @@ module DaVinciPASTestKit
|
|
|
439
632
|
end
|
|
440
633
|
|
|
441
634
|
def us_core_observation_profile_ids(resource)
|
|
442
|
-
code_profile_id = US_CORE_OBSERVATION_CODE_PROFILE_IDS.find do |code,
|
|
443
|
-
|
|
635
|
+
code_profile_id = US_CORE_OBSERVATION_CODE_PROFILE_IDS.find do |code, profile_id|
|
|
636
|
+
us_core_profile_available?(profile_id) &&
|
|
637
|
+
codeable_concept_has_code?(resource.code, code, system: LOINC_SYSTEM)
|
|
444
638
|
end&.last
|
|
445
639
|
return [code_profile_id] if code_profile_id.present?
|
|
446
640
|
|
|
@@ -463,7 +657,16 @@ module DaVinciPASTestKit
|
|
|
463
657
|
end
|
|
464
658
|
|
|
465
659
|
def us_core_profile_urls(profile_ids)
|
|
466
|
-
Array(profile_ids).map { |profile_id| "#{US_CORE_PROFILE_BASE}/#{profile_id}|#{
|
|
660
|
+
Array(profile_ids).map { |profile_id| "#{US_CORE_PROFILE_BASE}/#{profile_id}|#{us_core_version}" }
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
# Whether the selected US Core version defines the profile.
|
|
664
|
+
def us_core_profile_available?(profile_id)
|
|
665
|
+
# The only profile a later supported version dropped; see profile_url_for_validation.
|
|
666
|
+
return us_core_version == PASConstants::US_CORE_VERSION_3_1_1 if profile_id == US_CORE_CONDITION_PROFILE_ID
|
|
667
|
+
|
|
668
|
+
added_in = US_CORE_PROFILE_IDS_ADDED_IN_VERSION.find { |_, profile_ids| profile_ids.include?(profile_id) }&.first
|
|
669
|
+
added_in.nil? || Gem::Version.new(us_core_version) >= Gem::Version.new(added_in)
|
|
467
670
|
end
|
|
468
671
|
|
|
469
672
|
def profile_url_without_version(url)
|
|
@@ -492,13 +695,29 @@ module DaVinciPASTestKit
|
|
|
492
695
|
# @param resource [FHIR::Model] The resource to validate.
|
|
493
696
|
# @param profile_url [String, nil] The profile URL (with version) to validate against,
|
|
494
697
|
# or nil to validate against the base resource definition.
|
|
698
|
+
# @param validator [Symbol] The name of the FHIR resource validator to use.
|
|
699
|
+
# @param echoed_extensions [Array, nil] Extensions of the request resource the resource echoes, or
|
|
700
|
+
# nil if it doesn't echo one - see entry_validation_settings and echoed_extension_issue_messages.
|
|
495
701
|
# @return [Array<Hash>] Message hashes for the issues found.
|
|
496
|
-
def collect_resource_profile_messages(resource, profile_url = nil
|
|
702
|
+
def collect_resource_profile_messages(resource, profile_url = nil, validator: profile_validator,
|
|
703
|
+
echoed_extensions: nil)
|
|
497
704
|
response_details = []
|
|
498
|
-
resource_is_valid?(resource:, profile_url:,
|
|
705
|
+
resource_is_valid?(resource:, profile_url:, validator:,
|
|
499
706
|
add_messages_to_runnable: false,
|
|
500
707
|
validator_response_details: response_details)
|
|
501
|
-
|
|
708
|
+
issues = response_details.reject(&:filtered)
|
|
709
|
+
return validator_issues_to_messages(issues) if echoed_extensions.nil?
|
|
710
|
+
|
|
711
|
+
resource_hash = validated_hash(resource)
|
|
712
|
+
if validator == :default
|
|
713
|
+
# The :default validator allows every extension, so its only issues to drop are its notes that
|
|
714
|
+
# echoed extensions are unknown, which the echoed resource message already covers.
|
|
715
|
+
return validator_issues_to_messages(issues.reject do |issue|
|
|
716
|
+
echoed_unknown_extension_note?(issue, resource_hash, echoed_extensions)
|
|
717
|
+
end)
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
echoed_extension_issue_messages(issues, resource_hash, echoed_extensions)
|
|
502
721
|
end
|
|
503
722
|
|
|
504
723
|
# Same as collect_resource_profile_messages for a Bundle, additionally dropping
|
|
@@ -509,14 +728,21 @@ module DaVinciPASTestKit
|
|
|
509
728
|
# @return [Array<Hash>] Message hashes for the Bundle-structural issues found.
|
|
510
729
|
def collect_bundle_profile_messages(bundle, profile_url)
|
|
511
730
|
response_details = []
|
|
512
|
-
resource_is_valid?(resource: bundle, profile_url:,
|
|
731
|
+
resource_is_valid?(resource: bundle, profile_url:, validator: profile_validator,
|
|
513
732
|
add_messages_to_runnable: false,
|
|
514
733
|
validator_response_details: response_details)
|
|
515
734
|
validator_issues_to_messages(reject_entry_resource_issues(response_details))
|
|
516
735
|
end
|
|
517
736
|
|
|
518
737
|
def validator_issues_to_messages(issues)
|
|
519
|
-
issues.map { |issue|
|
|
738
|
+
issues.map { |issue| validator_issue_message(issue) }
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
# @param details [String, nil] replaces the validator's text, keeping the location the message starts with.
|
|
742
|
+
def validator_issue_message(issue, details: nil)
|
|
743
|
+
message = issue.message
|
|
744
|
+
message = message.delete_suffix(issue.raw_issue['message'].to_s) + details if details.present?
|
|
745
|
+
{ type: issue.severity, message: }
|
|
520
746
|
end
|
|
521
747
|
|
|
522
748
|
# Rejects validator issues that are already filtered or are located at/below
|
|
@@ -710,29 +936,6 @@ module DaVinciPASTestKit
|
|
|
710
936
|
bundle_map[key]
|
|
711
937
|
end
|
|
712
938
|
|
|
713
|
-
def absolute_url(reference, base_url)
|
|
714
|
-
return if reference.blank?
|
|
715
|
-
return reference if base_url.blank? || reference.starts_with?('urn:uuid:') || URI(reference).absolute?
|
|
716
|
-
|
|
717
|
-
"#{base_url}/#{reference}"
|
|
718
|
-
end
|
|
719
|
-
|
|
720
|
-
# Extracts the base URL from an absolute URL by removing the resource type and ID.
|
|
721
|
-
# @param absolute_url [String] The absolute URL.
|
|
722
|
-
# @return [String] The base URL, or an empty string if the URL format is not as expected.
|
|
723
|
-
def extract_base_url(absolute_url)
|
|
724
|
-
return '' if absolute_url.blank?
|
|
725
|
-
|
|
726
|
-
uri = URI(absolute_url)
|
|
727
|
-
return '' unless uri.scheme && uri.host
|
|
728
|
-
|
|
729
|
-
# Split the path segments and remove the last two segments (resource type and id)
|
|
730
|
-
path_segments = uri.path.split('/')
|
|
731
|
-
base_path = path_segments[0...-2].join('/')
|
|
732
|
-
|
|
733
|
-
"#{uri.scheme}://#{uri.host}#{base_path}"
|
|
734
|
-
end
|
|
735
|
-
|
|
736
939
|
# Resource Types to validate in request/ response bundle
|
|
737
940
|
def find_profile_url(request_type)
|
|
738
941
|
{
|
|
@@ -751,7 +954,7 @@ module DaVinciPASTestKit
|
|
|
751
954
|
|
|
752
955
|
# Determines the target profile URL for a Claim resource in a submit request bundle.
|
|
753
956
|
#
|
|
754
|
-
# In v2.2.1, profile-pas-request-bundle permits either profile-claim or profile-claim-update.
|
|
957
|
+
# In PAS v2.2.1, profile-pas-request-bundle permits either profile-claim or profile-claim-update.
|
|
755
958
|
# The structural discriminator is Claim.related: profile-claim-update requires it (must-support)
|
|
756
959
|
# while profile-claim disallows it (max: 0). For all other versions, profile-claim-update is
|
|
757
960
|
# used unconditionally.
|
|
@@ -785,15 +988,15 @@ module DaVinciPASTestKit
|
|
|
785
988
|
is_unique = sequences.uniq.length == sequences.length
|
|
786
989
|
return if is_unique
|
|
787
990
|
|
|
788
|
-
|
|
789
|
-
|
|
991
|
+
add_validation_error("[Claim/#{claim.id}]: The sequence element for each supportingInfo entry SHALL be " \
|
|
992
|
+
'unique within the Claim.')
|
|
790
993
|
end
|
|
791
994
|
|
|
792
995
|
def validate_bundle_entries_full_url(bundle)
|
|
793
996
|
msg = "[Bundle/#{bundle.id}]: Bundle.entry.fullUrl values SHALL be a valid url or in the form " \
|
|
794
997
|
"'urn:uuid:[some guid]'."
|
|
795
998
|
bundle.entry.each do |entry|
|
|
796
|
-
|
|
999
|
+
add_validation_error(msg) unless valid_url_or_urn_uuid?(entry.fullUrl)
|
|
797
1000
|
end
|
|
798
1001
|
end
|
|
799
1002
|
|
|
@@ -807,119 +1010,6 @@ module DaVinciPASTestKit
|
|
|
807
1010
|
string&.match?(url_regex) || string&.match?(urn_uuid_regex)
|
|
808
1011
|
end
|
|
809
1012
|
|
|
810
|
-
# This method traverses references within a FHIR resource, ensuring that referenced resources
|
|
811
|
-
# are populated in the bundle. It also enforces that a referenced resource appears only once in the bundle,
|
|
812
|
-
# as required by the PAS IG.
|
|
813
|
-
# @param target_resource [FHIR::Model] The FHIR resource to traverse and validate.
|
|
814
|
-
# @param base_url [String] The server base url.
|
|
815
|
-
# @param resources_to_match [Array<FHIR:Bundle:Entry] The list of FHIR bundle entries to match references against.
|
|
816
|
-
# @param skip_claim_related [Boolean] When true, a Claim's `related` element is not traversed. This is set
|
|
817
|
-
# for any Claim reached by following a reference (i.e. a non-primary Claim in a Claim Update chain), whose
|
|
818
|
-
# own Claim.related.claim (the grandparent) is deliberately omitted from the Bundle per spec-65/66. The
|
|
819
|
-
# primary Claim passed in by the caller keeps `skip_claim_related: false`, so its parent reference - and the
|
|
820
|
-
# parent's own referenced resources - are still checked.
|
|
821
|
-
def check_presence_of_referenced_resources(target_resource, base_url, resources_to_match,
|
|
822
|
-
skip_claim_related: false)
|
|
823
|
-
return if target_resource.blank?
|
|
824
|
-
|
|
825
|
-
if target_resource.is_a?(FHIR::Reference) && target_resource.reference.present?
|
|
826
|
-
ref = target_resource.reference
|
|
827
|
-
absolute_ref = absolute_url(ref, base_url)
|
|
828
|
-
matching_resources = resources_to_match.find_all { |res| res.fullUrl == absolute_ref }
|
|
829
|
-
|
|
830
|
-
if matching_resources.length != 1
|
|
831
|
-
validation_error_messages << resource_shall_appear_once_message(absolute_ref,
|
|
832
|
-
matching_resources.length)
|
|
833
|
-
end
|
|
834
|
-
|
|
835
|
-
if matching_resources.length.positive?
|
|
836
|
-
# A resource reached by following a reference is an included resource, not the primary Claim
|
|
837
|
-
# being validated; if it is itself a Claim Update, its referenced grandparent Claim is omitted.
|
|
838
|
-
check_presence_of_referenced_resources(matching_resources.first.resource, base_url, resources_to_match,
|
|
839
|
-
skip_claim_related: true)
|
|
840
|
-
end
|
|
841
|
-
else
|
|
842
|
-
target_resource.source_hash.each_key do |attr|
|
|
843
|
-
next if claim_response_request_attr?(target_resource, attr)
|
|
844
|
-
next if skip_claim_related && claim_related_attr?(target_resource, attr)
|
|
845
|
-
|
|
846
|
-
value = target_resource.send(attr.to_sym)
|
|
847
|
-
if value.is_a?(FHIR::Model)
|
|
848
|
-
check_presence_of_referenced_resources(value, base_url, resources_to_match, skip_claim_related:)
|
|
849
|
-
elsif value.is_a?(Array) && value.all?(FHIR::Model)
|
|
850
|
-
value.each do |elmt|
|
|
851
|
-
check_presence_of_referenced_resources(elmt, base_url, resources_to_match, skip_claim_related:)
|
|
852
|
-
end
|
|
853
|
-
end
|
|
854
|
-
end
|
|
855
|
-
end
|
|
856
|
-
end
|
|
857
|
-
|
|
858
|
-
# ClaimResponse.request is a back-reference to the submitted Claim. The PAS IG response bundle
|
|
859
|
-
# profile (profile-pas-response-bundle) has no required Claim entry slice, so the Claim need
|
|
860
|
-
# not be present in the response bundle. Skipping here matches the identical guard in
|
|
861
|
-
# ResponseGenerator#referenced_entities, which also skips ClaimResponse.request when
|
|
862
|
-
# building mock response bundles.
|
|
863
|
-
def claim_response_request_attr?(resource, attr)
|
|
864
|
-
attr.to_s == 'request' &&
|
|
865
|
-
resource.respond_to?(:resourceType) &&
|
|
866
|
-
resource.resourceType == 'ClaimResponse'
|
|
867
|
-
end
|
|
868
|
-
|
|
869
|
-
# Claim.related.claim points to the Claim being updated. For a non-primary Claim in a Claim Update
|
|
870
|
-
# chain (one reached by following a reference), that prior Claim is the grandparent, which spec-65/66
|
|
871
|
-
# require to be omitted from the Bundle. Used with the `skip_claim_related` flag so the generic
|
|
872
|
-
# reference-presence check does not flag the deliberately-omitted grandparent as missing.
|
|
873
|
-
def claim_related_attr?(resource, attr)
|
|
874
|
-
attr.to_s == 'related' &&
|
|
875
|
-
resource.respond_to?(:resourceType) &&
|
|
876
|
-
resource.resourceType == 'Claim'
|
|
877
|
-
end
|
|
878
|
-
|
|
879
|
-
# Extracts resources from a bundle while following "next" links.
|
|
880
|
-
#
|
|
881
|
-
# @param bundle [FHIR::Bundle] The initial FHIR bundle to extract resources from.
|
|
882
|
-
# @param response [Object] The HTTP response object for the bundle retrieval.
|
|
883
|
-
# @param reply_handler [Proc] A callback function to handle responses.
|
|
884
|
-
# @param max_pages [Integer] The maximum number of pages to process.
|
|
885
|
-
#
|
|
886
|
-
# This method extracts resources from a FHIR bundle, following "next" links in the bundle
|
|
887
|
-
# until the specified maximum number of pages is reached. It collects resources and
|
|
888
|
-
# invokes the reply_handler for each response.
|
|
889
|
-
def extract_resources_from_bundle(
|
|
890
|
-
bundle: nil,
|
|
891
|
-
response: nil,
|
|
892
|
-
reply_handler: nil,
|
|
893
|
-
max_pages: 20
|
|
894
|
-
)
|
|
895
|
-
page_count = 1
|
|
896
|
-
resources = []
|
|
897
|
-
|
|
898
|
-
until bundle.nil? || page_count == max_pages
|
|
899
|
-
resources += bundle&.entry&.map { |entry| entry&.resource }
|
|
900
|
-
next_bundle_link = bundle&.link&.find { |link| link.relation == 'next' }&.url
|
|
901
|
-
reply_handler&.call(response)
|
|
902
|
-
|
|
903
|
-
break if next_bundle_link.blank?
|
|
904
|
-
|
|
905
|
-
page_count += 1
|
|
906
|
-
end
|
|
907
|
-
|
|
908
|
-
resources
|
|
909
|
-
end
|
|
910
|
-
|
|
911
|
-
# Generates a message for a resource that appears more than once in a bundle.
|
|
912
|
-
#
|
|
913
|
-
# @param reference_resource_type [String] The resource type being referenced.
|
|
914
|
-
# @param reference_resource_id [String] The resource ID being referenced.
|
|
915
|
-
# @param total_matches [Integer] The total number of matches found in the bundle.
|
|
916
|
-
#
|
|
917
|
-
# This method generates an error message when a referenced resource appears more than once
|
|
918
|
-
# in a FHIR bundle, which is not allowed.
|
|
919
|
-
def resource_shall_appear_once_message(absolute_ref, total_matches)
|
|
920
|
-
" The referenced #{absolute_ref} resource SHALL appear exactly once in the Bundle, but found #{total_matches}."
|
|
921
|
-
end
|
|
922
|
-
|
|
923
1013
|
# Generates a message for a resource present in both the PA request and response bundles.
|
|
924
1014
|
#
|
|
925
1015
|
# @param resource [FHIR::Model] The resource present in both bundles.
|
|
@@ -930,5 +1020,115 @@ module DaVinciPASTestKit
|
|
|
930
1020
|
"Resource #{resource.resourceType}/#{resource.id} is an entry in both the PA Request Bundle and the Response " \
|
|
931
1021
|
'Bundle, but they do not have the same fullUrl or identifiers'
|
|
932
1022
|
end
|
|
1023
|
+
|
|
1024
|
+
###########################################################################
|
|
1025
|
+
# US Core Profile Constants
|
|
1026
|
+
###########################################################################
|
|
1027
|
+
|
|
1028
|
+
US_CORE_PROFILE_BASE = 'http://hl7.org/fhir/us/core/StructureDefinition'
|
|
1029
|
+
BASE_R4_PROFILE = :base_r4
|
|
1030
|
+
CLAIM_ENCOUNTER_EXTENSION_URL = 'http://hl7.org/fhir/5.0/StructureDefinition/extension-Claim.encounter'
|
|
1031
|
+
LOINC_SYSTEM = 'http://loinc.org'
|
|
1032
|
+
TERMINOLOGY_CONDITION_CATEGORY_SYSTEM = 'http://terminology.hl7.org/CodeSystem/condition-category'
|
|
1033
|
+
OBSERVATION_CATEGORY_SYSTEM = 'http://terminology.hl7.org/CodeSystem/observation-category'
|
|
1034
|
+
DIAGNOSTIC_REPORT_CATEGORY_SYSTEM = 'http://terminology.hl7.org/CodeSystem/v2-0074'
|
|
1035
|
+
|
|
1036
|
+
US_CORE_SINGLE_PROFILE_IDS_BY_RESOURCE = {
|
|
1037
|
+
'AllergyIntolerance' => 'us-core-allergyintolerance',
|
|
1038
|
+
'CarePlan' => 'us-core-careplan',
|
|
1039
|
+
'CareTeam' => 'us-core-careteam',
|
|
1040
|
+
'Coverage' => 'us-core-coverage',
|
|
1041
|
+
'Device' => 'us-core-implantable-device',
|
|
1042
|
+
'DocumentReference' => 'us-core-documentreference',
|
|
1043
|
+
'Encounter' => 'us-core-encounter',
|
|
1044
|
+
'Goal' => 'us-core-goal',
|
|
1045
|
+
'Immunization' => 'us-core-immunization',
|
|
1046
|
+
'Location' => 'us-core-location',
|
|
1047
|
+
'Medication' => 'us-core-medication',
|
|
1048
|
+
'MedicationDispense' => 'us-core-medicationdispense',
|
|
1049
|
+
'MedicationRequest' => 'us-core-medicationrequest',
|
|
1050
|
+
'Organization' => 'us-core-organization',
|
|
1051
|
+
'Patient' => 'us-core-patient',
|
|
1052
|
+
'Practitioner' => 'us-core-practitioner',
|
|
1053
|
+
'PractitionerRole' => 'us-core-practitionerrole',
|
|
1054
|
+
'Procedure' => 'us-core-procedure',
|
|
1055
|
+
'Provenance' => 'us-core-provenance',
|
|
1056
|
+
'QuestionnaireResponse' => 'us-core-questionnaireresponse',
|
|
1057
|
+
'RelatedPerson' => 'us-core-relatedperson',
|
|
1058
|
+
'ServiceRequest' => 'us-core-servicerequest',
|
|
1059
|
+
'Specimen' => 'us-core-specimen'
|
|
1060
|
+
}.freeze
|
|
1061
|
+
|
|
1062
|
+
US_CORE_CONDITION_PROFILE_ID = 'us-core-condition'
|
|
1063
|
+
US_CORE_CONDITION_ENCOUNTER_DIAGNOSIS_PROFILE_ID = 'us-core-condition-encounter-diagnosis'
|
|
1064
|
+
US_CORE_CONDITION_PROBLEMS_HEALTH_CONCERNS_PROFILE_ID = 'us-core-condition-problems-health-concerns'
|
|
1065
|
+
US_CORE_DIAGNOSTIC_REPORT_LAB_PROFILE_ID = 'us-core-diagnosticreport-lab'
|
|
1066
|
+
US_CORE_DIAGNOSTIC_REPORT_NOTE_PROFILE_ID = 'us-core-diagnosticreport-note'
|
|
1067
|
+
US_CORE_OBSERVATION_CLINICAL_RESULT_PROFILE_ID = 'us-core-observation-clinical-result'
|
|
1068
|
+
US_CORE_OBSERVATION_LAB_PROFILE_ID = 'us-core-observation-lab'
|
|
1069
|
+
US_CORE_OBSERVATION_SCREENING_ASSESSMENT_PROFILE_ID = 'us-core-observation-screening-assessment'
|
|
1070
|
+
US_CORE_SIMPLE_OBSERVATION_PROFILE_ID = 'us-core-simple-observation'
|
|
1071
|
+
US_CORE_SMOKING_STATUS_PROFILE_ID = 'us-core-smokingstatus'
|
|
1072
|
+
US_CORE_VITAL_SIGNS_PROFILE_ID = 'us-core-vital-signs'
|
|
1073
|
+
|
|
1074
|
+
US_CORE_OBSERVATION_CODE_PROFILE_IDS = {
|
|
1075
|
+
'11341-5' => 'us-core-observation-occupation',
|
|
1076
|
+
'86645-9' => 'us-core-observation-pregnancyintent',
|
|
1077
|
+
'82810-3' => 'us-core-observation-pregnancystatus',
|
|
1078
|
+
'76690-7' => 'us-core-observation-sexual-orientation',
|
|
1079
|
+
'95541-9' => 'us-core-care-experience-preference',
|
|
1080
|
+
'75773-2' => 'us-core-treatment-intervention-preference',
|
|
1081
|
+
'8289-1' => 'head-occipital-frontal-circumference-percentile',
|
|
1082
|
+
'59576-9' => 'pediatric-bmi-for-age',
|
|
1083
|
+
'77606-2' => 'pediatric-weight-for-height',
|
|
1084
|
+
'85354-9' => 'us-core-blood-pressure',
|
|
1085
|
+
'96607-7' => 'us-core-average-blood-pressure',
|
|
1086
|
+
'39156-5' => 'us-core-bmi',
|
|
1087
|
+
'8302-2' => 'us-core-body-height',
|
|
1088
|
+
'8310-5' => 'us-core-body-temperature',
|
|
1089
|
+
'29463-7' => 'us-core-body-weight',
|
|
1090
|
+
'9843-4' => 'us-core-head-circumference',
|
|
1091
|
+
'8867-4' => 'us-core-heart-rate',
|
|
1092
|
+
'59408-5' => 'us-core-pulse-oximetry',
|
|
1093
|
+
'2708-6' => 'us-core-pulse-oximetry',
|
|
1094
|
+
'9279-1' => 'us-core-respiratory-rate',
|
|
1095
|
+
'72166-2' => 'us-core-smokingstatus'
|
|
1096
|
+
}.freeze
|
|
1097
|
+
|
|
1098
|
+
# Fallback profiles that US Core 3.1.1 does not define, keyed by the earliest supported
|
|
1099
|
+
# version that does. Profiles not listed here exist in every supported version.
|
|
1100
|
+
US_CORE_PROFILE_IDS_ADDED_IN_VERSION = {
|
|
1101
|
+
PASConstants::US_CORE_VERSION_6_1_0 => [
|
|
1102
|
+
'us-core-blood-pressure',
|
|
1103
|
+
'us-core-bmi',
|
|
1104
|
+
'us-core-body-height',
|
|
1105
|
+
'us-core-body-temperature',
|
|
1106
|
+
'us-core-body-weight',
|
|
1107
|
+
'us-core-condition-encounter-diagnosis',
|
|
1108
|
+
'us-core-condition-problems-health-concerns',
|
|
1109
|
+
'us-core-coverage',
|
|
1110
|
+
'us-core-head-circumference',
|
|
1111
|
+
'us-core-heart-rate',
|
|
1112
|
+
'us-core-medicationdispense',
|
|
1113
|
+
'us-core-observation-clinical-result',
|
|
1114
|
+
'us-core-observation-occupation',
|
|
1115
|
+
'us-core-observation-pregnancyintent',
|
|
1116
|
+
'us-core-observation-pregnancystatus',
|
|
1117
|
+
'us-core-observation-screening-assessment',
|
|
1118
|
+
'us-core-observation-sexual-orientation',
|
|
1119
|
+
'us-core-questionnaireresponse',
|
|
1120
|
+
'us-core-relatedperson',
|
|
1121
|
+
'us-core-respiratory-rate',
|
|
1122
|
+
'us-core-servicerequest',
|
|
1123
|
+
'us-core-simple-observation',
|
|
1124
|
+
'us-core-specimen',
|
|
1125
|
+
'us-core-vital-signs'
|
|
1126
|
+
],
|
|
1127
|
+
PASConstants::US_CORE_VERSION_7_0_0 => [
|
|
1128
|
+
'us-core-average-blood-pressure',
|
|
1129
|
+
'us-core-care-experience-preference',
|
|
1130
|
+
'us-core-treatment-intervention-preference'
|
|
1131
|
+
]
|
|
1132
|
+
}.freeze
|
|
933
1133
|
end
|
|
934
1134
|
end
|