diff --git a/.github/actions/publish-images/action.yml b/.github/actions/publish-images/action.yml index 38f5d71970..65e401e653 100644 --- a/.github/actions/publish-images/action.yml +++ b/.github/actions/publish-images/action.yml @@ -2,10 +2,6 @@ name: Publish images to GHCR description: Builds, tags, and publish VRO's Docker images inputs: - image_prefix: - description: 'The prefix for the image name, e.g., "dev_" or "" (no prefix)' - type: string - default: 'dev_' image_tag: description: 'The tag for the image, e.g., first 7 of the commit hash' type: string @@ -62,7 +58,7 @@ runs: # This IMG_TAG value will cause a new image to be publish (and scanned by SecRel) IMG_TAG="${{ inputs.image_tag }}" - IMG_NAME="${{ inputs.image_prefix }}$(getVarValue "${PREFIX}" _IMG)" + IMG_NAME="$(getVarValue "${PREFIX}" _IMG)" echo "::group::Push image $IMG_NAME $IMG_TAG" GHCR_PATH="ghcr.io/${{ github.repository }}/${IMG_NAME}" if [ "$(imageTagExists "$IMG_NAME" "$IMG_TAG")" == "200" ]; then diff --git a/.github/workflows/delete-published-dev-images.yml b/.github/workflows/delete-published-dev-images.yml deleted file mode 100644 index 51f933cc99..0000000000 --- a/.github/workflows/delete-published-dev-images.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: "9. (Internal) Delete old published DEV images" -on: - schedule: - # Run at 01:01 twice a month. - # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html#tag_20_25_07 - - cron: '1 1 5,19 * *' - - # Allow manual triggering - workflow_dispatch: - inputs: - retain_days: - description: 'Delete images older than this many days' - required: true - type: string - default: 30 - keep_last: - description: 'Minimum versions to keep' - required: true - type: string - default: 10 - dry_run: - description: 'Always do a dry-run first' - required: true - type: boolean - default: true - -jobs: - delete_images: - if: github.repository == 'department-of-veterans-affairs/abd-vro-internal' - continue-on-error: true - strategy: - fail-fast: false - matrix: - repo: - - abd-vro-internal - # Do NOT delete non-dev images, which will be managed in a different workflow - package: - - dev_vro-api-gateway - - dev_vro-app - - dev_vro-db-init - - dev_vro-svc-bgs-api - - dev_vro-svc-lighthouse-api - - dev_vro-svc-bie-kafka - - dev_vro-xample-workflows - - dev_vro-cc-app - - dev_vro-ee-max-cfi-app - runs-on: ubuntu-latest - steps: - - name: "Delete old images in GHCR" - uses: vlaurin/action-ghcr-prune@v0.6.0 - with: - token: ${{ secrets.ACCESS_TOKEN_DELETE_PACKAGE }} - organization: department-of-veterans-affairs - container: ${{ matrix.repo }}/${{ matrix.package }} - # Dry-run first, then change to `false` - dry-run: ${{ inputs.dry_run }} - keep-younger-than: ${{ inputs.retain_days || 30 }} # days - # This applies to each of the 2 categories separately: prune-untagged and prune-tags-regexes - keep-last: ${{ inputs.keep_last || 10 }} - # Packages without a tag (shown as sha256:...) - prune-untagged: true - # Package with exactly 7 characters and SecRel-created signatures - prune-tags-regexes: | - ^.......$ - ^sha256-.*.sig$ diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index cab16c0f68..e30dfe548f 100644 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -1,6 +1,5 @@ name: Dependabot auto-merge -on: - pull_request: +on: pull_request permissions: contents: write @@ -9,17 +8,16 @@ permissions: jobs: dependabot: runs-on: ubuntu-latest - if: github.actor == 'dependabot[bot]' && github.repository == 'department-of-veterans-affairs/abd-vro' - + if: github.actor == 'dependabot[bot]' steps: - name: Dependabot metadata id: metadata uses: dependabot/fetch-metadata@v1 with: - github-token: "${{ secrets.ACCESS_TOKEN_PUSH_TO_DEVELOP }}" + github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Enable auto-merge for Dependabot PRs if: steps.metadata.outputs.update-type == 'version-update:semver-patch' run: gh pr merge --auto --merge "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} - GH_TOKEN: ${{secrets.ACCESS_TOKEN_PUSH_TO_DEVELOP}} + GH_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/secrel.yml b/.github/workflows/secrel.yml index 9fa82d47c3..aa99bae89d 100644 --- a/.github/workflows/secrel.yml +++ b/.github/workflows/secrel.yml @@ -1,5 +1,5 @@ name: "2. (Internal) SecRel workflow" -run-name: "SecRel ${{inputs.image_prefix}} (${{github.ref_name}}) ${{github.event.head_commit.message}}" +run-name: "SecRel (${{github.ref_name}}) ${{github.event.head_commit.message}}" on: # Trigger on every code push to main and develop branches @@ -12,14 +12,6 @@ on: # Allow manual runs workflow_dispatch: inputs: - image_prefix: - description: 'Image prefix for the chosen branch. Choose `(no prefix)` to create non-dev images for deployment to sandbox, prod-test, and prod.' - required: true - default: 'dev_' - type: choice - options: - - "dev_" - - "(no prefix)" run_tests: description: "Run Gradle tests?" required: true @@ -70,43 +62,31 @@ jobs: run-secrel: ${{ steps.image-props.outputs.run_secrel }} runs-on: ubuntu-latest steps: - - name: "Determine image prefix and tag" + - name: "Determine image tag" id: image-props run: | # Set defaults IMG_TAG=${GITHUB_SHA:0:7} - IMG_PREFIX="dev_" RUN_GRADLE_TESTS="true" RUN_SECREL="true" # Override some defaults depending on the branch/ref_name echo "ref_name: ${{ github.ref_name }}" - case "${{ github.ref_name }}" in - main) IMG_PREFIX="" - ;; - develop) # To reduce workflow runtime, don't run tests - RUN_GRADLE_TESTS=false - # To reduce SecRel scans, only published changed images - ;; - esac # If workflow was manually dispatched, override settings if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then - [ "${{ inputs.image_prefix }}" == "(no prefix)" ] && IMG_PREFIX="" RUN_GRADLE_TESTS=${{ inputs.run_tests }} RUN_SECREL=${{ inputs.run_secrel }} fi { echo "image_tag=${IMG_TAG}" - echo "image_prefix=${IMG_PREFIX}" echo "run_tests=${RUN_GRADLE_TESTS}" echo "run_secrel=${RUN_SECREL}" } >> "$GITHUB_OUTPUT" - name: "DEBUG" run: | - echo "image_prefix: ${{ steps.image-props.outputs.image_prefix }}" echo "image_tag: ${{ steps.image-props.outputs.image_tag }}" echo "run_tests: ${{ steps.image-props.outputs.run_tests }}" @@ -125,17 +105,15 @@ jobs: slack-text: ":arrow_forward: \ <${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}}|\ SecRel running (#${{ github.run_number }})>: \ - Publishing images with prefix `${{ steps.image-props.outputs.image_prefix }}` \ - and tag `${{ steps.image-props.outputs.image_tag }}` \ + Publishing images with tag `${{ steps.image-props.outputs.image_tag }}` \ from ${{github.ref_type}} `${{github.ref_name}}`, \ caused by `${{github.event_name}}` triggered by `${{github.triggering_actor}}` \ (Run tests? ${{ steps.image-props.outputs.run_tests }})...\n" - - name: "Publish ${{ steps.image-props.outputs.image_prefix }} images to GHCR" + - name: "Publish images to GHCR" id: publish-images uses: ./.github/actions/publish-images with: - image_prefix: "${{ steps.image-props.outputs.image_prefix }}" image_tag: "${{ steps.image-props.outputs.image_tag }}" ghcr_username: ${{ github.actor }} ghcr_password: ${{ secrets.GITHUB_TOKEN }} diff --git a/api-gateway/build.gradle b/api-gateway/build.gradle index efbcab0caa..fe67ad44ee 100644 --- a/api-gateway/build.gradle +++ b/api-gateway/build.gradle @@ -11,7 +11,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' // Spring Cloud - implementation 'org.springframework.cloud:spring-cloud-starter-gateway:4.1.1' + implementation 'org.springframework.cloud:spring-cloud-starter-gateway:4.1.2' if (osdetector.classifier == "osx-aarch_64") { // Fix MacOS error: Unable to load io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider, // which may result in incorrect DNS resolutions. @@ -21,10 +21,10 @@ dependencies { // Swagger UI for WebFlux implementation "org.springdoc:springdoc-openapi-starter-webflux-ui:${spring_doc_version}" - implementation 'io.netty:netty-codec-http2:4.1.107.Final' + implementation 'io.netty:netty-codec-http2:4.1.108.Final' constraints { // To address Snyk alert on DoS vulnerability - implementation 'org.springframework.boot:spring-boot-autoconfigure:3.2.3' + implementation 'org.springframework.boot:spring-boot-autoconfigure:3.2.4' } } diff --git a/db-init/Dockerfile b/db-init/Dockerfile index 6ef5f618b1..e0958cbfab 100644 --- a/db-init/Dockerfile +++ b/db-init/Dockerfile @@ -1,4 +1,4 @@ -FROM flyway/flyway:10.10-alpine +FROM flyway/flyway:10.11-alpine # hadolint ignore=DL3018 RUN < 10000: raise HTTPException(status_code=400, detail=f"The diagnostic code received is invalid: dc={dc}") + + +if __name__ == "__main__": + uvicorn.run(app, host="localhost", port=8130) diff --git a/domain-ee/ee-max-cfi-app/src/python_src/util/data/Max Ratings DC Lookup Table v0.1.csv b/domain-ee/ee-max-cfi-app/src/python_src/util/data/Max Ratings DC Lookup Table v0.1.csv deleted file mode 100644 index a1ab90daeb..0000000000 --- a/domain-ee/ee-max-cfi-app/src/python_src/util/data/Max Ratings DC Lookup Table v0.1.csv +++ /dev/null @@ -1,2 +0,0 @@ -Diagnostic Code,Rated Issue Name,Max Rating(%) -6260,Tinnitus,10 diff --git a/domain-ee/ee-max-cfi-app/src/python_src/util/data/Max Ratings DC Lookup Table v1.0.csv b/domain-ee/ee-max-cfi-app/src/python_src/util/data/Max Ratings DC Lookup Table v1.0.csv new file mode 100644 index 0000000000..e192a0d0f3 --- /dev/null +++ b/domain-ee/ee-max-cfi-app/src/python_src/util/data/Max Ratings DC Lookup Table v1.0.csv @@ -0,0 +1,730 @@ +Diagnostic Code,Rated Issue Name,Max Rating(%),Body System, Category, Subcategory, CFR_Ref +5000,"Osteomyelitis, acute, subacute, or chronic.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5001,"Bones and joints, tuberculosis of, active or inactive.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5002,"Multi-joint arthritis (except post-traumatic and gout), 2 or more joints, as an active process.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5003,"Degenerative arthritis, other than post-traumatic.",20,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5004,"Arthritis, gonorrheal.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5005,"Arthritis, pneumococcic.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5006,"Arthritis, typhoid.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5007,"Arthritis, syphilitic.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5008,"Arthritis, streptococcic.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5009,Other specified forms of arthropathy (excluding gout).,100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5010,Post-traumatic arthritis.,100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5011,Decompression illness.,100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5012,"Bones, neoplasm, malignant, primary or secondary.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5013,"Osteoporosis, residuals of.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5014,"Osteomalacia, residuals of.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5015,"Bones, neoplasm, benign.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5016,Osteitis deformans.,100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5017,Gout.,100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5018,[Removed],100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5019,Bursitis.,100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5020,[Removed],100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5021,Myositis.,100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5022,[Removed],100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5023,Heterotopic ossification.,100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5024,"Tenosynovitis, tendinitis, tendinosis or tendinopathy.",100,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5025,"Fibromyalgia (fibrositis, primary fibromyalgia syndrome).",40,Musculoskeletal,"Acute, Subacute, or Chronic Diseases",,38 CFR 4.71a +5051,Shoulder replacement (prosthesis),100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5052,Elbow replacement (prosthesis).,100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5053,Wrist replacement (prosthesis).,100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5054,"Hip, resurfacing or replacement (prosthesis).",100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5055,"Knee, resurfacing or replacement (prosthesis).",100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5056,Ankle replacement (prosthesis).,100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5104,Anatomical loss of one hand and loss of use of one foot,100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5105,Anatomical loss of one foot and loss of use of one hand,100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5106,Anatomical loss of both hands,100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5107,Anatomical loss of both feet,100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5108,Anatomical loss of one hand and one foot,100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5109,Loss of use of both hands,100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5110,Loss of use of both feet,100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5111,Loss of use of one hand and one foot,100,Musculoskeletal,Prosthetic Implants and Resurfacing,,38 CFR 4.71a +5120,"Complete amputation, upper extremity.",100,Musculoskeletal,Amputations: Upper Extremity,"Arm, amputation of:",38 CFR 4.71a +5121,Above insertion of deltoid,90,Musculoskeletal,Amputations: Upper Extremity,"Arm, amputation of:",38 CFR 4.71a +5122,Below insertion of deltoid,80,Musculoskeletal,Amputations: Upper Extremity,"Arm, amputation of:",38 CFR 4.71a +5123,Above insertion of pronator teres,80,Musculoskeletal,Amputations: Upper Extremity,"Forearm, amputation of:",38 CFR 4.71a +5124,Below insertion of pronator teres,70,Musculoskeletal,Amputations: Upper Extremity,"Forearm, amputation of:",38 CFR 4.71a +5125,"Hand, loss of use of",70,Musculoskeletal,Amputations: Upper Extremity,"Forearm, amputation of:",38 CFR 4.71a +5126,"Five digits of one hand, amputation of",70,Musculoskeletal,Amputations: Upper Extremity,"Four digits of one hand, amputation of:",38 CFR 4.71a +5127,"Thumb, index, long and ring",70,Musculoskeletal,Amputations: Upper Extremity,"Four digits of one hand, amputation of:",38 CFR 4.71a +5128,"Thumb, index, long and little",70,Musculoskeletal,Amputations: Upper Extremity,"Four digits of one hand, amputation of:",38 CFR 4.71a +5129,"Thumb, index, ring and little",70,Musculoskeletal,Amputations: Upper Extremity,"Four digits of one hand, amputation of:",38 CFR 4.71a +5130,"Thumb, long, ring and little",70,Musculoskeletal,Amputations: Upper Extremity,"Four digits of one hand, amputation of:",38 CFR 4.71a +5131,"Index, long, ring and little",60,Musculoskeletal,Amputations: Upper Extremity,"Four digits of one hand, amputation of:",38 CFR 4.71a +5132,"Thumb, index and long",60,Musculoskeletal,Amputations: Upper Extremity,"Three digits of one hand, amputation of:",38 CFR 4.71a +5133,"Thumb, index and ring",60,Musculoskeletal,Amputations: Upper Extremity,"Three digits of one hand, amputation of:",38 CFR 4.71a +5134,"Thumb, index and little",60,Musculoskeletal,Amputations: Upper Extremity,"Three digits of one hand, amputation of:",38 CFR 4.71a +5135,"Thumb, long and ring",60,Musculoskeletal,Amputations: Upper Extremity,"Three digits of one hand, amputation of:",38 CFR 4.71a +5136,"Thumb, long and little",60,Musculoskeletal,Amputations: Upper Extremity,"Three digits of one hand, amputation of:",38 CFR 4.71a +5137,"Thumb, ring and little",60,Musculoskeletal,Amputations: Upper Extremity,"Three digits of one hand, amputation of:",38 CFR 4.71a +5138,"Index, long and ring",50,Musculoskeletal,Amputations: Upper Extremity,"Three digits of one hand, amputation of:",38 CFR 4.71a +5139,"Index, long and little",50,Musculoskeletal,Amputations: Upper Extremity,"Three digits of one hand, amputation of:",38 CFR 4.71a +5140,"Index, ring and little",50,Musculoskeletal,Amputations: Upper Extremity,"Three digits of one hand, amputation of:",38 CFR 4.71a +5141,"Long, ring and little",40,Musculoskeletal,Amputations: Upper Extremity,"Three digits of one hand, amputation of:",38 CFR 4.71a +5142,Thumb and index,50,Musculoskeletal,Amputations: Upper Extremity,"Two digits of one hand, amputation of:",38 CFR 4.71a +5143,Thumb and long,50,Musculoskeletal,Amputations: Upper Extremity,"Two digits of one hand, amputation of:",38 CFR 4.71a +5144,Thumb and ring,50,Musculoskeletal,Amputations: Upper Extremity,"Two digits of one hand, amputation of:",38 CFR 4.71a +5145,Thumb and little,50,Musculoskeletal,Amputations: Upper Extremity,"Two digits of one hand, amputation of:",38 CFR 4.71a +5146,Index and long,40,Musculoskeletal,Amputations: Upper Extremity,"Two digits of one hand, amputation of:",38 CFR 4.71a +5147,Index and ring,40,Musculoskeletal,Amputations: Upper Extremity,"Two digits of one hand, amputation of:",38 CFR 4.71a +5148,Index and little,40,Musculoskeletal,Amputations: Upper Extremity,"Two digits of one hand, amputation of:",38 CFR 4.71a +5149,Long and ring,30,Musculoskeletal,Amputations: Upper Extremity,"Two digits of one hand, amputation of:",38 CFR 4.71a +5150,Long and little,30,Musculoskeletal,Amputations: Upper Extremity,"Two digits of one hand, amputation of:",38 CFR 4.71a +5151,Ring and little,30,Musculoskeletal,Amputations: Upper Extremity,"Two digits of one hand, amputation of:",38 CFR 4.71a +5152,"Thumb, amputation of.",40,Musculoskeletal,Amputations: Upper Extremity,Single finger amputations,38 CFR 4.71a +5153,"Index finger, amputation of",30,Musculoskeletal,Amputations: Upper Extremity,Single finger amputations,38 CFR 4.71a +5154,"Long finger, amputation of.",20,Musculoskeletal,Amputations: Upper Extremity,Single finger amputations,38 CFR 4.71a +5155,"Ring finger, amputation of.",20,Musculoskeletal,Amputations: Upper Extremity,Single finger amputations,38 CFR 4.71a +5156,"Little finger, amputation of.",20,Musculoskeletal,Amputations: Upper Extremity,Single finger amputations,38 CFR 4.71a +5160,"Complete amputation, lower extremity.",100,Musculoskeletal,Amputations: Lower Extremity,"Thigh, amputation of:",38 CFR 4.71a +5161,"Upper third, one-third of the distance from perineum to knee joint measured from perineum",80,Musculoskeletal,Amputations: Lower Extremity,"Thigh, amputation of:",38 CFR 4.71a +5162,Middle or lower thirds,60,Musculoskeletal,Amputations: Lower Extremity,"Thigh, amputation of:",38 CFR 4.71a +5163,"With defective stump, thigh amputation recommended",60,Musculoskeletal,Amputations: Lower Extremity,"Leg, amputation of:",38 CFR 4.71a +5164,Amputation not improvable by prosthesis controlled by natural knee action,60,Musculoskeletal,Amputations: Lower Extremity,"Leg, amputation of:",38 CFR 4.71a +5165,"At a lower level, permitting prosthesis",40,Musculoskeletal,Amputations: Lower Extremity,"Leg, amputation of:",38 CFR 4.71a +5166,"Forefoot, amputation proximal to metatarsal bones (more than one-half of metatarsal loss)",40,Musculoskeletal,Amputations: Lower Extremity,"Leg, amputation of:",38 CFR 4.71a +5167,"Foot, loss of use of",40,Musculoskeletal,Amputations: Lower Extremity,"Leg, amputation of:",38 CFR 4.71a +5170,"Toes, all, amputation of, without metatarsal loss or transmetatarsal, amputation of, with up to half of metatarsal loss",30,Musculoskeletal,Amputations: Lower Extremity,"Leg, amputation of:",38 CFR 4.71a +5171,"Toe, great, amputation of.",30,Musculoskeletal,Amputations: Lower Extremity,"Leg, amputation of:",38 CFR 4.71a +5172,"Toes, other than great, amputation of, with removal of metatarsal head.",20,Musculoskeletal,Amputations: Lower Extremity,"Leg, amputation of:",38 CFR 4.71a +5173,"Toes, three or four, amputation of, without metatarsal involvement.",20,Musculoskeletal,Amputations: Lower Extremity,"Leg, amputation of:",38 CFR 4.71a +5200,"Scapulohumeral articulation, ankylosis of.",50,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5201,"Arm, limitation of motion of.",40,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5202,"Humerus, other impairment of.",80,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5203,"Clavicle or scapula, impairment of.",20,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5205,"Elbow, ankylosis of.",60,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5206,"Forearm, limitation of flexion of.",50,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5207,"Forearm, limitation of extension of.",50,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5208,"Forearm, flexion limited to 100° and extension to 45°",20,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5209,"Elbow, other impairment of Flail joint",60,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5210,"Radius and ulna, nonunion of, with flail false joint",50,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5211,"Ulna, impairment of.",40,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5212,"Radius, impairment of.",40,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5213,"Supination and pronation, impairment of.",40,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5214,"Wrist, ankylosis of.",50,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5215,"Wrist, limitation of motion of.",10,Musculoskeletal,The Shoulder and Arm,,38 CFR 4.71a +5216,"Five digits of one hand, unfavorable ankylosis of",60,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5217,"Four digits of one hand, unfavorable ankylosis of.",60,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5218,"Three digits of one hand, unfavorable ankylosis of.",50,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5219,"Two digits of one hand, unfavorable ankylosis of.",40,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5220,"Five digits of one hand, favorable ankylosis of",50,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5221,"Four digits of one hand, favorable ankylosis of.",50,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5222,"Three digits of one hand, favorable ankylosis of.",40,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5223,"Two digits of one hand, favorable ankylosis of.",30,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5224,"Thumb, ankylosis of.",20,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5225,"Index finger, ankylosis of.",10,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5226,"Long finger, ankylosis of.",10,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5227,"Ring or little finger, ankylosis of.",0,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5228,"Thumb, limitation of motion.",20,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5229,"Index or long finger, limitation of motion.",10,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5230,"Ring or little finger, limitation of motion.",0,Musculoskeletal,Evaluation of Ankylosis or Limitation of Motion of Single or Multiple Digits of the Hand,,38 CFR 4.71a +5235,Vertebral fracture or dislocation,100,Musculoskeletal,The Spine,,38 CFR 4.71a +5236,Sacroiliac injury and weakness,100,Musculoskeletal,The Spine,,38 CFR 4.71a +5237,Lumbosacral or cervical strain,100,Musculoskeletal,The Spine,,38 CFR 4.71a +5238,Spinal stenosis,100,Musculoskeletal,The Spine,,38 CFR 4.71a +5239,Spondylolisthesis or segmental instability,100,Musculoskeletal,The Spine,,38 CFR 4.71a +5240,Ankylosing spondylitis,100,Musculoskeletal,The Spine,,38 CFR 4.71a +5241,Spinal fusion,100,Musculoskeletal,The Spine,,38 CFR 4.71a +5242,"Degenerative arthritis, degenerative disc disease other than intervertebral disc syndrome",100,Musculoskeletal,The Spine,,38 CFR 4.71a +5243,Intervertebral disc syndrome,100,Musculoskeletal,The Spine,,38 CFR 4.71a +5244,"Traumatic paralysis, complete.",100,Musculoskeletal,The Spine,,38 CFR 4.71a +5250,"Hip, ankylosis of.",90,Musculoskeletal,The Hip and Thigh,,38 CFR 4.71a +5251,"Thigh, limitation of extension of.",10,Musculoskeletal,The Hip and Thigh,,38 CFR 4.71a +5252,"Thigh, limitation of flexion of.",40,Musculoskeletal,The Hip and Thigh,,38 CFR 4.71a +5253,"Thigh, impairment of.",20,Musculoskeletal,The Hip and Thigh,,38 CFR 4.71a +5254,"Hip, flail joint",80,Musculoskeletal,The Hip and Thigh,,38 CFR 4.71a +5255,"Femur, impairment of.",80,Musculoskeletal,The Hip and Thigh,,38 CFR 4.71a +5256,"Knee, ankylosis of.",60,Musculoskeletal,The Knee and Leg,,38 CFR 4.71a +5257,"Knee, other impairment of.",30,Musculoskeletal,The Knee and Leg,,38 CFR 4.71a +5258,"Cartilage, semilunar, dislocated, with frequent episodes of “locking,” pain, and effusion into the joint",20,Musculoskeletal,The Knee and Leg,,38 CFR 4.71a +5259,"Cartilage, semilunar, removal of, symptomatic",10,Musculoskeletal,The Knee and Leg,,38 CFR 4.71a +5260,"Leg, limitation of flexion of.",30,Musculoskeletal,The Knee and Leg,,38 CFR 4.71a +5261,"Leg, limitation of extension of.",50,Musculoskeletal,The Knee and Leg,,38 CFR 4.71a +5262,"Tibia and fibula, impairment of.",40,Musculoskeletal,The Knee and Leg,,38 CFR 4.71a +5263,"Genu recurvatum (acquired, traumatic, with weakness and insecurity in weight-bearing objectively demonstrated)",10,Musculoskeletal,The Knee and Leg,,38 CFR 4.71a +5269,Plantar fasciitis.,40,Musculoskeletal,The Foot,,38 CFR 4.71a +5270,"Ankle, ankylosis of.",40,Musculoskeletal,The Ankle,,38 CFR 4.71a +5271,"Ankle, limited motion of.",20,Musculoskeletal,The Ankle,,38 CFR 4.71a +5272,"Subastragalar or tarsal joint, ankylosis of.",20,Musculoskeletal,The Ankle,,38 CFR 4.71a +5273,"Os calcis or astragalus, malunion of.",20,Musculoskeletal,The Ankle,,38 CFR 4.71a +5274,Astragalectomy,20,Musculoskeletal,The Ankle,,38 CFR 4.71a +5275,"Bones, of the lower extremity, shortening of.",60,Musculoskeletal,Shortening of the Lower Extremity,,38 CFR 4.71a +5276,"Flatfoot, acquired.",50,Musculoskeletal,The Foot,,38 CFR 4.71a +5277,"Weak foot, bilateral.",100,Musculoskeletal,The Foot,,38 CFR 4.71a +5278,"Claw foot (pes cavus), acquired.",50,Musculoskeletal,The Foot,,38 CFR 4.71a +5279,"Metatarsalgia, anterior (Morton's disease), unilateral, or bilateral",10,Musculoskeletal,The Foot,,38 CFR 4.71a +5280,"Hallux valgus, unilateral.",10,Musculoskeletal,The Foot,,38 CFR 4.71a +5281,"Hallux rigidus, unilateral, severe.",10,Musculoskeletal,The Foot,,38 CFR 4.71a +5282,Hammer toe.,10,Musculoskeletal,The Foot,,38 CFR 4.71a +5283,"Tarsal, or metatarsal bones, malunion of, or nonunion of.",40,Musculoskeletal,The Foot,,38 CFR 4.71a +5284,"Foot injuries, other.",40,Musculoskeletal,The Foot,,38 CFR 4.71a +5296,"Skull, loss of part of, both inner and outer tables.",80,Musculoskeletal,The Skull,,38 CFR 4.71a +5297,"Ribs, removal of.",50,Musculoskeletal,The Ribs,,38 CFR 4.71a +5298,"Coccyx, removal of.",10,Musculoskeletal,The Coccyx,,38 CFR 4.71a +5301,Group I. Function: Upward rotation of scapula,40,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5302,Group II. Function: Depression of arm,40,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5303,Group III. Function: Elevation and abduction of arm,40,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5304,Group IV. Function: Stabilization of shoulder,30,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5305,Group V. Function: Elbow supination,40,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5306,Group VI. Function: Extension of elbow,40,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5307,Group VII. Function: Flexion of wrist and fingers.,40,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5308,"Group VIII. Function: Extension of wrist, fingers, and thumb",30,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5309,Group IX. Function: The forearm,50,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5310,Group X. Function: Movements of forefoot and toes,30,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5311,"Group XI. Function: Propulsion, plantar flexion of foot",30,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5312,Group XII. Function: Dorsiflexion,30,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5313,Group XIII. Function: Extension of hip and flexion of knee,40,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5314,Group XIV. Function: Extension of knee,40,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5315,Group XV. Function: Adduction of hip,30,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5316,Group XVI. Function: Flexion of hip,40,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5317,Group XVII. Function: Extension of hip,50,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5318,Group XVIII. Function: Outward rotation of thigh,30,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5319,Group XIX. Function: Support and compression of abdominal wall and lower thoraz,50,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5320,Group XX. Function: Postural support of body,60,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5321,Group XXI. Function: Respiration,20,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5322,Group XXII. Function: Rotary and forward movements of the head,30,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5323,Group XXIII. Function: Movements of the head,30,Musculoskeletal,Muscle Injuries,,38 CFR 4.71a +5324,"Diaphragm, rupture of, with herniation. Rate under diagnostic code 7346",60,Musculoskeletal,Miscellaneous,,38 CFR 4.71a +5325,"Muscle injury, facial muscles. Evaluate functional impairment as seventh (facial) cranial nerve neuropathy (diagnostic code 8207), disfiguring scar (diagnostic code 7800), etc. Minimum, if interfering to any extent with mastication—10",80,Musculoskeletal,Miscellaneous,,38 CFR 4.71a +5326,"Muscle hernia, extensive. ",10,Musculoskeletal,Miscellaneous,,38 CFR 4.71a +5327,"Muscle, neoplasm of, malignant (excluding soft tissue sarcoma)",100,Musculoskeletal,Miscellaneous,,38 CFR 4.71a +5328,"Muscle, neoplasm of, benign, postoperative. Rate on impairment of function, i.e., limitation of motion, or scars, diagnostic code 7805, etc",100,Musculoskeletal,Miscellaneous,,38 CFR 4.71a +5329,"Sarcoma, soft tissue (of muscle, fat, or fibrous connective tissue)",100,Musculoskeletal,Miscellaneous,,38 CFR 4.71a +5330,"Rhabdomyolysis, residuals of.",100,Musculoskeletal,Miscellaneous,,38 CFR 4.71a +5331,Compartment syndrome.,60,Musculoskeletal,Miscellaneous,,38 CFR 4.71a +6000,"Choroidopathy, including uveitis, iritis, cyclitis, or choroiditis.",100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6001,Keratopathy.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6002,Scleritis.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6006,Retinopathy or maculopathy not otherwise specified,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6007,Intraocular hemorrhage.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6008,Detachment of retina.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6009,Unhealed eye injury.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6010,Tuberculosis of eye.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6011,"Retinal scars, atrophy, or irregularities.",100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6012,Angle-closure glaucoma,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6013,Open-angle glaucoma,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6014,"Malignant neoplasms of the eye, orbit, and adnexa (excluding skin).",100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6015,"Benign neoplasms of the eye, orbit, and adnexa (excluding skin).",100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6016,"Nystagmus, central",10,The Organs of Special Sense,Eye,,38 CFR 4.79 +6017,Trachomatous conjunctivitis.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6018,Chronic conjunctivitis (nontrachomatous).,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6019,"Ptosis, unilateral or bilateral.",100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6020,Ectropion.,20,The Organs of Special Sense,Eye,,38 CFR 4.79 +6021,Entropion.,20,The Organs of Special Sense,Eye,,38 CFR 4.79 +6022,Lagophthalmos.,20,The Organs of Special Sense,Eye,,38 CFR 4.79 +6023,"Loss of eyebrows, complete, unilateral or bilateral",10,The Organs of Special Sense,Eye,,38 CFR 4.79 +6024,"Loss of eyelashes, complete, unilateral or bilateral",10,The Organs of Special Sense,Eye,,38 CFR 4.79 +6025,"Disorders of the lacrimal apparatus (epiphora, dacryocystitis, etc.).",20,The Organs of Special Sense,Eye,,38 CFR 4.79 +6026,Optic neuropathy,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6027,Cataract.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6029,Aphakia or dislocation of crystalline lens.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6030,Paralysis of accommodation (due to neuropathy of the Oculomotor Nerve (cranial nerve III)).,20,The Organs of Special Sense,Eye,,38 CFR 4.79 +6032,"Loss of eyelids, partial or complete.",100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6034,Pterygium.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6035,Keratoconus,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6036,Status post corneal transplant.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6037,Pinguecula.,90,The Organs of Special Sense,Eye,,38 CFR 4.79 +6040,Diabetic retinopathy,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6042,"Retinal dystrophy (including retinitis pigmentosa, wet or dry macular degeneration, early-onset macular degeneration, rod and/or cone dystrophy)",100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6046,Post-chiasmal disorders,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6061,Anatomical loss of both eyes,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6062,No more than light perception in both eyes,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6063,Anatomical loss of one eye.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6064,No more than light perception in one eye.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6065,Vision in one eye 5/200 (1.5/60),100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6066,Visual acuity in one eye 10/200 (3/60) or better.,90,The Organs of Special Sense,Eye,,38 CFR 4.79 +6080,Visual field defects.,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6081,"Scotoma, unilateral.",100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6090,Diplopia (double vision),100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6091,Symblepharon,100,The Organs of Special Sense,Eye,,38 CFR 4.79 +6200,"Chronic suppurative otitis media, mastoiditis, or cholesteatoma (or any combination).",10,The Organs of Special Sense,Ear,,38 CFR 4.87 +6201,Chronic nonsuppurative otitis media with effusion (serous otitis media).,100,The Organs of Special Sense,Ear,,38 CFR 4.87 +6202,Otosclerosis.,100,The Organs of Special Sense,Ear,,38 CFR 4.87 +6204,Peripheral vestibular disorders.,30,The Organs of Special Sense,Ear,,38 CFR 4.87 +6205,Meniere's syndrome (endolymphatic hydrops).,100,The Organs of Special Sense,Ear,,38 CFR 4.87 +6207,Loss of auricle.,50,The Organs of Special Sense,Ear,,38 CFR 4.87 +6208,Malignant neoplasm of the ear (other than skin only),100,The Organs of Special Sense,Ear,,38 CFR 4.87 +6209,Benign neoplasms of the ear (other than skin only).,100,The Organs of Special Sense,Ear,,38 CFR 4.87 +6210,Chronic otitis externa.,10,The Organs of Special Sense,Ear,,38 CFR 4.87 +6211,"Tympanic membrane, perforation of",0,The Organs of Special Sense,Ear,,38 CFR 4.87 +6260,"Tinnitus, recurrent",10,The Organs of Special Sense,Ear,,38 CFR 4.87 +6275,"Sense of smell, complete loss",10,The Organs of Special Sense,Other sense organs,,38 CFR 4.87a +6276,"Sense of taste, complete loss",10,The Organs of Special Sense,Other sense organs,,38 CFR 4.87a +6300,"Vibriosis (Cholera, Non-cholera).",100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6301,Visceral leishmaniasis.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6302,Leprosy (Hansen's disease).,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6304,Malaria.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6305,"Lymphatic filariasis, to include elephantiasis.",100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6306,Bartonellosis.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6307,Plague.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6308,Relapsing Fever.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6309,Rheumatic fever.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6310,"Syphilis, and other treponema infections.",100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6311,"Tuberculosis, miliary.",100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6312,Nontuberculosis mycobacterium infection.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6313,Avitaminosis.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6314,Beriberi.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6315,Pellagra.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6316,Brucellosis.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6317,"Rickettsial, ehrlichia, and anaplasma infections.",100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6318,Melioidosis.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6319,Lyme disease.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6320,Parasitic diseases otherwise not specified.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6325,Hyperinfection syndrome or disseminated strongyloidiasis.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6326,Schistosomiasis.,0,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6329,"Hemorrhagic fevers, including dengue, yellow fever, and others.",100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6330,Campylobacter jejuni infection.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6331,Coxiella burnetii infection (Q fever).,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6333,Nontyphoid salmonella infections.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6334,Shigella infections.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6335,West Nile virus infection.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6350,"Lupus erythematosus, systemic (disseminated).",100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6351,HIV-related illness.,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6354,Chronic fatigue syndrome (CFS).,100,"Infectious Diseases, Immune Disorders and Nutritional Deficiencies",,,38 CFR 4.88b +6502,"Septum, nasal, deviation of.",10,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6504,"Nose, loss of part of, or scars.",30,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6510,"Sinusitis, pansinusitis, chronic.",50,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6511,"Sinusitis, ethmoid, chronic.",50,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6512,"Sinusitis, frontal, chronic.",50,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6513,"Sinusitis, maxillary, chronic.",50,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6514,"Sinusitis, sphenoid, chronic.",50,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6515,"Laryngitis, tuberculous, active or inactive.",100,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6516,"Laryngitis, chronic.",30,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6518,"Laryngectomy, total.",100,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6519,"Aphonia, complete organic.",100,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6520,"Larynx, stenosis of, including residuals of laryngeal trauma (unilateral or bilateral).",100,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6521,"Pharynx, injuries to.",50,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6522,Allergic or vasomotor rhinitis.,30,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6523,Bacterial rhinitis.,50,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6524,Granulomatous rhinitis.,100,The respiratory system,DISEASES OF THE NOSE AND THROAT,,38 CFR 4.97 +6600,"Bronchitis, chronic.",100,The respiratory system,DISEASES OF THE TRACHEA AND BRONCHI,,38 CFR 4.97 +6601,Bronchiectasis.,100,The respiratory system,DISEASES OF THE TRACHEA AND BRONCHI,,38 CFR 4.97 +6602,"Asthma, bronchial.",100,The respiratory system,DISEASES OF THE TRACHEA AND BRONCHI,,38 CFR 4.97 +6603,"Emphysema, pulmonary.",100,The respiratory system,DISEASES OF THE TRACHEA AND BRONCHI,,38 CFR 4.97 +6604,Chronic obstructive pulmonary disease.,100,The respiratory system,DISEASES OF THE TRACHEA AND BRONCHI,,38 CFR 4.97 +6701,"Tuberculosis, pulmonary, chronic, far advanced, active",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6702,"Tuberculosis, pulmonary, chronic, moderately advanced, active",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6703,"Tuberculosis, pulmonary, chronic, minimal, active",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6704,"Tuberculosis, pulmonary, chronic, active, advancement unspecified",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6721,"Tuberculosis, pulmonary, chronic, far advanced, inactive",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6722,"Tuberculosis, pulmonary, chronic, moderately advanced, inactive",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6723,"Tuberculosis, pulmonary, chronic, minimal, inactive",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6724,"Tuberculosis, pulmonary, chronic, inactive, advancement unspecified",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6730,"Tuberculosis, pulmonary, chronic, active",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6731,"Tuberculosis, pulmonary, chronic, inactive.",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6732,"Pleurisy, tuberculous, active or inactive.",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6817,Pulmonary Vascular Disease.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6819,"Neoplasms, malignant, any specified part of respiratory system exclusive of skin growths",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6820,"Neoplasms, benign, any specified part of respiratory system. Evaluate using an appropriate respiratory analogy.",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6822,Actinomycosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6823,Nocardiosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6824,Chronic lung abscess.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6825,"Diffuse interstitial fibrosis (interstitial pneumonitis, fibrosing alveolitis).",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6826,Desquamative interstitial pneumonitis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6827,Pulmonary alveolar proteinosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6828,Eosinophilic granuloma of lung.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6829,Drug-induced pulmonary pneumonitis and fibrosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6830,Radiation-induced pulmonary pneumonitis and fibrosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6831,Hypersensitivity pneumonitis (extrinsic allergic alveolitis).,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6832,"Pneumoconiosis (silicosis, anthracosis, etc.).",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6833,Asbestosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6834,Histoplasmosis of lung.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6835,Coccidioidomycosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6836,Blastomycosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6837,Cryptococcosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6838,Aspergillosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6839,Mucormycosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6840,Diaphragm paralysis or paresis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6841,Spinal cord injury with respiratory insufficiency.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6842,"Kyphoscoliosis, pectus excavatum, pectus carinatum.",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6843,"Traumatic chest wall defect, pneumothorax, hernia, etc.",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6844,"Post-surgical residual (lobectomy, pneumonectomy, etc.).",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6845,Chronic pleural effusion or fibrosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6846,Sarcoidosis.,100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +6847,"Sleep Apnea Syndromes (Obstructive, Central, Mixed).",100,The respiratory system,DISEASES OF THE LUNGS AND PLEURA—TUBERCULOSIS,,38 CFR 4.97 +7000,"Valvular heart disease (including rheumatic heart disease),",100,The Cardiovascular System,,,38 CFR 4.104 +7001,"Endocarditis, or",100,The Cardiovascular System,,,38 CFR 4.104 +7002,Pericarditis.,100,The Cardiovascular System,,,38 CFR 4.104 +7003,Pericardial adhesions.,100,The Cardiovascular System,,,38 CFR 4.104 +7004,Syphilitic heart disease.,100,The Cardiovascular System,,,38 CFR 4.104 +7005,Arteriosclerotic heart disease (coronary artery disease).,100,The Cardiovascular System,,,38 CFR 4.104 +7006,Myocardial infarction.,100,The Cardiovascular System,,,38 CFR 4.104 +7007,Hypertensive heart disease.,100,The Cardiovascular System,,,38 CFR 4.104 +7008,Hyperthyroid heart disease.,100,The Cardiovascular System,,,38 CFR 4.104 +7009,"Bradycardia (Bradyarrhythmia), symptomatic, requiring permanent pacemaker implantation.",100,The Cardiovascular System,,,38 CFR 4.104 +7010,Supraventricular tachycardia.,30,The Cardiovascular System,,,38 CFR 4.104 +7011,Ventricular arrhythmias (sustained).,100,The Cardiovascular System,,,38 CFR 4.104 +7015,Atrioventricular block.,100,The Cardiovascular System,,,38 CFR 4.104 +7016,Heart valve replacement (prosthesis).,100,The Cardiovascular System,,,38 CFR 4.104 +7017,Coronary bypass surgery.,100,The Cardiovascular System,,,38 CFR 4.104 +7018,Implantable cardiac pacemakers.,100,The Cardiovascular System,,,38 CFR 4.104 +7019,Cardiac transplantation.,100,The Cardiovascular System,,,38 CFR 4.104 +7020,Cardiomyopathy.,100,The Cardiovascular System,,,38 CFR 4.104 +7101,Hypertensive vascular disease (hypertension and isolated systolic hypertension).,60,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7110,"Aortic aneurysm. Ascending, thoracic, or abdominal.",100,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7111,"Aneurysm, any large artery.",100,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7112,"Aneurysm, any small artery.",100,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7113,"Arteriovenous fistula, traumatic.",100,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7114,Peripheral arterial disease.,100,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7115,Thrombo-angiitis obliterans (Buerger's Disease).,100,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7117,Raynaud's syndrome (also known as secondary Raynaud's phenomenon or secondary Raynaud's).,100,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7118,Angioneurotic edema.,40,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7119,Erythromelalgia.,100,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7120,Varicose veins.,100,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7121,Post-phlebitic syndrome of any etiology.,100,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7122,Cold injury residuals.,30,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7123,Soft tissue sarcoma (of vascular origin),100,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7124,Raynaud's disease (also known as primary Raynaud's).,10,The Cardiovascular System,Diseases of the Arteries and Veins,,38 CFR 4.104 +7200,"Mouth, injuries of.",90,The Digestive System,,,38 CFR 4.114 +7201,"Lips, injuries of.",90,The Digestive System,,,38 CFR 4.114 +7202,"Tongue, loss of whole or part.",100,The Digestive System,,,38 CFR 4.114 +7203,"Esophagus, stricture of.",80,The Digestive System,,,38 CFR 4.114 +7204,"Esophagus, spasm of (cardiospasm).",80,The Digestive System,,,38 CFR 4.114 +7205,"Esophagus, diverticulum of, acquired.",80,The Digestive System,,,38 CFR 4.114 +7301,"Peritoneum, adhesions of.",50,The Digestive System,,,38 CFR 4.114 +7304,"Ulcer, gastric.",100,The Digestive System,,,38 CFR 4.114 +7305,"Ulcer, duodenal.",60,The Digestive System,,,38 CFR 4.114 +7306,"Ulcer, marginal (gastrojejunal).",100,The Digestive System,,,38 CFR 4.114 +7307,"Gastritis, hypertrophic (identified by gastroscope).",60,The Digestive System,,,38 CFR 4.114 +7308,Postgastrectomy syndromes.,60,The Digestive System,,,38 CFR 4.114 +7309,"Stomach, stenosis of.",80,The Digestive System,,,38 CFR 4.114 +7310,"Stomach, injury of, residuals.",50,The Digestive System,,,38 CFR 4.114 +7311,Residuals of injury of the liver.,100,The Digestive System,,,38 CFR 4.114 +7312,"Cirrhosis of the liver, primary biliary cirrhosis, or cirrhotic phase of sclerosing cholangitis.",100,The Digestive System,,,38 CFR 4.114 +7314,"Cholecystitis, chronic.",30,The Digestive System,,,38 CFR 4.114 +7315,"Cholelithiasis, chronic.",30,The Digestive System,,,38 CFR 4.114 +7316,"Cholangitis, chronic.",30,The Digestive System,,,38 CFR 4.114 +7317,"Gall bladder, injury of.",50,The Digestive System,,,38 CFR 4.114 +7318,"Gall bladder, removal of.",30,The Digestive System,,,38 CFR 4.114 +7319,"Irritable colon syndrome (spastic colitis, mucous colitis, etc.).",30,The Digestive System,,,38 CFR 4.114 +7321,Amebiasis.,100,The Digestive System,,,38 CFR 4.114 +7322,"Dysentery, bacillary.",100,The Digestive System,,,38 CFR 4.114 +7323,"Colitis, ulcerative.",100,The Digestive System,,,38 CFR 4.114 +7324,"Distomiasis, intestinal or hepatic.",30,The Digestive System,,,38 CFR 4.114 +7325,"Enteritis, chronic.",30,The Digestive System,,,38 CFR 4.114 +7326,"Enterocolitis, chronic.",30,The Digestive System,,,38 CFR 4.114 +7327,Diverticulitis.,100,The Digestive System,,,38 CFR 4.114 +7328,"Intestine, small, resection of.",60,The Digestive System,,,38 CFR 4.114 +7329,"Intestine, large, resection of.",40,The Digestive System,,,38 CFR 4.114 +7330,"Intestine, fistula of, persistent, or after attempt at operative closure.",100,The Digestive System,,,38 CFR 4.114 +7331,"Peritonitis, tuberculous, active or inactive.",100,The Digestive System,,,38 CFR 4.114 +7332,"Rectum and anus, impairment of sphincter control.",100,The Digestive System,,,38 CFR 4.114 +7333,"Rectum and anus, stricture of.",100,The Digestive System,,,38 CFR 4.114 +7334,"Rectum, prolapse of.",50,The Digestive System,,,38 CFR 4.114 +7335,"Ano, fistula in.",100,The Digestive System,,,38 CFR 4.114 +7336,"Hemorrhoids, external or internal.",20,The Digestive System,,,38 CFR 4.114 +7337,Pruritus ani.,0,The Digestive System,,,38 CFR 4.114 +7338,"Hernia, inguinal.",70,The Digestive System,,,38 CFR 4.114 +7339,"Hernia, ventral, postoperative.",100,The Digestive System,,,38 CFR 4.114 +7340,"Hernia, femoral.",70,The Digestive System,,,38 CFR 4.114 +7342,"Visceroptosis, symptomatic, marked",10,The Digestive System,,,38 CFR 4.114 +7343,"Malignant neoplasms of the digestive system, exclusive of skin growths",100,The Digestive System,,,38 CFR 4.114 +7344,"Benign neoplasms, exclusive of skin growths.",0,The Digestive System,,,38 CFR 4.114 +7345,"Chronic liver disease without cirrhosis (including hepatitis B, chronic active hepatitis, autoimmune hepatitis, hemochromatosis, drug-induced hepatitis, etc., but excluding bile duct disorders and hepatitis C).",100,The Digestive System,,,38 CFR 4.114 +7346,Hernia hiatal.,60,The Digestive System,,,38 CFR 4.114 +7347,Pancreatitis.,100,The Digestive System,,,38 CFR 4.114 +7348,Vagotomy with pyloroplasty or gastroenterostomy.,40,The Digestive System,,,38 CFR 4.114 +7351,Liver transplant.,100,The Digestive System,,,38 CFR 4.114 +7354,"Hepatitis C (or non-A, non-B hepatitis).",100,The Digestive System,,,38 CFR 4.114 +7500,"Kidney, removal of one.",100,The Genitourinary System,,,38 CFR 4.115b +7501,"Kidney, abscess of.",30,The Genitourinary System,,,38 CFR 4.115b +7502,"Nephritis, chronic.",100,The Genitourinary System,,,38 CFR 4.115b +7504,"Pyelonephritis, chronic.",100,The Genitourinary System,,,38 CFR 4.115b +7505,"Kidney, tuberculosis of.",100,The Genitourinary System,,,38 CFR 4.115b +7507,"Nephrosclerosis, arteriolar.",100,The Genitourinary System,,,38 CFR 4.115b +7508,Nephrolithiasis/Ureterolithiasis/Nephrocalcinosis.,100,The Genitourinary System,,,38 CFR 4.115b +7509,Hydronephrosis.,100,The Genitourinary System,,,38 CFR 4.115b +7511,"Ureter, stricture of.",100,The Genitourinary System,,,38 CFR 4.115b +7512,"Cystitis, chronic, includes interstitial and all etiologies, infectious and non-infectious.",60,The Genitourinary System,,,38 CFR 4.115b +7515,"Bladder, calculus in, with symptoms interfering with function.",60,The Genitourinary System,,,38 CFR 4.115b +7516,"Bladder, fistula of.",100,The Genitourinary System,,,38 CFR 4.115b +7517,"Bladder, injury of.",60,The Genitourinary System,,,38 CFR 4.115b +7518,"Urethra, stricture of.",60,The Genitourinary System,,,38 CFR 4.115b +7519,"Urethra, fistula of.",100,The Genitourinary System,,,38 CFR 4.115b +7520,"Penis, removal of half or more",30,The Genitourinary System,,,38 CFR 4.115b +7521,"Penis, removal of glans",20,The Genitourinary System,,,38 CFR 4.115b +7522,"Erectile dysfunction, with or without penile deformity",0,The Genitourinary System,,,38 CFR 4.115b +7523,"Testis, atrophy complete.",20,The Genitourinary System,,,38 CFR 4.115b +7524,"Testis, removal.",30,The Genitourinary System,,,38 CFR 4.115b +7525,"Prostatitis, urethritis, epididymitis, orchitis (unilateral or bilateral), chronic only.",100,The Genitourinary System,,,38 CFR 4.115b +7527,"Prostate gland injuries, infections, hypertrophy, postoperative residuals, bladder outlet obstruction.",60,The Genitourinary System,,,38 CFR 4.115b +7528,Malignant neoplasms of the genitourinary system,100,The Genitourinary System,,,38 CFR 4.115b +7529,Benign neoplasms of the genitourinary system.,100,The Genitourinary System,,,38 CFR 4.115b +7530,Chronic renal disease requiring regular dialysis.,100,The Genitourinary System,,,38 CFR 4.115b +7531,Kidney transplant.,100,The Genitourinary System,,,38 CFR 4.115b +7532,"Renal tubular disorders (such as renal glycosurias, aminoacidurias, renal tubular acidosis, Fanconi's syndrome, Bartter's syndrome, related disorders of Henle's loop and proximal or distal nephron function, etc.).",100,The Genitourinary System,,,38 CFR 4.115b +7533,Cystic diseases of the kidneys.,100,The Genitourinary System,,,38 CFR 4.115b +7534,"Atherosclerotic renal disease (renal artery stenosis, atheroembolic renal disease, or large vessel disease, unspecified).",100,The Genitourinary System,,,38 CFR 4.115b +7535,"Toxic nephropathy (antibotics, radiocontrast agents, nonsteroidal anti-inflammatory agents, heavy metals, and similar agents).",100,The Genitourinary System,,,38 CFR 4.115b +7536,Glomerulonephritis.,100,The Genitourinary System,,,38 CFR 4.115b +7537,"Interstitial nephritis, including gouty nephropathy, disorders of calcium metabolism.",100,The Genitourinary System,,,38 CFR 4.115b +7538,Papillary necrosis.,100,The Genitourinary System,,,38 CFR 4.115b +7539,Renal amyloid disease.,100,The Genitourinary System,,,38 CFR 4.115b +7540,Disseminated intravascular coagulation with renal cortical necrosis.,100,The Genitourinary System,,,38 CFR 4.115b +7541,Renal involvement in diabetes mellitus type I or II.,100,The Genitourinary System,,,38 CFR 4.115b +7542,Neurogenic bladder.,60,The Genitourinary System,,,38 CFR 4.115b +7543,Varicocele/Hydrocele,0,The Genitourinary System,,,38 CFR 4.115b +7544,"Renal disease caused by viral infection such as human immunodeficiency virus (HIV), Hepatitis B, and Hepatitis C.",100,The Genitourinary System,,,38 CFR 4.115b +7545,"Bladder, diverticulum of.",60,The Genitourinary System,,,38 CFR 4.115b +7610,"Vulva or clitoris, disease or injury of (including vulvovaginitis)",30,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7611,"Vagina, disease or injury of.",30,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7612,"Cervix, disease or injury of.",30,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7613,"Uterus, disease, injury, or adhesions of.",30,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7614,"Fallopian tube, disease, injury, or adhesions of (including pelvic inflammatory disease (PID)).",30,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7615,"Ovary, disease, injury, or adhesions of.",30,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7617,"Uterus and both ovaries, removal of, complete.",100,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7618,"Uterus, removal of, including corpus.",100,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7619,"Ovary, removal of.",100,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7620,"Ovaries, atrophy of both, complete",20,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7621,"Complete or incomplete pelvic organ prolapse due to injury, disease, or surgical complications of pregnancy",10,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7624,"Fistula, rectovaginal.",100,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7625,"Fistula, urethrovaginal.",100,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7626,"Breast, surgery of.",80,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7627,Malignant neoplasms of gynecological system,100,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7628,Benign neoplasms of gynecological system.,,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7629,Endometriosis.,50,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7630,Malignant neoplasms of the breast,100,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7631,Benign neoplasms of the breast and other injuries of the breast. ,,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7632,Female sexual arousal disorder (FSAD),0,Gynecological Conditions and Disorders of the Breast,,,38 CFR 4.116 +7702,"Agranulocytosis, acquired.",100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7703,Leukemia (except for chronic myelogenous leukemia).,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7704,Polycythemia vera.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7705,Immune thrombocytopenia.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7706,Splenectomy,20,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7707,"Spleen, injury of, healed.",0,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7709,Hodgkin's lymphoma.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7710,"Adenitis, tuberculous, active or inactive.",100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7712,Multiple myeloma.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7714,Sickle cell anemia.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7715,Non-Hodgkin's lymphoma.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7716,Aplastic anemia.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7717,AL amyloidosis (primary amyloidosis),100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7718,Essential thrombocythemia and primary myelofibrosis.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7719,Chronic myelogenous leukemia (CML) (chronic myeloid leukemia or chronic granulocytic leukemia).,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7720,Iron deficiency anemia.,30,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7721,Folic acid deficiency.,10,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7722,Pernicious anemia and Vitamin B12 deficiency anemia.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7723,Acquired hemolytic anemia.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7724,Solitary plasmacytoma.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7725,Myelodysplastic syndromes.,100,The Hematologic and Lymphatic Systems,,,38 CFR 4.117 +7800,"Burn scar(s) of the head, face, or neck; scar(s) of the head, face, or neck due to other causes; or other disfigurement of the head, face, or neck.",80,The Skin,,,38 CFR 4.118 +7801,"Burn scar(s) or scar(s) due to other causes, not of the head, face, or neck, that are associated with underlying soft tissue damage.",40,The Skin,,,38 CFR 4.118 +7802,"Burn scar(s) or scar(s) due to other causes, not of the head, face, or neck, that are not associated with underlying soft tissue damage.",10,The Skin,,,38 CFR 4.118 +7804,"Scar(s), unstable or painful.",40,The Skin,,,38 CFR 4.118 +7805,"Scars, other; and other effects of scars evaluated under diagnostic codes 7800, 7801, 7802, or 7804.",,The Skin,,,38 CFR 4.118 +7806,Dermatitis or eczema.,60,The Skin,,,38 CFR 4.118 +7807,"American (New World) leishmaniasis (mucocutaneous, espundia).",,The Skin,,,38 CFR 4.118 +7808,"Old World leishmaniasis (cutaneous, Oriental sore).",,The Skin,,,38 CFR 4.118 +7809,Discoid lupus erythematosus.,60,The Skin,,,38 CFR 4.118 +7811,"Tuberculosis luposa (lupus vulgaris), active or inactive.",100,The Skin,,,38 CFR 4.118 +7813,"Dermatophytosis (ringworm: Of body, tinea corporis; of head, tinea capitis; of feet, tinea pedis; of beard area, tinea barbae; of nails, tinea unguium (onychomycosis); of inguinal area (jock itch), tinea cruris; tinea versicolor).",60,The Skin,,,38 CFR 4.118 +7815,"Bullous disorders (including pemphigus vulgaris, pemphigus foliaceous, bullous pemphigoid, dermatitis herpetiformis, epidermolysis bullosa acquisita, benign chronic familial pemphigus (Hailey-Hailey), and porphyria cutanea tarda).",60,The Skin,,,38 CFR 4.118 +7816,Psoriasis.,60,The Skin,,,38 CFR 4.118 +7817,Erythroderma.,100,The Skin,,,38 CFR 4.118 +7818,Malignant skin neoplasms (other than malignant melanoma).,100,The Skin,,,38 CFR 4.118 +7819,Benign skin neoplasms.,,The Skin,,,38 CFR 4.118 +7820,"Infections of the skin not listed elsewhere (including bacterial, fungal, viral, treponemal, and parasitic diseases).",60,The Skin,,,38 CFR 4.118 +7821,"Cutaneous manifestations of collagen-vascular diseases not listed elsewhere (including scleroderma, calcinosis cutis, subacute cutaneous lupus erythematosus, and dermatomyositis).",60,The Skin,,,38 CFR 4.118 +7822,"Papulosquamous disorders not listed elsewhere (including lichen planus, large or small plaque parapsoriasis, pityriasis lichenoides et varioliformis acuta (PLEVA), lymphomatoid papulosus, mycosis fungoides, and pityriasis rubra pilaris (PRP)).",60,The Skin,,,38 CFR 4.118 +7823,Vitiligo.,10,The Skin,,,38 CFR 4.118 +7824,"Diseases of keratinization (including icthyoses, Darier's disease, and palmoplantar keratoderma).",60,The Skin,,,38 CFR 4.118 +7825,Chronic urticaria.,60,The Skin,,,38 CFR 4.118 +7826,"Vasculitis, primary cutaneous.",60,The Skin,,,38 CFR 4.118 +7827,Erythema multiforme; Toxic epidermal necrolysis.,60,The Skin,,,38 CFR 4.118 +7828,Acne.,30,The Skin,,,38 CFR 4.118 +7829,Chloracne.,30,The Skin,,,38 CFR 4.118 +7830,Scarring alopecia.,20,The Skin,,,38 CFR 4.118 +7831,Alopecia areata:,10,The Skin,,,38 CFR 4.118 +7832,Hyperhidrosis.,30,The Skin,,,38 CFR 4.118 +7833,Malignant melanoma.,100,The Skin,,,38 CFR 4.118 +7900,"Hyperthyroidism, including, but not limited to, Graves' disease.",30,The Endocrine System,,,38 CFR 4.119 +7901,"Thyroid enlargement, toxic.",80,The Endocrine System,,,38 CFR 4.119 +7902,"Thyroid enlargement, nontoxic.",100,The Endocrine System,,,38 CFR 4.119 +7903,Hypothyroidism.,100,The Endocrine System,,,38 CFR 4.119 +7904,Hyperparathyroidism.,100,The Endocrine System,,,38 CFR 4.119 +7905,Hypoparathyroidism.,100,The Endocrine System,,,38 CFR 4.119 +7906,Thyroiditis.,100,The Endocrine System,,,38 CFR 4.119 +7907,Cushing's syndrome.,100,The Endocrine System,,,38 CFR 4.119 +7908,Acromegaly.,100,The Endocrine System,,,38 CFR 4.119 +7909,Diabetes insipidus.,30,The Endocrine System,,,38 CFR 4.119 +7911,Addison's disease (adrenocortical insufficiency).,60,The Endocrine System,,,38 CFR 4.119 +7912,"Polyglandular syndrome (multiple endocrine neoplasia, autoimmune polyglandular syndrome).",100,The Endocrine System,,,38 CFR 4.119 +7913,Diabetes mellitus.,100,The Endocrine System,,,38 CFR 4.119 +7914,"Neoplasm, malignant, any specified part of the endocrine system",100,The Endocrine System,,,38 CFR 4.119 +7915,"Neoplasm, benign, any specified part of the endocrine system.",100,The Endocrine System,,,38 CFR 4.119 +7916,Hyperpituitarism (prolactin secreting pituitary dysfunction).,100,The Endocrine System,,,38 CFR 4.119 +7917,Hyperaldosteronism (benign or malignant).,100,The Endocrine System,,,38 CFR 4.119 +7918,Pheochromocytoma (benign or malignant).,100,The Endocrine System,,,38 CFR 4.119 +7919,C-cell hyperplasia of the thyroid.,100,The Endocrine System,,,38 CFR 4.119 +8000,"Encephalitis, epidemic, chronic.",100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8002,Malignant new growth of the brain,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,"Brain, new growth of:",38 CFR 4.124a +8003,"Benign, minimum new growth of the brain",100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,"Brain, new growth of:",38 CFR 4.124a +8004,Paralysis agitans.,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8005,Bulbar palsy,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8007,"Brain, vessels, embolism of.",100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8008,"Brain, vessels, thrombosis of.",100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8009,"Brain, vessels, hemorrhage from.",100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8010,Myelitis.,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8011,"Poliomyelitis, anterior.",100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8012,Hematomyelia.,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8013,"Syphilis, cerebrospinal.",100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8014,"Syphilis, meningovascular.",100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8015,Tabes dorsalis.,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8017,Amyotrophic lateral sclerosis,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8018,Multiple sclerosis.,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8019,"Meningitis, cerebrospinal, epidemic.",100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8020,"Brain, abscess of.",100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8021,Malignant new growths of the spinal cord,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,"Spinal cord, new growths of:",38 CFR 4.124a +8022,"Benign new growths of the spinal cord, minimum rating",100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,"Spinal cord, new growths of:",38 CFR 4.124a +8023,Progressive muscular atrophy.,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8024,Syringomyelia.,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8025,Myasthenia gravis.,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8045,Residuals of traumatic brain injury (TBI),100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8046,Cerebral arteriosclerosis.,100,Neurological Conditions and Convulsive Disorders,Organic Diseases of the Central Nervous System,,38 CFR 4.124a +8100,Migraine.,50,Neurological Conditions and Convulsive Disorders,Miscellaneous Diseases,,38 CFR 4.124a +8103,"Tic, convulsive.",30,Neurological Conditions and Convulsive Disorders,Miscellaneous Diseases,,38 CFR 4.124a +8104,"Paramyoclonus multiplex (convulsive state, myoclonic type).",60,Neurological Conditions and Convulsive Disorders,Miscellaneous Diseases,,38 CFR 4.124a +8105,"Chorea, Sydenham's.",100,Neurological Conditions and Convulsive Disorders,Miscellaneous Diseases,,38 CFR 4.124a +8106,"Chorea, Huntington's.",100,Neurological Conditions and Convulsive Disorders,Miscellaneous Diseases,,38 CFR 4.124a +8107,"Athetosis, acquired.",100,Neurological Conditions and Convulsive Disorders,Miscellaneous Diseases,,38 CFR 4.124a +8108,Narcolepsy.,100,Neurological Conditions and Convulsive Disorders,Miscellaneous Diseases,,38 CFR 4.124a +8205,Paralysis of,50,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Fifth (trigeminal) cranial nerve,38 CFR 4.124a +8207,Paralysis of,30,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Seventh (facial) cranial nerve,38 CFR 4.124a +8209,Paralysis of.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Ninth (glossopharyngeal) cranial nerve,38 CFR 4.124a +8210,Paralysis of.,50,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,"Tenth (pneumogastric, vagus) cranial nerve",38 CFR 4.124a +8211,Paralysis of.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,"Eleventh (spinal accessory, external branch) cranial nerve.",38 CFR 4.124a +8212,Paralysis of.,50,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Twelfth (hypoglossal) cranial nerve.,38 CFR 4.124a +8305,Neuritis.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Fifth (trigeminal) cranial nerve,38 CFR 4.124a +8307,Neuritis.,20,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Seventh (facial) cranial nerve,38 CFR 4.124a +8309,Neuritis.,20,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Ninth (glossopharyngeal) cranial nerve,38 CFR 4.124a +8310,Neuritis.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,"Tenth (pneumogastric, vagus) cranial nerve",38 CFR 4.124a +8311,Neuritis.,20,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,"Eleventh (spinal accessory, external branch) cranial nerve.",38 CFR 4.124a +8312,Neuritis.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Twelfth (hypoglossal) cranial nerve.,38 CFR 4.124a +8405,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Fifth (trigeminal) cranial nerve,38 CFR 4.124a +8407,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Seventh (facial) cranial nerve,38 CFR 4.124a +8409,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Ninth (glossopharyngeal) cranial nerve,38 CFR 4.124a +8410,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,"Tenth (pneumogastric, vagus) cranial nerve",38 CFR 4.124a +8411,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,"Eleventh (spinal accessory, external branch) cranial nerve.",38 CFR 4.124a +8412,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Cranial Nerves,Twelfth (hypoglossal) cranial nerve.,38 CFR 4.124a +8510,Paralysis of.,70,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Upper radicular group (fifth and sixth cervicals),38 CFR 4.124a +8511,Paralysis of.,70,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Middle radicular group,38 CFR 4.124a +8512,Paralysis of.,70,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Lower radicular group,38 CFR 4.124a +8513,Paralysis of.,90,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,All radicular groups,38 CFR 4.124a +8514,Paralysis of.,70,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,The musculospiral nerve (radial nerve),38 CFR 4.124a +8515,Paralysis of.,70,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,The median nerve,38 CFR 4.124a +8516,Paralysis of.,60,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,The ulnar nerve,38 CFR 4.124a +8517,Paralysis of.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Musculocutaneous nerve,38 CFR 4.124a +8518,Paralysis of.,50,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Circumflex nerve,38 CFR 4.124a +8519,Paralysis of.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Long thoracic nerve,38 CFR 4.124a +8520,Paralysis of.,80,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Sciatic nerve,38 CFR 4.124a +8521,Paralysis of.,40,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,External popliteal nerve (common peroneal),38 CFR 4.124a +8522,Paralysis of.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Musculocutaneous nerve (superficial peroneal),38 CFR 4.124a +8523,Paralysis of.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Anterior tibial nerve (deep peroneal),38 CFR 4.124a +8524,Paralysis of.,40,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Internal popliteal nerve (tibial),38 CFR 4.124a +8525,Paralysis of.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Posterior tibial nerve,38 CFR 4.124a +8526,Paralysis of.,40,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Anterior crural nerve (femoral),38 CFR 4.124a +8527,Paralysis of.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Internal saphenous nerve,38 CFR 4.124a +8528,Paralysis of.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Obturator nerve,38 CFR 4.124a +8529,Paralysis of.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,External cutaneous nerve of thigh,38 CFR 4.124a +8530,Paralysis of.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Ilio-inguinal nerve,38 CFR 4.124a +8540,Soft-tissue sarcoma (of neurogenic origin),100,Neurological Conditions and Convulsive Disorders,,Ilio-inguinal nerve,38 CFR 4.124a +8610,Neuritis.,50,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Upper radicular group (fifth and sixth cervicals),38 CFR 4.124a +8611,Neuritis.,50,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Middle radicular group,38 CFR 4.124a +8612,Neuritis.,50,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Lower radicular group,38 CFR 4.124a +8613,Neuritis.,70,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,All radicular groups,38 CFR 4.124a +8614,Neuritis.,50,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,The musculospiral nerve (radial nerve),38 CFR 4.124a +8615,Neuritis.,50,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,The median nerve,38 CFR 4.124a +8616,Neuritis.,40,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,The ulnar nerve,38 CFR 4.124a +8617,Neuritis.,20,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Musculocutaneous nerve,38 CFR 4.124a +8618,Neuritis.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Circumflex nerve,38 CFR 4.124a +8619,Neuritis.,20,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Long thoracic nerve,38 CFR 4.124a +8620,Neuritis.,60,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Sciatic nerve,38 CFR 4.124a +8621,Neuritis.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,External popliteal nerve (common peroneal),38 CFR 4.124a +8622,Neuritis.,20,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Musculocutaneous nerve (superficial peroneal),38 CFR 4.124a +8623,Neuritis.,20,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Anterior tibial nerve (deep peroneal),38 CFR 4.124a +8624,Neuritis.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Internal popliteal nerve (tibial),38 CFR 4.124a +8625,Neuritis.,20,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Posterior tibial nerve,38 CFR 4.124a +8626,Neuritis.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Anterior crural nerve (femoral),38 CFR 4.124a +8627,Neuritis.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Internal saphenous nerve,38 CFR 4.124a +8628,Neuritis.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Obturator nerve,38 CFR 4.124a +8629,Neuritis.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,External cutaneous nerve of thigh,38 CFR 4.124a +8630,Neuritis.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Ilio-inguinal nerve,38 CFR 4.124a +8710,Neuralgia.,40,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Upper radicular group (fifth and sixth cervicals),38 CFR 4.124a +8711,Neuralgia.,40,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Middle radicular group,38 CFR 4.124a +8712,Neuralgia.,40,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Lower radicular group,38 CFR 4.124a +8713,Neuralgia.,40,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,All radicular groups,38 CFR 4.124a +8714,Neuralgia.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,The musculospiral nerve (radial nerve),38 CFR 4.124a +8715,Neuralgia.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,The median nerve,38 CFR 4.124a +8716,Neuralgia.,30,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,The ulnar nerve,38 CFR 4.124a +8717,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Musculocutaneous nerve,38 CFR 4.124a +8718,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Circumflex nerve,38 CFR 4.124a +8719,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Long thoracic nerve,38 CFR 4.124a +8720,Neuralgia.,40,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Sciatic nerve,38 CFR 4.124a +8721,Neuralgia.,20,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,External popliteal nerve (common peroneal),38 CFR 4.124a +8722,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Musculocutaneous nerve (superficial peroneal),38 CFR 4.124a +8723,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Anterior tibial nerve (deep peroneal),38 CFR 4.124a +8724,Neuralgia.,20,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Internal popliteal nerve (tibial),38 CFR 4.124a +8725,Neuralgia.,10,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Posterior tibial nerve,38 CFR 4.124a +8726,Neuralgia.,20,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Anterior crural nerve (femoral),38 CFR 4.124a +8727,Neuralgia.,0,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Internal saphenous nerve,38 CFR 4.124a +8728,Neuralgia.,0,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Obturator nerve,38 CFR 4.124a +8729,Neuralgia.,0,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,External cutaneous nerve of thigh,38 CFR 4.124a +8730,Neuralgia.,0,Neurological Conditions and Convulsive Disorders,Diseases of the Peripheral Nerves,Ilio-inguinal nerve,38 CFR 4.124a +8910,"Epilepsy, grand mal.",100,Neurological Conditions and Convulsive Disorders,The Epilepsies,,38 CFR 4.124a +8911,"Epilepsy, petit mal.",80,Neurological Conditions and Convulsive Disorders,The Epilepsies,,38 CFR 4.124a +8912,"Epilepsy, Jacksonian and focal motor or sensory.",100,Neurological Conditions and Convulsive Disorders,The Epilepsies,,38 CFR 4.124a +8913,"Epilepsy, diencephalic.",100,Neurological Conditions and Convulsive Disorders,The Epilepsies,,38 CFR 4.124a +8914,"Epilepsy, psychomotor.",100,Neurological Conditions and Convulsive Disorders,The Epilepsies,,38 CFR 4.124a +9201,Schizophrenia,100,Mental Disorders,,,38 CFR 4.130 +9202,[Removed],,Mental Disorders,,,38 CFR 4.130 +9203,[Removed],,Mental Disorders,,,38 CFR 4.130 +9204,[Removed],,Mental Disorders,,,38 CFR 4.130 +9205,[Removed],,Mental Disorders,,,38 CFR 4.130 +9208,Delusional disorder,100,Mental Disorders,,,38 CFR 4.130 +9210,Other specified and unspecified schizophrenia spectrum and other psychotic disorders,100,Mental Disorders,,,38 CFR 4.130 +9211,Schizoaffective disorder,100,Mental Disorders,,,38 CFR 4.130 +9300,Delirium,100,Mental Disorders,,,38 CFR 4.130 +9301,Major or mild neurocognitive disorder due to HIV or other infections,100,Mental Disorders,,,38 CFR 4.130 +9304,Major or mild neurocognitive disorder due to traumatic brain injury,100,Mental Disorders,,,38 CFR 4.130 +9305,Major or mild vascular neurocognitive disorder,100,Mental Disorders,,,38 CFR 4.130 +9310,Unspecified neurocognitive disorder,100,Mental Disorders,,,38 CFR 4.130 +9312,Major or mild neurocognitive disorder due to Alzheimer's disease,100,Mental Disorders,,,38 CFR 4.130 +9326,Major or mild neurocognitive disorder due to another medical condition or substance/medication-induced major or mild neurocognitive disorder,100,Mental Disorders,,,38 CFR 4.130 +9327,[Removed],,Mental Disorders,,,38 CFR 4.130 +9400,Generalized anxiety disorder,100,Mental Disorders,,,38 CFR 4.130 +9403,Specific phobia; social anxiety disorder (social phobia),100,Mental Disorders,,,38 CFR 4.130 +9404,Obsessive compulsive disorder,100,Mental Disorders,,,38 CFR 4.130 +9410,Other specified anxiety disorder,100,Mental Disorders,,,38 CFR 4.130 +9411,Posttraumatic stress disorder,100,Mental Disorders,,,38 CFR 4.130 +9412,Panic disorder and/or agoraphobia,100,Mental Disorders,,,38 CFR 4.130 +9413,Unspecified anxiety disorder,100,Mental Disorders,,,38 CFR 4.130 +9416,Dissociative amnesia; dissociative identity disorder,100,Mental Disorders,,,38 CFR 4.130 +9417,Depersonalization/Derealization disorder,100,Mental Disorders,,,38 CFR 4.130 +9421,Somatic symptom disorder,100,Mental Disorders,,,38 CFR 4.130 +9422,Other specified somatic symptom and related disorder,100,Mental Disorders,,,38 CFR 4.130 +9423,Unspecified somatic symptom and related disorder,100,Mental Disorders,,,38 CFR 4.130 +9424,Conversion disorder (functional neurological symptom disorder),100,Mental Disorders,,,38 CFR 4.130 +9425,Illness anxiety disorder,100,Mental Disorders,,,38 CFR 4.130 +9431,Cyclothymic disorder,100,Mental Disorders,,,38 CFR 4.130 +9432,Bipolar disorder,100,Mental Disorders,,,38 CFR 4.130 +9433,Persistent depressive disorder (dysthymia),100,Mental Disorders,,,38 CFR 4.130 +9434,Major depressive disorder,100,Mental Disorders,,,38 CFR 4.130 +9435,Unspecified depressive disorder,100,Mental Disorders,,,38 CFR 4.130 +9440,Chronic adjustment disorder,100,Mental Disorders,,,38 CFR 4.130 +9520,Anorexia nervosa,100,Mental Disorders,,,38 CFR 4.130 +9521,Bulimia nervosa,100,Mental Disorders,,,38 CFR 4.130 +9900,"Maxilla or mandible, chronic osteomyelitis, osteonecrosis or osteoradionecrosis of.",100,Dental and Oral Conditions,,,38 CFR 4.150 +9901,"Mandible, loss of, complete, between angles",100,Dental and Oral Conditions,,,38 CFR 4.150 +9902,"Mandible, loss of, including ramus, unilaterally or bilaterally.",70,Dental and Oral Conditions,,,38 CFR 4.150 +9903,"Mandible, nonunion of, confirmed by diagnostic imaging studies.",30,Dental and Oral Conditions,,,38 CFR 4.150 +9904,"Mandible, malunion of.",20,Dental and Oral Conditions,,,38 CFR 4.150 +9905,Temporomandibular disorder (TMD).,50,Dental and Oral Conditions,,,38 CFR 4.150 +9908,"Condyloid process, loss of, one or both sides",30,Dental and Oral Conditions,,,38 CFR 4.150 +9909,"Coronoid process, loss of.",20,Dental and Oral Conditions,,,38 CFR 4.150 +9911,"Hard palate, loss of.",30,Dental and Oral Conditions,,,38 CFR 4.150 +9913,"Teeth, loss of, due to loss of substance of body of maxilla or mandible without loss of continuity.",40,Dental and Oral Conditions,,,38 CFR 4.150 +9914,"Maxilla, loss of more than half.",100,Dental and Oral Conditions,,,38 CFR 4.150 +9915,"Maxilla, loss of half or less.",40,Dental and Oral Conditions,,,38 CFR 4.150 +9916,"Maxilla, malunion or nonunion of.",30,Dental and Oral Conditions,,,38 CFR 4.150 +9917,"Neoplasm, hard and soft tissue, benign.",0,Dental and Oral Conditions,,,38 CFR 4.150 +9918,"Neoplasm, hard and soft tissue, malignant",100,Dental and Oral Conditions,,,38 CFR 4.150 diff --git a/domain-ee/ee-max-cfi-app/src/python_src/util/lookup_table.py b/domain-ee/ee-max-cfi-app/src/python_src/util/lookup_table.py index 4235d880d8..bf5dbdcc33 100644 --- a/domain-ee/ee-max-cfi-app/src/python_src/util/lookup_table.py +++ b/domain-ee/ee-max-cfi-app/src/python_src/util/lookup_table.py @@ -14,9 +14,19 @@ def get_max_ratings_by_code(): for index, csv_line in enumerate(csv_reader): if index == 0: continue - diagnostic_code, rated_issue_name, max_rating = csv_line - diagnostic_code = int(diagnostic_code) - max_rating = int(max_rating) + + if len(csv_line) != 7: + raise ValueError(f"Invalid CSV line at index {index}") + + diagnostic_code, rated_issue_name, max_rating, body_system, category, subcategory, cfr_ref = csv_line + if not diagnostic_code or not max_rating: + continue + + try: + diagnostic_code = int(diagnostic_code) + max_rating = int(max_rating) + except ValueError: + raise ValueError(f"Invalid diagnostic code or max rating at index {index}: \n{csv_line}") diagnostic_code_to_max_rating[diagnostic_code] = max_rating return diagnostic_code_to_max_rating diff --git a/domain-ee/ee-max-cfi-app/src/python_src/util/table_version.py b/domain-ee/ee-max-cfi-app/src/python_src/util/table_version.py index e614c3affa..1dba7e5b95 100644 --- a/domain-ee/ee-max-cfi-app/src/python_src/util/table_version.py +++ b/domain-ee/ee-max-cfi-app/src/python_src/util/table_version.py @@ -1 +1 @@ -TABLE_VERSION = "v0.1" +TABLE_VERSION = "v1.0" diff --git a/domain-ee/ee-max-cfi-app/tests/test_api.py b/domain-ee/ee-max-cfi-app/tests/test_api.py index d117b07e81..9dafc413e4 100644 --- a/domain-ee/ee-max-cfi-app/tests/test_api.py +++ b/domain-ee/ee-max-cfi-app/tests/test_api.py @@ -3,8 +3,8 @@ MAX_RATING = "/max-ratings" TINNITUS = {"diagnostic_code": 6260, "max_rating": 10} - -TUBERCULOSIS = {"diagnostic_code": 7710} +TUBERCULOSIS = {"diagnostic_code": 7710, "max_rating": 100} +NOT_RATED = {"diagnostic_code": 9999} def test_max_rating_with_no_dc(client: TestClient): @@ -31,6 +31,21 @@ def test_max_rating_with_one_dc(client: TestClient): assert ratings[0]["max_rating"] == TINNITUS["max_rating"] +def test_max_rating_with_multiple_dc(client: TestClient): + json_post_dict = {"diagnostic_codes": [TINNITUS["diagnostic_code"], TUBERCULOSIS["diagnostic_code"]]} + + response = client.post(MAX_RATING, json=json_post_dict) + assert response.status_code == 200 + response_json = response.json() + + ratings = response_json["ratings"] + assert len(ratings) == 2 + assert ratings[0]["diagnostic_code"] == TINNITUS["diagnostic_code"] + assert ratings[0]["max_rating"] == TINNITUS["max_rating"] + assert ratings[1]["diagnostic_code"] == TUBERCULOSIS["diagnostic_code"] + assert ratings[1]["max_rating"] == TUBERCULOSIS["max_rating"] + + def test_max_rating_with_duplicate_dc(client: TestClient): json_post_dict = {"diagnostic_codes": [TINNITUS["diagnostic_code"], TINNITUS["diagnostic_code"]]} @@ -51,7 +66,7 @@ def test_max_rating_with_too_many_dc(client: TestClient): def test_max_rating_with_unmapped_dc(client: TestClient): - json_post_dict = {"diagnostic_codes": [TUBERCULOSIS["diagnostic_code"]]} + json_post_dict = {"diagnostic_codes": [NOT_RATED["diagnostic_code"]]} response = client.post(MAX_RATING, json=json_post_dict) diff --git a/domain-rrd/MAS End to End Process.md b/domain-rrd/MAS End to End Process.md deleted file mode 100644 index 13d1069365..0000000000 --- a/domain-rrd/MAS End to End Process.md +++ /dev/null @@ -1,10 +0,0 @@ -1. Get evidence from MAS -2. Get evidence from Lighthouse -3. Combine evidence into one -4. Call Julian service using abdevidence and claimCondition.disabilityActionType -5. Julian service returns summary (flag) -6. Enhance response with Veteran info (for GeneratePDF) -7. Call generate PDF -8. --> If no evidence, call pcOrderExam -9. Call claimStatusUpdate -10. Upload PDF file (probably using BIP) diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/RRR__Get_Metrics_Counts.sql b/domain-rrd/db-init/src/main/resource/database.migrations/RRR__Get_Metrics_Counts.sql deleted file mode 100644 index 70ebb31324..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/RRR__Get_Metrics_Counts.sql +++ /dev/null @@ -1,10 +0,0 @@ --- Gets all the latest counts for each contention_id -CREATE OR REPLACE FUNCTION GetLatestCounts() returns setof jsonb -AS $function$ -BEGIN -Return query -SELECT DISTINCT ON (contention_id) evidence_count_summary -FROM claims.assessment_result -ORDER BY contention_id, created_at DESC NULLS LAST, contention_id; -END; -$function$ LANGUAGE plpgsql; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V2.0__Create_Tables.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V2.0__Create_Tables.sql deleted file mode 100644 index af0573d097..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V2.0__Create_Tables.sql +++ /dev/null @@ -1,61 +0,0 @@ -CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; - -CREATE TABLE IF NOT EXISTS veteran ( - id uuid DEFAULT uuid_generate_v4 () NOT NULL, - icn VARCHAR NOT NULL UNIQUE, - participant_id VARCHAR, - created_at timestamp NOT NULL, - updated_at timestamp NOT NULL, - PRIMARY KEY(id) -); - -CREATE TABLE IF NOT EXISTS claim ( - id uuid DEFAULT uuid_generate_v4 () NOT NULL, - claim_submission_id VARCHAR NOT NULL UNIQUE, - veteran_id uuid DEFAULT uuid_generate_v4 () NOT NULL, - id_type VARCHAR NOT NULL, - incoming_status VARCHAR, - created_at timestamp NOT NULL, - updated_at timestamp NOT NULL, - PRIMARY KEY(id), - CONSTRAINT fk_veteran_id - FOREIGN KEY (veteran_id) - REFERENCES veteran(id) -); - -CREATE TABLE IF NOT EXISTS contention( - id uuid DEFAULT uuid_generate_v4 () NOT NULL, - claim_id uuid DEFAULT uuid_generate_v4 () NOT NULL, - diagnostic_code VARCHAR NOT NULL UNIQUE, - created_at timestamp NOT NULL, - updated_at timestamp NOT null, - PRIMARY KEY(id), - CONSTRAINT fk_claim_id - FOREIGN KEY (claim_id) - REFERENCES claim(id) -); - -CREATE TABLE IF NOT EXISTS assessment_result ( - id uuid DEFAULT uuid_generate_v4 () NOT NULL, - contention_id uuid DEFAULT uuid_generate_v4 () NOT NULL, - evidence_count INTEGER NOT NULL, - created_at timestamp NOT NULL, - updated_at timestamp NOT NULL, - PRIMARY KEY(id), - CONSTRAINT fk_contention_id - FOREIGN KEY (contention_id) - REFERENCES contention(id) -); - -CREATE TABLE IF NOT EXISTS evidence_summary_document ( - id uuid DEFAULT uuid_generate_v4 () NOT NULL, - contention_id uuid DEFAULT uuid_generate_v4 () NOT NULL, - evidence_count INTEGER NOT NULL, - document_name VARCHAR NOT NULL, - created_at timestamp NOT NULL, - updated_at timestamp NOT NULL, - PRIMARY KEY(id), - CONSTRAINT fk_contention_id - FOREIGN KEY (contention_id) - REFERENCES contention(id) -); diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V2.1__Fix_Unique_Constraint.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V2.1__Fix_Unique_Constraint.sql deleted file mode 100644 index 290d83f728..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V2.1__Fix_Unique_Constraint.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE contention DROP CONSTRAINT contention_diagnostic_code_key; - -CREATE UNIQUE INDEX uk_contention_claim_code ON contention (claim_id, diagnostic_code); diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V2.2__Evidence_Count_Summary.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V2.2__Evidence_Count_Summary.sql deleted file mode 100644 index 2285ae38d2..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V2.2__Evidence_Count_Summary.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE assessment_result DROP COLUMN evidence_count; - -ALTER TABLE assessment_result ADD COLUMN evidence_count_summary jsonb; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V3.0__Create_Event_Table.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V3.0__Create_Event_Table.sql deleted file mode 100644 index 8fca084ded..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V3.0__Create_Event_Table.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE TABLE IF NOT EXISTS audit_event ( - id uuid DEFAULT uuid_generate_v4 () NOT NULL, - event_id VARCHAR NOT NULL, - route_id VARCHAR, - payload_type VARCHAR NOT NULL, - message VARCHAR, - throwable TEXT, - details TEXT, - event_time timestamp NOT NULL, - PRIMARY KEY(id) -); - -CREATE INDEX audit_event_id_idx on audit_event(event_id); diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V3.1__Evidence_Summary_Document_Counts.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V3.1__Evidence_Summary_Document_Counts.sql deleted file mode 100644 index 5a9116f9c9..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V3.1__Evidence_Summary_Document_Counts.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE evidence_summary_document DROP COLUMN evidence_count; -ALTER TABLE evidence_summary_document ADD COLUMN evidence_count jsonb; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V3.2__Add_Collection_Id.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V3.2__Add_Collection_Id.sql deleted file mode 100644 index 187c38e9ff..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V3.2__Add_Collection_Id.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE claim ADD COLUMN collection_id VARCHAR; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.0__Create_VeteranFlashId_Table.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.0__Create_VeteranFlashId_Table.sql deleted file mode 100644 index 2529000ebf..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.0__Create_VeteranFlashId_Table.sql +++ /dev/null @@ -1,15 +0,0 @@ --- create association table: a veteran can have many flash_ids -CREATE TABLE IF NOT EXISTS veteran_flash_id ( - id uuid DEFAULT uuid_generate_v4 () NOT NULL, - -- on other schemas, we appear to have been doing something like this to our UUID FKs: - -- `veteran_id uuid DEFAULT uuid_generate_v4 () NOT NULL,` - -- this statement says "if no data for this field, then generate a new UUID" - -- but i don't think this is necessary... for many of our use-cases - -- here, `veteran_id uuid` should be sufficient, since it should already exist - veteran_id uuid NOT NULL, - flash_id INTEGER NOT NULL, - PRIMARY KEY(id), - CONSTRAINT fk_veteran_id - FOREIGN KEY (veteran_id) - REFERENCES veteran(id) -); diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.10__Reference_Claim_Submission_In_Exam_Order.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.10__Reference_Claim_Submission_In_Exam_Order.sql deleted file mode 100644 index 355aec44f5..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.10__Reference_Claim_Submission_In_Exam_Order.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE exam_order - ADD COLUMN IF NOT EXISTS claim_submission_id UUID; - -ALTER TABLE exam_order - ADD CONSTRAINT fk_claim_submission_id FOREIGN KEY (claim_submission_id) REFERENCES claim_submission (id); diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.11__Add_InScope_To_Claim_Submission.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.11__Add_InScope_To_Claim_Submission.sql deleted file mode 100644 index 2d66072cac..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.11__Add_InScope_To_Claim_Submission.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE claim_submission - ADD COLUMN IF NOT EXISTS in_scope BOOLEAN; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.12__Change_Veteran_Flash.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.12__Change_Veteran_Flash.sql deleted file mode 100644 index 08261b58e9..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.12__Change_Veteran_Flash.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE veteran_flash_id ALTER COLUMN flash_id TYPE VARCHAR; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.13__Additional_Contention_And_Exam_Order_Fields.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.13__Additional_Contention_And_Exam_Order_Fields.sql deleted file mode 100644 index 47a0d094c4..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.13__Additional_Contention_And_Exam_Order_Fields.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE contention ADD COLUMN condition_name VARCHAR; -ALTER TABLE contention ADD COLUMN classification_code VARCHAR; -ALTER TABLE exam_order ADD COLUMN ordered_at TIMESTAMP; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.14__Add_E_Folder_ID_to_ESD.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.14__Add_E_Folder_ID_to_ESD.sql deleted file mode 100644 index 3de0c9f194..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.14__Add_E_Folder_ID_to_ESD.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE evidence_summary_document ADD COLUMN folder_id UUID; - -ALTER TABLE evidence_summary_document DROP COLUMN location; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.15__Add_UploadedAt_To_EvidenceSummaryDocument.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.15__Add_UploadedAt_To_EvidenceSummaryDocument.sql deleted file mode 100644 index 738a832478..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.15__Add_UploadedAt_To_EvidenceSummaryDocument.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE evidence_summary_document ADD COLUMN uploaded_at TIMESTAMP; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.1__Create_ExamOrder_Table.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.1__Create_ExamOrder_Table.sql deleted file mode 100644 index 0d3bdf4014..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.1__Create_ExamOrder_Table.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE IF NOT EXISTS exam_order ( - id uuid DEFAULT uuid_generate_v4 () NOT NULL, - collection_id VARCHAR, - status VARCHAR, - created_at timestamp NOT NULL, - updated_at timestamp NOT NULL, - PRIMARY KEY(id) -); diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.2__Update_AuditEvent_details_Column.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.2__Update_AuditEvent_details_Column.sql deleted file mode 100644 index 907f147f5d..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.2__Update_AuditEvent_details_Column.sql +++ /dev/null @@ -1,4 +0,0 @@ --- We do not need to preserve this data since we should not have any production audit details, yet -ALTER TABLE audit_event DROP COLUMN details; --- As such, we can just recreate the column as JSONB -ALTER TABLE audit_event ADD COLUMN details JSONB; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.3__Update_Claim_Table.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.3__Update_Claim_Table.sql deleted file mode 100644 index 3d009972d0..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.3__Update_Claim_Table.sql +++ /dev/null @@ -1,8 +0,0 @@ -ALTER TABLE claim -ADD COLUMN vbms_id VARCHAR, -ADD COLUMN off_ramp_reason VARCHAR, -ADD COLUMN presumptive_flag BOOLEAN, -ADD COLUMN disability_action_type VARCHAR, -ADD COLUMN in_scope BOOLEAN, -ADD COLUMN submission_source VARCHAR, -ADD COLUMN submission_date timestamp; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.4__Update_Veteran_Table.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.4__Update_Veteran_Table.sql deleted file mode 100644 index 5c23b0959e..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.4__Update_Veteran_Table.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE veteran -ADD COLUMN icn_timestamp timestamp; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.5__Update_EvidenceSummaryDocument_Table.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.5__Update_EvidenceSummaryDocument_Table.sql deleted file mode 100644 index febf85e5f6..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.5__Update_EvidenceSummaryDocument_Table.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE evidence_summary_document -ADD COLUMN location VARCHAR; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.6__Create_Claim_Submission_Table.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.6__Create_Claim_Submission_Table.sql deleted file mode 100644 index e77f819607..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.6__Create_Claim_Submission_Table.sql +++ /dev/null @@ -1,11 +0,0 @@ -CREATE TABLE IF NOT EXISTS claim_submission ( - id uuid DEFAULT uuid_generate_v4 () NOT NULL, - reference_id VARCHAR, - id_type VARCHAR, - submission_source VARCHAR, - submission_date timestamp, - incoming_status VARCHAR, - created_at timestamp NOT NULL, - updated_at timestamp NOT NULL, - PRIMARY KEY(id) -); diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.7__Add_Claim_FK_On_Claim_Submission.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.7__Add_Claim_FK_On_Claim_Submission.sql deleted file mode 100644 index 2f68530ab0..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.7__Add_Claim_FK_On_Claim_Submission.sql +++ /dev/null @@ -1,8 +0,0 @@ -ALTER TABLE claim_submission - ADD COLUMN IF NOT EXISTS claim_id UUID NOT NULL; - -ALTER TABLE claim_submission - ADD COLUMN IF NOT EXISTS off_ramp_reason VARCHAR; - -ALTER TABLE claim_submission - ADD CONSTRAINT fk_claim_id FOREIGN KEY (claim_id) REFERENCES claim (id); diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.8__Remove_Claim_Columns.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.8__Remove_Claim_Columns.sql deleted file mode 100644 index 081a42f4dc..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.8__Remove_Claim_Columns.sql +++ /dev/null @@ -1,9 +0,0 @@ -ALTER TABLE claim DROP COLUMN claim_submission_id; -ALTER TABLE claim DROP COLUMN id_type; -ALTER TABLE claim DROP COLUMN incoming_status; -ALTER TABLE claim DROP COLUMN submission_source; -ALTER TABLE claim DROP COLUMN submission_date; -ALTER TABLE claim DROP COLUMN off_ramp_reason; -ALTER TABLE claim DROP COLUMN in_scope; -ALTER TABLE claim DROP COLUMN collection_id; -ALTER TABLE claim ADD COLUMN rfd_flag BOOLEAN; diff --git a/domain-rrd/db-init/src/main/resource/database.migrations/V4.9__Add_Sufficient_Evidence_Flag.sql b/domain-rrd/db-init/src/main/resource/database.migrations/V4.9__Add_Sufficient_Evidence_Flag.sql deleted file mode 100644 index 73518768ed..0000000000 --- a/domain-rrd/db-init/src/main/resource/database.migrations/V4.9__Add_Sufficient_Evidence_Flag.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE assessment_result ADD COLUMN sufficient_evidence_flag BOOLEAN; diff --git a/domain-rrd/github/rrd-end2end-test.yml b/domain-rrd/github/rrd-end2end-test.yml deleted file mode 100644 index c39df4a8b2..0000000000 --- a/domain-rrd/github/rrd-end2end-test.yml +++ /dev/null @@ -1,105 +0,0 @@ -# UNUSED GITHUB WORKFLOW DEFINITION -# MAINTAINED AS A FORMAT FOR FUTURE E2E TESTING - -name: "PR: RRD End-to-end test for v2" - -on: - pull_request: - branches: [ main, qa, develop ] - # Limit to certain PR event types since this action doesn't need to run for every commit - types: [ready_for_review, review_requested] - - # When changes are pushed to special branches - push: - # Branch `develop` is handled by continuous-integration.yml, which calls this workflow - branches: [main, qa] - - # Allow manual triggering - workflow_dispatch: - - # Trigger when called by another GitHub Action - workflow_call: - -env: - LH_ACCESS_CLIENT_ID: ${{ secrets.LH_ACCESS_CLIENT_ID }} - LH_PRIVATE_KEY: ${{ secrets.LH_PRIVATE_KEY }} - SLACK_EXCEPTION_WEBHOOK: "http://mock-slack:20100/slack-messages" - - # This GitHub Secret has been removed and will need to be re-created to restore connection to MAS system - # MAS_API_AUTH_CLIENT_SECRET: ${{ secrets.MAS_API_AUTH_CLIENT_SECRET }} - COMPOSE_PROFILES: "v2,v2-mocks,pdfgen,lh" - -jobs: - end2end-test: - runs-on: ubuntu-latest - steps: - - name: "Checkout source code" - uses: actions/checkout@v4 - - - name: "Build the images" - uses: ./.github/actions/build-images - - - name: "Start the containers" - env: - ENV: "end2end-test" - run: | - source scripts/setenv.sh - export -p | sed 's/declare -x //' - - ./gradlew :app:dockerComposeUp - sleep 20 - docker ps - - ./gradlew :mocks:dockerComposeUp - sleep 20 - docker ps - - - name: "Wait for VRO to be ready" - uses: nev7n/wait_for_response@v1 - with: - url: 'http://localhost:8081/actuator/health' - responseCode: 200 - # Retry every 2 seconds - interval: 2000 - # Quite after 60 seconds - timeout: 60000 - - - name: "Run the end-to-end tests" - env: - ENV: "end2end-test" - run: | - docker ps - ./gradlew :domain-rrd:rrd-app-test:end2EndTest - - - name: "Collect docker logs on failure" - if: always() - uses: jwalton/gh-docker-logs@v2 - with: - dest: './vro-logs' - - - name: "Upload artifact" - if: always() - uses: actions/upload-artifact@v4 - with: - name: vro-logs - path: ./vro-logs/** - retention-days: 14 - - - name: "Check for tracking files" - run: | - TRACKING_FOLDER="/persist/tracking/mas-claim-submitted/$(date '+%Y-%m-%d')" - echo "::group::Examining app's tracking files in $TRACKING_FOLDER" - TRACKING_FILES=$(docker exec vro_app_1 ls "$TRACKING_FOLDER") - echo "$TRACKING_FILES" - for COLLECTION_ID in 365 366 367 369 375 376 377 378 380 381 385 386 390 391 392 400 401 500; do - echo "Checking for $COLLECTION_ID.json" - echo "$TRACKING_FILES" | grep "$COLLECTION_ID.json" - done - echo "::endgroup::" - - - name: "Clean docker container, images, and volumes" - if: always() - run: | - source scripts/setenv.sh - ./gradlew dockerclean - ./gradlew dockermaintainerclean diff --git a/domain-rrd/gradle.properties b/domain-rrd/gradle.properties deleted file mode 100644 index 773b367bc9..0000000000 --- a/domain-rrd/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -sb_webflux=2.7.4 -sb_security=2.7.4 -json_assert_version=1.5.1 diff --git a/domain-rrd/mock-mas-api/build.gradle.bak b/domain-rrd/mock-mas-api/build.gradle.bak deleted file mode 100644 index b41c9f4b46..0000000000 --- a/domain-rrd/mock-mas-api/build.gradle.bak +++ /dev/null @@ -1,23 +0,0 @@ -plugins { - id 'local.java.container-spring-conventions' - id 'local.std.java.library-spring-conventions' -} - -ext { - // TODO: improve test code coverage so that the following can be removed - jacoco_minimum_coverage = 0.2 -} - -dependencies { - - implementation "com.fasterxml.jackson.core:jackson-databind:${jackson_databind_version}" - implementation "com.fasterxml.jackson.core:jackson-core:${jackson_version}" - - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-actuator' - // implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - - implementation "org.springdoc:springdoc-openapi-starter-webmvc-api:${spring_doc_version}" - - // testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" -} diff --git a/domain-rrd/mock-mas-api/gradle.properties b/domain-rrd/mock-mas-api/gradle.properties deleted file mode 100644 index c5be55d30b..0000000000 --- a/domain-rrd/mock-mas-api/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -# server_port=20400 -healthcheck_port=20401 diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/MockMasApplication.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/MockMasApplication.java deleted file mode 100644 index 888f3a5226..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/MockMasApplication.java +++ /dev/null @@ -1,16 +0,0 @@ -package gov.va.vro.mockmas; - -import gov.va.vro.mockmas.config.MasApiProperties; -import gov.va.vro.mockmas.config.MasOauth2Properties; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; - -@SpringBootApplication -@EnableConfigurationProperties({MasApiProperties.class, MasOauth2Properties.class}) -public class MockMasApplication { - - public static void main(String[] args) { - SpringApplication.run(MockMasApplication.class, args); - } -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MasApiProperties.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MasApiProperties.java deleted file mode 100644 index f9bfd411e7..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MasApiProperties.java +++ /dev/null @@ -1,15 +0,0 @@ -package gov.va.vro.mockmas.config; - -import lombok.Getter; -import lombok.Setter; -import org.springframework.boot.context.properties.ConfigurationProperties; - -@Getter -@Setter -@ConfigurationProperties(prefix = "mock-mas.mas-api") -public class MasApiProperties { - private String baseUrl; - private String collectionStatusPath; - private String collectionAnnotsPath; - private String createExamOrderPath; -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MasApiService.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MasApiService.java deleted file mode 100644 index f084a04940..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MasApiService.java +++ /dev/null @@ -1,110 +0,0 @@ -package gov.va.vro.mockmas.config; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.mockmas.model.MasTokenResponse; -import gov.va.vro.mockmas.model.OrderExamRequest; -import gov.va.vro.mockmas.model.OrderExamResponse; -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import gov.va.vro.model.rrd.mas.request.MasCollectionAnnotationRequest; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Service; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; - -import java.util.List; - -@Service -@RequiredArgsConstructor -@Slf4j -public class MasApiService { - private final RestTemplate template; - private final ObjectMapper mapper; - private final MasApiProperties apiProperties; - private final MasOauth2Properties oauth2Properties; - - /** - * Retrieves token from the MAS development server. - * - * @return MasTokenResponse - */ - public MasTokenResponse getToken() { - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - - final String url = oauth2Properties.getTokenUri(); - - MultiValueMap map = new LinkedMultiValueMap<>(); - map.add("scope", oauth2Properties.getScope()); - map.add("grant_type", oauth2Properties.getGrantType()); - map.add("client_id", oauth2Properties.getClientId()); - map.add("client_secret", oauth2Properties.getClientSecret()); - - HttpEntity> request = new HttpEntity<>(map, headers); - - var response = template.postForEntity(url, request, MasTokenResponse.class); - return response.getBody(); - } - - /** - * Retrieves the collection from the MAS development server. - * - * @param collectionId - * @return public List annotations for the collection - */ - @SneakyThrows - public List getAnnotation(int collectionId) { - MasTokenResponse tokenResponse = getToken(); - String token = tokenResponse.getAccessToken(); - - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.setBearerAuth(token); - - String baseUrl = apiProperties.getBaseUrl(); - final String url = baseUrl + apiProperties.getCollectionAnnotsPath(); - - MasCollectionAnnotationRequest body = new MasCollectionAnnotationRequest(); - body.setCollectionsId(collectionId); - - HttpEntity request = new HttpEntity<>(body, headers); - - var response = template.postForEntity(url, request, String.class); - String responseBody = response.getBody(); - return mapper.readValue(responseBody, new TypeReference<>() {}); - } - - /** - * Order an exam for the collection. - * - * @param collectionId - * @return OrderExamResponse - */ - @SneakyThrows - public OrderExamResponse orderExam(int collectionId) { - MasTokenResponse tokenResponse = getToken(); - String token = tokenResponse.getAccessToken(); - - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.setBearerAuth(token); - - String baseUrl = apiProperties.getBaseUrl(); - final String url = baseUrl + apiProperties.getCreateExamOrderPath(); - - OrderExamRequest body = new OrderExamRequest(collectionId); - - HttpEntity request = new HttpEntity<>(body, headers); - - var response = template.postForEntity(url, request, String.class); - String responseBody = response.getBody(); - log.info("order exam response: {}", responseBody); - return mapper.readValue(responseBody, new TypeReference<>() {}); - } -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MasOauth2Properties.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MasOauth2Properties.java deleted file mode 100644 index bfb6675425..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MasOauth2Properties.java +++ /dev/null @@ -1,16 +0,0 @@ -package gov.va.vro.mockmas.config; - -import lombok.Getter; -import lombok.Setter; -import org.springframework.boot.context.properties.ConfigurationProperties; - -@Getter -@Setter -@ConfigurationProperties(prefix = "mock-mas.mas-oauth2") -public class MasOauth2Properties { - private String tokenUri; - private String clientId; - private String clientSecret; - private String scope; - private String grantType; -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MockMasConfig.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MockMasConfig.java deleted file mode 100644 index 47da77f072..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/config/MockMasConfig.java +++ /dev/null @@ -1,76 +0,0 @@ -package gov.va.vro.mockmas.config; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.mockmas.model.CollectionStore; -import gov.va.vro.mockmas.model.ExamOrderStore; -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.web.client.RestTemplate; - -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.Objects; - -@Slf4j -@Configuration -public class MockMasConfig { - - private static final String DATA_PATTERN = "classpath:annotations/*.json"; - - /** Creates and provides the common instance of RestTemplate as a bean for the application. */ - @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); - } - - @Bean - public ObjectMapper objectMapper() { - return new ObjectMapper(); - } - - @SneakyThrows - private List readFromResource(Resource resource) { - InputStream stream = resource.getInputStream(); - ObjectMapper mapper = objectMapper(); - return mapper.readValue(stream, new TypeReference<>() {}); - } - - /** - * Creates a HashMap store and all mock collections and populates the collections in the store. - * - * @return CollectionStore - */ - @Bean - public CollectionStore collectionStore() throws IOException { - CollectionStore store = new CollectionStore(); - - log.info("Loading mock annotations from resources"); - ClassLoader classLoader = this.getClass().getClassLoader(); - PathMatchingResourcePatternResolver r = new PathMatchingResourcePatternResolver(classLoader); - Resource[] resources = r.getResources(DATA_PATTERN); - - for (Resource mockCollection : resources) { - log.info("Found mock collection with filename " + mockCollection.getFilename()); - String collectionId = Objects.requireNonNull(mockCollection.getFilename()).split("[-.]")[1]; - Integer collectionInt = Integer.parseInt(collectionId); - List collectionList = readFromResource(mockCollection); - store.put(collectionInt, collectionList); - } - - log.info("Returning store with mock annotations"); - return store; - } - - @Bean - public ExamOrderStore examOrderStore() { - ExamOrderStore store = new ExamOrderStore(); - return store; - } -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/controller/GlobalExceptionHandler.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/controller/GlobalExceptionHandler.java deleted file mode 100644 index 8cbc89d929..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/controller/GlobalExceptionHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -package gov.va.vro.mockmas.controller; - -import gov.va.vro.mockmas.model.ErrorResponse; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.server.ResponseStatusException; - -@ControllerAdvice -@Slf4j -public class GlobalExceptionHandler { - - /** - * Handles response status exceptions from controllers. - * - * @param exception the exception - * @return http response - */ - @ExceptionHandler(ResponseStatusException.class) - public ResponseEntity handleException(ResponseStatusException exception) { - log.info("Expected thrown exception", exception); - ErrorResponse error = new ErrorResponse(); - error.setMessage(exception.getReason()); - return new ResponseEntity<>(error, exception.getStatus()); - } - - /** - * Handles general, unspecified exceptions (catch-all). - * - * @param exception the exception - * @return returns exception - */ - @ExceptionHandler(Exception.class) - public ResponseEntity handleException(Exception exception) { - log.error("Unexpected error", exception); - ErrorResponse error = new ErrorResponse(); - error.setMessage(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()); - return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); - } -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/controller/MockMasController.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/controller/MockMasController.java deleted file mode 100644 index 6d4f09e330..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/controller/MockMasController.java +++ /dev/null @@ -1,179 +0,0 @@ -package gov.va.vro.mockmas.controller; - -import gov.va.vro.mockmas.config.MasApiService; -import gov.va.vro.mockmas.model.CollectionStore; -import gov.va.vro.mockmas.model.ConditionInfo; -import gov.va.vro.mockmas.model.ExamOrderStore; -import gov.va.vro.mockmas.model.MasTokenResponse; -import gov.va.vro.mockmas.model.OrderExamCheckResponse; -import gov.va.vro.mockmas.model.OrderExamResponse; -import gov.va.vro.mockmas.model.OrderExamSuccess; -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import gov.va.vro.model.rrd.mas.MasCollectionStatus; -import gov.va.vro.model.rrd.mas.MasStatus; -import gov.va.vro.model.rrd.mas.request.MasCollectionAnnotationRequest; -import gov.va.vro.model.rrd.mas.request.MasCollectionStatusRequest; -import gov.va.vro.model.rrd.mas.request.MasOrderExamRequest; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.enums.ParameterIn; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.util.MultiValueMap; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.server.ResponseStatusException; - -import java.util.Collections; -import java.util.List; - -@Controller -@RequestMapping("/") -@RequiredArgsConstructor -@Slf4j -public class MockMasController { - private final MasApiService apiService; - private final CollectionStore store; - - private final ExamOrderStore examOrderStore; - - @RequestMapping( - method = RequestMethod.POST, - value = "/pcQueryCollectionAnnots", - produces = {"application/json", "application/problem+json"}) - ResponseEntity> getAnnotations( - @RequestBody MasCollectionAnnotationRequest request) { - int collectionId = request.getCollectionsId(); - log.info("Received annotations request for collection id: {}", collectionId); - if (collectionId == 350) { - List collection = apiService.getAnnotation(collectionId); - return new ResponseEntity<>(collection, HttpStatus.OK); - } - - if (collectionId == 369 || collectionId == 370) { // Used to test mas exceptions - throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Mas exception testing"); - } - - List collection = store.get(collectionId); - if (collection == null) { - String reason = "No claim found for id: " + collectionId; - throw new ResponseStatusException(HttpStatus.NOT_FOUND, reason); - } - - return new ResponseEntity<>(collection, HttpStatus.OK); - } - - @RequestMapping( - method = RequestMethod.POST, - value = "/pcCheckCollectionStatus", - produces = {"application/json", "application/problem+json"}) - ResponseEntity> getCollectionStatus( - @RequestBody MasCollectionStatusRequest request) { - int collectionId = request.getCollectionsId(); - MasCollectionStatus status = new MasCollectionStatus(); - status.setCollectionsId(collectionId); - status.setCollectionStatus(MasStatus.VRONOTIFIED.getStatus()); - List response = Collections.singletonList(status); - return new ResponseEntity<>(response, HttpStatus.OK); - } - - @RequestMapping( - method = RequestMethod.POST, - value = "/pcOrderExam", - produces = {MediaType.APPLICATION_JSON_VALUE}) - ResponseEntity postExam( - @Parameter( - name = "claimId", - description = "The CorpDB BNFT_CLAIM_ID", - required = true, - in = ParameterIn.PATH) - @RequestBody - MasOrderExamRequest request) { - log.info("Ordering exam for {}.", request.getCollectionsId()); - - // Test cases that require a mas ERROR on ordering exam - if (request.getCollectionsId() == 391) { - throw new ResponseStatusException( - HttpStatus.INTERNAL_SERVER_ERROR, "Returning 500 for testing"); - } - ConditionInfo conditionInfo = new ConditionInfo("HYPERTENSION", "HYPERTENSION"); - - OrderExamSuccess success = new OrderExamSuccess(); - success.setCollectionsId(request.getCollectionsId()); - success.setConditions(Collections.singletonList(conditionInfo)); - - OrderExamResponse response = new OrderExamResponse(success); - examOrderStore.put(request.getCollectionsId(), true); - return new ResponseEntity<>(response, HttpStatus.OK); - } - - /** - * This service does not exist in the real MAS Service. It is used for end to end testing with - * this mock only to ensure that the /pcOrderExam path was called correctly. * - */ - @RequestMapping( - method = RequestMethod.GET, - value = "/checkExamOrdered/{collectionsId}", - produces = {MediaType.APPLICATION_JSON_VALUE}) - ResponseEntity checkExamOrdered( - @Parameter( - name = "collectionsId", - description = "The collectionId given to /pcOrderExam", - required = true, - in = ParameterIn.PATH) - @PathVariable("collectionsId") - Integer collectionsId) { - log.info("Checking if exam ordered for {}.", collectionsId); - - Boolean examOrdered = examOrderStore.get(collectionsId); - if (examOrdered == null) { - examOrdered = false; - } - OrderExamCheckResponse response = new OrderExamCheckResponse(examOrdered); - return new ResponseEntity<>(response, HttpStatus.OK); - } - - /** - * This service does not exist in the real MAS Service. It is used for end to end testing with - * this mock only to ensure that the /pcOrderExam path was called correctly. * - */ - @RequestMapping( - method = RequestMethod.DELETE, - value = "/checkExamOrdered/{collectionsId}", - produces = {MediaType.APPLICATION_JSON_VALUE}) - ResponseEntity deleteExamCheck( - @Parameter( - name = "collectionsId", - description = "The collectionId given to /pcOrderExam", - required = true, - in = ParameterIn.PATH) - @PathVariable("collectionsId") - Integer collectionsId) { - - Boolean examOrdered = examOrderStore.get(collectionsId); - if (examOrdered == null) { - // Not all test cases haver exams ordered. If it's not found just proceed instead of erroring. - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - examOrderStore.reset(collectionsId); - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - @RequestMapping( - method = RequestMethod.POST, - value = "/token", - consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE}, - produces = {MediaType.APPLICATION_JSON_VALUE}) - ResponseEntity postForToken( - @RequestParam MultiValueMap paramMap) { - log.info("Getting the token from MAS server."); - MasTokenResponse response = apiService.getToken(); - return new ResponseEntity<>(response, HttpStatus.OK); - } -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/CollectionStore.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/CollectionStore.java deleted file mode 100644 index 1b33e90227..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/CollectionStore.java +++ /dev/null @@ -1,19 +0,0 @@ -package gov.va.vro.mockmas.model; - -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class CollectionStore { - private Map> store = new HashMap<>(); - - public void put(Integer collectionId, List collection) { - store.put(collectionId, collection); - } - - public List get(Integer collectionId) { - return store.get(collectionId); - } -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/ConditionInfo.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/ConditionInfo.java deleted file mode 100644 index e8409e700f..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/ConditionInfo.java +++ /dev/null @@ -1,15 +0,0 @@ -package gov.va.vro.mockmas.model; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class ConditionInfo { - private String contentionCode; - private String contentionText; -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/ErrorResponse.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/ErrorResponse.java deleted file mode 100644 index db045a837d..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/ErrorResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package gov.va.vro.mockmas.model; - -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class ErrorResponse { - private String message; -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/ExamOrderStore.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/ExamOrderStore.java deleted file mode 100644 index a6892eea96..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/ExamOrderStore.java +++ /dev/null @@ -1,20 +0,0 @@ -package gov.va.vro.mockmas.model; - -import java.util.HashMap; -import java.util.Map; - -public class ExamOrderStore { - private Map store = new HashMap<>(); - - public void put(Integer collectionId, Boolean orderedExam) { - store.put(collectionId, orderedExam); - } - - public Boolean get(Integer collectionId) { - return store.get(collectionId); - } - - public void reset(Integer collectionId) { - store.remove(collectionId); - } -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/MasTokenRequest.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/MasTokenRequest.java deleted file mode 100644 index b2367e31d9..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/MasTokenRequest.java +++ /dev/null @@ -1,20 +0,0 @@ -package gov.va.vro.mockmas.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class MasTokenRequest { - private String scope; - - @JsonProperty("grant-type") - private String grantType; - - @JsonProperty("client-id") - private String clientId; - - @JsonProperty("client_secret") - private String clientSecret; -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/MasTokenResponse.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/MasTokenResponse.java deleted file mode 100644 index bcc694702e..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/MasTokenResponse.java +++ /dev/null @@ -1,38 +0,0 @@ -package gov.va.vro.mockmas.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -@JsonIgnoreProperties(ignoreUnknown = true) -public class MasTokenResponse { - @JsonProperty("access_token") - private String accessToken; - - @JsonProperty("expires_in") - private int expiresIn; - - @JsonProperty("refresh_expires_in") - private int refreshExpiresIn; - - @JsonProperty("refresh_token") - private String refreshToken; - - @JsonProperty("token_type") - private String tokenType; - - @JsonProperty("id_token") - private String idToken; - - @JsonProperty("not-before-policy") - private int NotBeforePolicy; - - @JsonProperty("session_state") - private String sessionState; - - @JsonProperty("scope") - private String scope; -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamCheckResponse.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamCheckResponse.java deleted file mode 100644 index bc2598db13..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamCheckResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package gov.va.vro.mockmas.model; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class OrderExamCheckResponse { - private boolean ordered; -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamRequest.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamRequest.java deleted file mode 100644 index 3df14e977c..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamRequest.java +++ /dev/null @@ -1,14 +0,0 @@ -package gov.va.vro.mockmas.model; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class OrderExamRequest { - private int collectionsId; -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamResponse.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamResponse.java deleted file mode 100644 index e48be9ec77..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package gov.va.vro.mockmas.model; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class OrderExamResponse { - private OrderExamSuccess success; -} diff --git a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamSuccess.java b/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamSuccess.java deleted file mode 100644 index b5a354baac..0000000000 --- a/domain-rrd/mock-mas-api/src/main/java/gov/va/vro/mockmas/model/OrderExamSuccess.java +++ /dev/null @@ -1,13 +0,0 @@ -package gov.va.vro.mockmas.model; - -import lombok.Getter; -import lombok.Setter; - -import java.util.List; - -@Getter -@Setter -public class OrderExamSuccess { - private List conditions; - private int collectionsId; -} diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-365.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-365.json deleted file mode 100644 index 877399bcc0..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-365.json +++ /dev/null @@ -1,176 +0,0 @@ -[ - { - "collectionsId": 365, - "vtrnFileId": "099999365", - "creationDate": "2023-02-14T12:11:53.888Z", - "icn": "1012666073V986365", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "740", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 866, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Irbesartan-Hydrochlorothiazide", - "page_num": "22", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 889, - "acd_pref_name": "irbesartan", - "spellcheck_val": "irbesartan - hydrochlorothiazide", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "141/92", - "page_num": "83, 86", - "dates": "", - "observation_date": "2022-07-17Z", - "end": 1603, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/93", - "page_num": "576, 753, 878", - "dates": "", - "observation_date": "2022-08-11Z", - "end": 376, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/92", - "page_num": "813", - "dates": "", - "observation_date": "2022-08-21Z", - "end": 1394, - "acd_pref_name": "SystolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "143/88", - "page_num": "823", - "dates": "", - "observation_date": "2022-09-01Z", - "end": 1571, - "acd_pref_name": "DiastolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-366.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-366.json deleted file mode 100644 index 740f0f899b..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-366.json +++ /dev/null @@ -1,176 +0,0 @@ -[ - { - "collectionsId": 366, - "vtrnFileId": "099999366", - "creationDate": "2023-02-14T12:11:53.888Z", - "icn": "1012666073V986366", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "740", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 866, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Irbesartan-Hydrochlorothiazide", - "page_num": "22", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 889, - "acd_pref_name": "irbesartan", - "spellcheck_val": "irbesartan - hydrochlorothiazide", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "141/92", - "page_num": "83, 86", - "dates": "", - "observation_date": "2022-07-17Z", - "end": 1603, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/93", - "page_num": "576, 753, 878", - "dates": "", - "observation_date": "2022-08-11Z", - "end": 376, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/92", - "page_num": "813", - "dates": "", - "observation_date": "2022-08-21Z", - "end": 1394, - "acd_pref_name": "SystolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "143/88", - "page_num": "823", - "dates": "", - "observation_date": "2022-09-01Z", - "end": 1571, - "acd_pref_name": "DiastolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-367.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-367.json deleted file mode 100644 index 74aa7e248a..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-367.json +++ /dev/null @@ -1,176 +0,0 @@ -[ - { - "collectionsId": 367, - "vtrnFileId": "099999367", - "creationDate": "2023-02-14T12:11:53.888Z", - "icn": "1012666073V986367", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "740", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 866, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Irbesartan-Hydrochlorothiazide", - "page_num": "22", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 889, - "acd_pref_name": "irbesartan", - "spellcheck_val": "irbesartan - hydrochlorothiazide", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "141/92", - "page_num": "83, 86", - "dates": "", - "observation_date": "2022-07-17Z", - "end": 1603, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/93", - "page_num": "576, 753, 878", - "dates": "", - "observation_date": "2022-08-11Z", - "end": 376, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/92", - "page_num": "813", - "dates": "", - "observation_date": "2022-08-21Z", - "end": 1394, - "acd_pref_name": "SystolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "143/88", - "page_num": "823", - "dates": "", - "observation_date": "2022-09-01Z", - "end": 1571, - "acd_pref_name": "DiastolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-375.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-375.json deleted file mode 100644 index 2b59a1addd..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-375.json +++ /dev/null @@ -1,176 +0,0 @@ -[ - { - "collectionsId": 375, - "vtrnFileId": "099999376", - "creationDate": "2023-02-14T12:11:53.888Z", - "icn": "9999999999V999999", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "740", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 866, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Irbesartan-Hydrochlorothiazide", - "page_num": "22", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 889, - "acd_pref_name": "irbesartan", - "spellcheck_val": "irbesartan - hydrochlorothiazide", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "141/92", - "page_num": "83, 86", - "dates": "", - "observation_date": "2022-07-17Z", - "end": 1603, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/93", - "page_num": "576, 753, 878", - "dates": "", - "observation_date": "2022-08-11Z", - "end": 376, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/92", - "page_num": "813", - "dates": "", - "observation_date": "2022-08-21Z", - "end": 1394, - "acd_pref_name": "SystolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "143/88", - "page_num": "823", - "dates": "", - "observation_date": "2022-09-01Z", - "end": 1571, - "acd_pref_name": "DiastolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-376.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-376.json deleted file mode 100644 index 7990b2f730..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-376.json +++ /dev/null @@ -1,339 +0,0 @@ -[ - { - "collectionsId": 376, - "vtrnFileId": "099999376", - "creationDate": "2023-02-14T12:11:53.888Z", - "icn": "9999999999V999999", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension With partial", - "page_num": "44", - "dates": "", - "end": 14788, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "04/14/****", - "sorted_date": "1999-11-22Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "740", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 866, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Irbesartan-Hydrochlorothiazide", - "page_num": "22", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 889, - "acd_pref_name": "irbesartan", - "spellcheck_val": "irbesartan - hydrochlorothiazide", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "141/92", - "page_num": "83, 86", - "dates": "", - "observation_date": "2022-07-17Z", - "end": 1603, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/93", - "page_num": "576, 753, 878", - "dates": "", - "observation_date": "2022-08-11Z", - "end": 376, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/92", - "page_num": "813", - "dates": "", - "observation_date": "2022-08-21Z", - "end": 1394, - "acd_pref_name": "SystolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "140/95", - "page_num": "42", - "dates": "", - "observation_date": "", - "end": 591, - "acd_pref_name": "BPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "143/88", - "page_num": "823", - "dates": "", - "observation_date": "2022-09-01Z", - "end": 1571, - "acd_pref_name": "DiastolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - }, - { - "docTypeDescription": "Certificate of Release", - "eFolderVersionRefId": "{9YDD999-99456-989898-B5345-HSYEJ887HSYY}", - "recDate": "1970-08-21Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Vassotea", - "page_num": "81", - "dates": "", - "end": 277, - "acd_pref_name": "enalapril", - "spellcheck_val": "Vasotec", - "relevant": true, - "partial_date": "12/09/****", - "sorted_date": "1999-10-27Z", - "dbq_type": "" - }, - { - "annot_type": "service", - "annot_name": "", - "annot_val": "Republic Of Vietnam", - "page_num": "7", - "dates": "", - "end": 888, - "acd_pref_name": "", - "spellcheck_val": "", - "relevant": false, - "partial_date": "", - "sorted_date": "1999-10-27Z", - "dbq_type": "" - }, - { - "annot_type": "service", - "annot_name": "", - "annot_val": "Vietnam", - "page_num": "9", - "dates": "", - "end": 999, - "acd_pref_name": "", - "spellcheck_val": "", - "relevant": false, - "partial_date": "", - "sorted_date": "1999-10-27Z", - "dbq_type": "" - } - ] - }, - { - "docTypeDescription": "C and P Exam", - "eFolderVersionRefId": "{U76A1A2A-FFFF-EEEE-DDDD-000000000001}", - "recDate": "2023-08-26Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "C and P Exam", - "eFolderVersionRefId": "{U76A1A2A-FFFF-EEEE-DDDD-000000000002}", - "recDate": "2023-09-01Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "VAMC Other Output Reports", - "eFolderVersionRefId": "", - "recDate": "2022-12-23Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "128/55", - "page_num": "0000009", - "dates": "", - "observation_date": "2022-10-16Z", - "end": 292, - "acd_pref_name": "BPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-12-23Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "129/65", - "page_num": "0000021", - "dates": "", - "observation_date": "2022-09-15Z", - "end": 19658, - "acd_pref_name": "BPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-12-23Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-15Z", - "end": 888, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-12-23Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "44", - "dates": "", - "observation_date": "2022-08-16Z", - "end": 9444, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-12-23Z", - "dbq_type": "" - } ] - } - ], - "documentsWithoutAnnotationsChecked": [ - "{U76A1A2A-FFFF-EEEE-DDDD-000000000001}", - "{U76A1A2A-FFFF-EEEE-DDDD-000000000002}" - ] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-377.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-377.json deleted file mode 100644 index ad81a86c3d..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-377.json +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "collectionsId": 377, - "vtrnFileId": "9999377", - "creationDate": "2023-02-28T12:11:53.888Z", - "icn": "mock1012666073V986377", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-378.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-378.json deleted file mode 100644 index f1532d2f56..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-378.json +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "collectionsId": 378, - "vtrnFileId": "9999378", - "creationDate": "2023-02-28T12:11:53.888Z", - "icn": "mock1012666073V986378", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-379.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-379.json deleted file mode 100644 index 2baa99c019..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-379.json +++ /dev/null @@ -1,339 +0,0 @@ -[ - { - "collectionsId": 379, - "vtrnFileId": "099999379", - "creationDate": "2023-02-14T12:11:53.888Z", - "icn": "mock1012666073V986379", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension With partial", - "page_num": "44", - "dates": "", - "end": 14788, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "04/14/****", - "sorted_date": "1999-11-22Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "740", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 866, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Irbesartan-Hydrochlorothiazide", - "page_num": "22", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 889, - "acd_pref_name": "irbesartan", - "spellcheck_val": "irbesartan - hydrochlorothiazide", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "141/92", - "page_num": "83, 86", - "dates": "", - "observation_date": "2022-07-17Z", - "end": 1603, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/93", - "page_num": "576, 753, 878", - "dates": "", - "observation_date": "2022-08-11Z", - "end": 379, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/92", - "page_num": "813", - "dates": "", - "observation_date": "2022-08-21Z", - "end": 1394, - "acd_pref_name": "SystolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "140/95", - "page_num": "42", - "dates": "", - "observation_date": "", - "end": 591, - "acd_pref_name": "BPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "143/88", - "page_num": "823", - "dates": "", - "observation_date": "2022-09-01Z", - "end": 1571, - "acd_pref_name": "DiastolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - }, - { - "docTypeDescription": "Certificate of Release", - "eFolderVersionRefId": "{9YDD999-99456-989898-B5345-HSYEJ887HSYY}", - "recDate": "1970-08-21Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Vassotea", - "page_num": "81", - "dates": "", - "end": 277, - "acd_pref_name": "enalapril", - "spellcheck_val": "Vasotec", - "relevant": true, - "partial_date": "12/09/****", - "sorted_date": "1999-10-27Z", - "dbq_type": "" - }, - { - "annot_type": "service", - "annot_name": "", - "annot_val": "Republic Of Vietnam", - "page_num": "7", - "dates": "", - "end": 888, - "acd_pref_name": "", - "spellcheck_val": "", - "relevant": false, - "partial_date": "", - "sorted_date": "1999-10-27Z", - "dbq_type": "" - }, - { - "annot_type": "service", - "annot_name": "", - "annot_val": "Vietnam", - "page_num": "9", - "dates": "", - "end": 999, - "acd_pref_name": "", - "spellcheck_val": "", - "relevant": false, - "partial_date": "", - "sorted_date": "1999-10-27Z", - "dbq_type": "" - } - ] - }, - { - "docTypeDescription": "C and P Exam", - "eFolderVersionRefId": "{U76A1A2A-FFFF-EEEE-DDDD-000000000001}", - "recDate": "2023-08-26Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "C and P Exam", - "eFolderVersionRefId": "{U76A1A2A-FFFF-EEEE-DDDD-000000000002}", - "recDate": "2023-09-01Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "VAMC Other Output Reports", - "eFolderVersionRefId": "", - "recDate": "2022-12-23Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "128/55", - "page_num": "0000009", - "dates": "", - "observation_date": "2022-10-16Z", - "end": 292, - "acd_pref_name": "BPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-12-23Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "129/65", - "page_num": "0000021", - "dates": "", - "observation_date": "2022-09-15Z", - "end": 19658, - "acd_pref_name": "BPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-12-23Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-15Z", - "end": 888, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-12-23Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "44", - "dates": "", - "observation_date": "2022-08-16Z", - "end": 9444, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-12-23Z", - "dbq_type": "" - } ] - } - ], - "documentsWithoutAnnotationsChecked": [ - "{U76A1A2A-FFFF-EEEE-DDDD-000000000001}", - "{U76A1A2A-FFFF-EEEE-DDDD-000000000002}" - ] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-380.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-380.json deleted file mode 100644 index 35d0ae8eb2..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-380.json +++ /dev/null @@ -1,176 +0,0 @@ -[ - { - "collectionsId": 380, - "vtrnFileId": "9999380", - "creationDate": "2023-02-28T12:11:53.888Z", - "icn": "mock1012666073V986380", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "740", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 866, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Irbesartan-Hydrochlorothiazide", - "page_num": "22", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 889, - "acd_pref_name": "irbesartan", - "spellcheck_val": "irbesartan - hydrochlorothiazide", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "160/100", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "120/92", - "page_num": "83, 86", - "dates": "", - "observation_date": "2022-07-17Z", - "end": 1603, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/77", - "page_num": "576, 753, 878", - "dates": "", - "observation_date": "2022-08-11Z", - "end": 376, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "-/92", - "page_num": "813", - "dates": "", - "observation_date": "2022-08-21Z", - "end": 1394, - "acd_pref_name": "SystolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "143/-", - "page_num": "823", - "dates": "", - "observation_date": "2022-09-01Z", - "end": 1571, - "acd_pref_name": "DiastolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-381.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-381.json deleted file mode 100644 index d842e00601..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-381.json +++ /dev/null @@ -1,162 +0,0 @@ -[ - { - "collectionsId": 381, - "vtrnFileId": "9999381", - "creationDate": "2023-02-28T12:11:53.888Z", - "icn": "mock1012666073V986381", - "documents": [ - { - "docTypeDescription": "VAMC Other Output Reports", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "740", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 866, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Irbesartan-Hydrochlorothiazide", - "page_num": "22", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 889, - "acd_pref_name": "irbesartan", - "spellcheck_val": "irbesartan - hydrochlorothiazide", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "153/115", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-06-20Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "120/92", - "page_num": "83, 86", - "dates": "", - "observation_date": "2022-07-17Z", - "end": 1603, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/77", - "page_num": "576, 753, 878", - "dates": "", - "observation_date": "2022-08-11Z", - "end": 376, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F6}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "167/93", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-11Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-385.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-385.json deleted file mode 100644 index 573bc7b212..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-385.json +++ /dev/null @@ -1,176 +0,0 @@ -[ - { - "collectionsId": 385, - "vtrnFileId": "099999385", - "creationDate": "2023-02-14T12:11:53.888Z", - "icn": "mock1012666073V986385", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "740", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 866, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Irbesartan-Hydrochlorothiazide", - "page_num": "22", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 889, - "acd_pref_name": "irbesartan", - "spellcheck_val": "irbesartan - hydrochlorothiazide", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "141/92", - "page_num": "83, 86", - "dates": "", - "observation_date": "2022-07-17Z", - "end": 1603, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/93", - "page_num": "576, 753, 878", - "dates": "", - "observation_date": "2022-08-11Z", - "end": 376, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/92", - "page_num": "813", - "dates": "", - "observation_date": "2022-08-21Z", - "end": 1394, - "acd_pref_name": "SystolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "143/88", - "page_num": "823", - "dates": "", - "observation_date": "2022-09-01Z", - "end": 1571, - "acd_pref_name": "DiastolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-386.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-386.json deleted file mode 100644 index 467554c7b9..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-386.json +++ /dev/null @@ -1,176 +0,0 @@ -[ - { - "collectionsId": 386, - "vtrnFileId": "099999386", - "creationDate": "2023-02-14T12:11:53.888Z", - "icn": "mock1012666073V986386", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "740", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 866, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Irbesartan-Hydrochlorothiazide", - "page_num": "22", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 889, - "acd_pref_name": "irbesartan", - "spellcheck_val": "irbesartan - hydrochlorothiazide", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "141/92", - "page_num": "83, 86", - "dates": "", - "observation_date": "2022-07-17Z", - "end": 1603, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/93", - "page_num": "576, 753, 878", - "dates": "", - "observation_date": "2022-08-11Z", - "end": 376, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/92", - "page_num": "813", - "dates": "", - "observation_date": "2022-08-21Z", - "end": 1394, - "acd_pref_name": "SystolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "143/88", - "page_num": "823", - "dates": "", - "observation_date": "2022-09-01Z", - "end": 1571, - "acd_pref_name": "DiastolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-390.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-390.json deleted file mode 100644 index 8e9bfab896..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-390.json +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "collectionsId": 390, - "vtrnFileId": "9999390", - "creationDate": "2023-02-28T12:11:53.888Z", - "icn": "mock1012666073V986390", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-391.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-391.json deleted file mode 100644 index da77c415b9..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-391.json +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "collectionsId": 391, - "vtrnFileId": "9999391", - "creationDate": "2023-02-28T12:11:53.888Z", - "icn": "mock1012666073V986391", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-392.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-392.json deleted file mode 100644 index 3238d59a53..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-392.json +++ /dev/null @@ -1,176 +0,0 @@ -[ - { - "collectionsId": 392, - "vtrnFileId": "9999392", - "creationDate": "2023-02-28T12:11:53.888Z", - "icn": "mock1012666073V986392", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - }, - { - "docTypeDescription": "Medical Treatment Record - Government Facility", - "eFolderVersionRefId": "{2853EB8D-D2BB-4AA1-B8DF-55EB0E7DE1F5}", - "recDate": "2022-09-25Z", - "condition": "Hypertension", - "annotations": [ - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Hypertension", - "page_num": "2, 3", - "dates": "", - "observation_date": "2022-05-27Z", - "end": 631, - "acd_pref_name": "hyper-tension", - "spellcheck_val": "Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medical_condition", - "annot_name": "", - "annot_val": "Essential Hypertension", - "page_num": "52", - "dates": "", - "observation_date": "2022-08-30Z", - "end": 548, - "acd_pref_name": "primary hyper-tension", - "spellcheck_val": "Essential Hypertension", - "relevant": false, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "33", - "dates": "", - "observation_date": "2022-08-09Z", - "end": 704, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Losartan", - "page_num": "740", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 866, - "acd_pref_name": "losartan", - "spellcheck_val": "losartan", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "medication", - "annot_name": "", - "annot_val": "Irbesartan-Hydrochlorothiazide", - "page_num": "22", - "dates": "", - "observation_date": "2022-08-31Z", - "end": 889, - "acd_pref_name": "irbesartan", - "spellcheck_val": "irbesartan - hydrochlorothiazide", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "155/90", - "page_num": "18, 41", - "dates": "", - "observation_date": "2022-05-21Z", - "end": 750, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "141/92", - "page_num": "83, 86", - "dates": "", - "observation_date": "2022-07-17Z", - "end": 1603, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/93", - "page_num": "576, 753, 878", - "dates": "", - "observation_date": "2022-08-11Z", - "end": 376, - "acd_pref_name": "SystolicDiastolicBP", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "139/92", - "page_num": "813", - "dates": "", - "observation_date": "2022-08-21Z", - "end": 1394, - "acd_pref_name": "SystolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - }, - { - "annot_type": "blood_pressure", - "annot_name": "BP", - "annot_val": "143/88", - "page_num": "823", - "dates": "", - "observation_date": "2022-09-01Z", - "end": 1571, - "acd_pref_name": "DiastolicBPReading", - "spellcheck_val": "", - "relevant": true, - "partial_date": "", - "sorted_date": "2022-09-25Z", - "dbq_type": "" - } - ] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-400.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-400.json deleted file mode 100644 index 2873471397..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-400.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "collectionsId": 400, - "vtrnFileId": "9999400", - "creationDate": "2023-02-28T12:11:53.888Z", - "icn": "mock1012666073V986400", - "documents": [], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-401.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-401.json deleted file mode 100644 index 45904c62ca..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-401.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "collectionsId": 401, - "vtrnFileId": "9999400", - "creationDate": "2023-02-28T12:11:53.888Z", - "icn": "mock1012666073V986401", - "documents": [], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-500.json b/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-500.json deleted file mode 100644 index 5e34166c5e..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/annotations/collection-500.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "collectionsId": 500, - "vtrnFileId": "099999500", - "creationDate": "2023-02-22T16:11:53.888Z", - "icn": "9000682", - "documents": [ - { - "docTypeDescription": "STR - Dental", - "eFolderVersionRefId": "{XXXXXX643-YTE8-763G-ABT5-DGDGDTYEGDD76}", - "recDate": "2022-04-23Z", - "condition": "Hypertension", - "annotations": [] - } - ], - "documentsWithoutAnnotationsChecked": [] - } -] diff --git a/domain-rrd/mock-mas-api/src/main/resources/application.yml b/domain-rrd/mock-mas-api/src/main/resources/application.yml deleted file mode 100644 index c00b524724..0000000000 --- a/domain-rrd/mock-mas-api/src/main/resources/application.yml +++ /dev/null @@ -1,44 +0,0 @@ -# spring settings -spring: - profiles: - active: ${ENV:default} - -# server settings -server: - port: 20400 - -# Health -management: - server: - port: 20401 - ssl.enabled: false - endpoint: - health: - show-details: always - enabled: true - probes: - enabled: true - group: - readiness: - include: readinessState - liveness: - include: livenessState - endpoints: - enabled-by-default: false - web: - exposure: - include: health - -# mock mas application specific -mock-mas: - mas-oauth2: - token-uri: "${MAS_API_AUTH_TOKEN_URI:https://viccs-api-dev.ibm-intelligent-automation.com/pca/api/dev/token}" - client-id: "${MAS_API_AUTH_CLIENTID:vro_dev}" - client-secret: "${MAS_API_AUTH_CLIENT_SECRET}" - scope: "${MAS_API_AUTH_SCOPE:openid}" - grant-type: client_credentials - mas-api: - base-url: "${MAS_API_BASE_URL:https://viccs-api-dev.ibm-intelligent-automation.com/pca/api/dev}" - collection-annots-path: "${MAS_COLLECTION_ANNOTS_PATH:/pcQueryCollectionAnnots}" - collection-status-path: "${MAS_COLLECTION_STATUS_PATH:/pcCheckCollectionStatus}" - create-exam-order-path: "${MAS_CREATE_EXAM_ORDER_PATH:/pcOrderExam}" diff --git a/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/CollectionsAnnotsTest.java b/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/CollectionsAnnotsTest.java deleted file mode 100644 index 920b1b6a9b..0000000000 --- a/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/CollectionsAnnotsTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package gov.va.vro.mockmas; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import gov.va.vro.mockmas.config.MasApiProperties; -import gov.va.vro.mockmas.config.MasOauth2Properties; -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import gov.va.vro.model.rrd.mas.request.MasCollectionAnnotationRequest; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.server.LocalServerPort; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.web.client.RestTemplate; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@Slf4j -@ActiveProfiles("test") -@EnableConfigurationProperties({MasApiProperties.class, MasOauth2Properties.class}) -public class CollectionsAnnotsTest { - @LocalServerPort private int port; - - @Autowired private RestTemplate template; - - @Autowired private MasApiProperties apiProperties; - - private void sanityCheck(int collectionId, int collectionLength, int documentSize) { - String url = "http://localhost:" + port + apiProperties.getCollectionAnnotsPath(); - MasCollectionAnnotationRequest request = new MasCollectionAnnotationRequest(); - request.setCollectionsId(collectionId); - - ResponseEntity response = - template.postForEntity(url, request, MasCollectionAnnotation[].class); - MasCollectionAnnotation[] body = response.getBody(); - - assertEquals(collectionLength, body.length); - - MasCollectionAnnotation collection = body[0]; - assertEquals(documentSize, collection.getDocuments().size()); - } - - @Test - void collection375Test() { - sanityCheck(375, 1, 2); - } -} diff --git a/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/FieldCheckTest.java b/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/FieldCheckTest.java deleted file mode 100644 index dbb09a0cd9..0000000000 --- a/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/FieldCheckTest.java +++ /dev/null @@ -1,89 +0,0 @@ -package gov.va.vro.mockmas; - -import gov.va.vro.mockmas.config.MasApiProperties; -import gov.va.vro.mockmas.config.MasApiService; -import gov.va.vro.mockmas.config.MasOauth2Properties; -import gov.va.vro.model.rrd.mas.MasAnnotation; -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import gov.va.vro.model.rrd.mas.MasDocument; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -import java.util.List; - -/** - * For now checks for incomplete blood pressure with plans to extends to other fields. To use change - * mcp-mas properties in application-test.yml to point to your environment values (i.e. prod-test), - * uncomment @Test, and update for collection ids you want to check. Once it is run search for - * "Incomplete reading" tp see the incomplete reading. - */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@Slf4j -@ActiveProfiles("test") -@EnableConfigurationProperties({MasApiProperties.class, MasOauth2Properties.class}) -public class FieldCheckTest { - private static final String BP_READING_REGEX = "^\\d{1,3}\\/\\d{1,3}$"; - - @Autowired private MasApiService apiService; - - void checkBloodPressure(List collections) { - for (MasCollectionAnnotation collection : collections) { - log.info(String.valueOf(collection.getCollectionsId())); - log.info("==========================================="); - List documents = collection.getDocuments(); - if (documents == null || documents.size() < 1) { - log.info("No document found for {}", collection.getCollectionsId()); - log.info(""); - continue; - } - for (MasDocument document : documents) { - log.info("Document: {}", document.getDocTypeDescription()); - log.info("==================="); - List annotations = document.getAnnotations(); - if (annotations == null || annotations.size() < 1) { - log.info("No annotations found for {}", document.getDocTypeDescription()); - log.info(""); - continue; - } - int bpAnnotationCount = 0; - int bpIncompleteCount = 0; - - for (MasAnnotation annotation : annotations) { - if (!annotation.getAnnotType().equals("blood_pressure")) { - continue; - } - ++bpAnnotationCount; - String value = annotation.getAnnotVal(); - if (value.matches(BP_READING_REGEX)) { - continue; - } - log.info("Incomplete reading: {}", value); - ++bpIncompleteCount; - } - log.info(""); - log.info( - "Total BP Count: {}, incomplete BP Count: {}", bpAnnotationCount, bpIncompleteCount); - } - } - } - - // @Test - void extraordinaryBloodPressures() { - int[] collectionIds = {5745, 5746, 5747, 5748, 5751, 5753, 5754}; - - for (int collectionIndex = 0; collectionIndex < collectionIds.length; ++collectionIndex) { - int collectionId = collectionIds[collectionIndex]; - List collections = apiService.getAnnotation(collectionId); - log.info("******************************************************"); - if (collections == null) { - log.info("Collection {} cannot be found", collectionId); - } else { - checkBloodPressure(collections); - } - log.info("******************************************************"); - } - } -} diff --git a/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/OrderExamTest.java b/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/OrderExamTest.java deleted file mode 100644 index 6e65ac227c..0000000000 --- a/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/OrderExamTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package gov.va.vro.mockmas; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import gov.va.vro.mockmas.config.MasApiProperties; -import gov.va.vro.mockmas.config.MasOauth2Properties; -import gov.va.vro.mockmas.model.OrderExamRequest; -import gov.va.vro.mockmas.model.OrderExamResponse; -import gov.va.vro.mockmas.model.OrderExamSuccess; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.server.LocalServerPort; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.web.client.RestTemplate; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@Slf4j -@ActiveProfiles("test") -@EnableConfigurationProperties({MasApiProperties.class, MasOauth2Properties.class}) -public class OrderExamTest { - @LocalServerPort private int port; - - @Autowired private RestTemplate template; - - @Autowired private MasApiProperties apiProperties; - - private void sanityCheck(int collectionId, int collectionLength, int documentSize) {} - - @Test - void orderExam375Test() { - String url = "http://localhost:" + port + apiProperties.getCreateExamOrderPath(); - OrderExamRequest request = new OrderExamRequest(); - request.setCollectionsId(375); - - ResponseEntity response = - template.postForEntity(url, request, OrderExamResponse.class); - OrderExamResponse body = response.getBody(); - OrderExamSuccess success = body.getSuccess(); - - assertEquals(375, success.getCollectionsId()); - } -} diff --git a/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/config/MasApiServiceTest.java b/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/config/MasApiServiceTest.java deleted file mode 100644 index e6d9ff040a..0000000000 --- a/domain-rrd/mock-mas-api/src/test/java/gov/va/vro/mockmas/config/MasApiServiceTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package gov.va.vro.mockmas.config; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -import java.util.List; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@Slf4j -@ActiveProfiles("test") -@EnableConfigurationProperties({MasApiProperties.class, MasOauth2Properties.class}) -public class MasApiServiceTest { - @Autowired private MasApiService apiService; - - @Autowired private MasOauth2Properties oauth2Properties; - - // @Test - void retrieveAnnotation350() { - if (oauth2Properties.getClientSecret() == null) { - return; // ignore when client secret is not available (scripts/setenv.sh has not been run) - } - List annotations = apiService.getAnnotation(350); - // Sanity check if this is the record from the dev server - assertNotNull(annotations); - assertEquals(2, annotations.size()); - assertEquals(34, annotations.get(0).getDocuments().size()); - } - - // @Test - void orderExam350() { - if (oauth2Properties.getClientSecret() == null) { - return; // ignore when client secret is not available (scripts/setenv.sh has not been run) - } - // OrderExamResponse response = apiService.orderExam(350); - } -} diff --git a/domain-rrd/mock-mas-api/src/test/resources/application-test.yml b/domain-rrd/mock-mas-api/src/test/resources/application-test.yml deleted file mode 100644 index e7a412e3d0..0000000000 --- a/domain-rrd/mock-mas-api/src/test/resources/application-test.yml +++ /dev/null @@ -1,4 +0,0 @@ -## Logging -logging: - level: - root: INFO diff --git a/domain-rrd/rrd-api-controller/build.gradle.bak b/domain-rrd/rrd-api-controller/build.gradle.bak deleted file mode 100644 index c72b98631b..0000000000 --- a/domain-rrd/rrd-api-controller/build.gradle.bak +++ /dev/null @@ -1,22 +0,0 @@ - -plugins { - id 'local.std.java.library-spring-conventions' -} - -dependencies { - implementation project(':domain-rrd:rrd-shared') - - // TODO: api-controller should not be dependent directly on services - implementation project(':domain-rrd:rrd-workflows') - - implementation "org.springdoc:springdoc-openapi-starter-webmvc-api:${spring_doc_version}" - implementation 'io.micrometer:micrometer-core' - - //MAS oAuth2 webclient libs - implementation "org.springframework.boot:spring-boot-starter-webflux:${sb_webflux}" - implementation "org.springframework.security:spring-security-oauth2-client:${spring_security_version}" - implementation "org.springframework.boot:spring-boot-starter-security:${sb_security}" - - // https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api - compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1' -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/model/ClaimInfo.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/model/ClaimInfo.java deleted file mode 100644 index 4002e1ab64..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/model/ClaimInfo.java +++ /dev/null @@ -1,27 +0,0 @@ -package gov.va.vro.api.rrd.model; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; - -import java.util.List; -import java.util.Map; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -@Builder -@ToString -public class ClaimInfo { - String claimSubmissionId; - String veteranIcn; - int contentionsCount; - int assessmentResultsCount; - int evidenceSummaryDocumentsCount; - List contentions; - Map evidenceSummary; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/model/ClaimProcessingException.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/model/ClaimProcessingException.java deleted file mode 100644 index 9329d93a37..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/model/ClaimProcessingException.java +++ /dev/null @@ -1,55 +0,0 @@ -package gov.va.vro.api.rrd.model; - -import lombok.Getter; -import org.springframework.http.HttpStatus; - -public class ClaimProcessingException extends Exception { - - @Getter private final String claimSubmissionId; - @Getter private final HttpStatus httpStatus; - - /*** - *

Summary.

- * - * @param claimSubmissionId claim submission ID - * @param httpStatus HTTP Status - * @param message message - */ - public ClaimProcessingException(String claimSubmissionId, HttpStatus httpStatus, String message) { - super(message); - this.claimSubmissionId = claimSubmissionId; - this.httpStatus = httpStatus; - } - - /*** - *

Summary.

- * - * @param claimSubmissionId claim submission id - * - * @param httpStatus http status - * - * @param exception exception - */ - public ClaimProcessingException( - String claimSubmissionId, HttpStatus httpStatus, Exception exception) { - super(exception); - this.claimSubmissionId = claimSubmissionId; - this.httpStatus = httpStatus; - } - - /*** - *

Summary.

- * - * @return returns the message - */ - public String getOriginalMessage() { - Throwable exception = super.getCause(); - if (exception == null) { - return this.getMessage(); - } - if (exception.getCause() == null) { - return exception.getMessage(); - } - return exception.getCause().getMessage(); - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/requests/FetchPdfRequest.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/requests/FetchPdfRequest.java deleted file mode 100644 index f46ba633f3..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/requests/FetchPdfRequest.java +++ /dev/null @@ -1,22 +0,0 @@ -package gov.va.vro.api.rrd.requests; - -import com.fasterxml.jackson.annotation.JsonCreator; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; - -import javax.validation.constraints.NotBlank; - -@Builder -@Getter -@Schema(name = "FetchPdfRequest", description = "Details for fetching generated pdf") -public class FetchPdfRequest { - @NotBlank - @Schema(description = "Claim submission ID", example = "1234") - private String claimSubmissionId; - - @JsonCreator - public FetchPdfRequest(String claimSubmissionId) { - this.claimSubmissionId = claimSubmissionId; - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/requests/GeneratePdfRequest.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/requests/GeneratePdfRequest.java deleted file mode 100644 index 5a376eba4a..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/requests/GeneratePdfRequest.java +++ /dev/null @@ -1,52 +0,0 @@ -package gov.va.vro.api.rrd.requests; - -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.VeteranInfo; -import gov.va.vro.model.rrd.mas.ClaimCondition; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import lombok.Setter; -import org.springframework.lang.Nullable; - -import java.util.List; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -@AllArgsConstructor -@NoArgsConstructor -@Getter -@Setter -@Schema(name = "GeneratePdfRequest", description = "Details for pdf generation") -public class GeneratePdfRequest { - @NotBlank - @Schema(description = "Claim submission ID", example = "1234") - private String claimSubmissionId; - - @NotBlank - @Schema(description = "Diagnostic code", example = "7101") - private String diagnosticCode; - - @NotNull - @Schema(description = "Veteran data for the pdf") - private VeteranInfo veteranInfo; - - @Nullable - @Schema(description = "Veteran file identifier", example = "12345") - private String veteranFileId; - - private ClaimCondition conditions; - - @NonNull - @Schema(description = "Medical evidence supporting assessment") - private AbdEvidence evidence; - - @Nullable - @Schema(description = "PDF template to generate", example = "v1") - private String pdfTemplate; - - @Schema(description = "Documents unavailable for automated review") - private List documentsWithoutAnnotationsChecked; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/requests/HealthDataAssessmentRequest.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/requests/HealthDataAssessmentRequest.java deleted file mode 100644 index 156ce070d3..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/requests/HealthDataAssessmentRequest.java +++ /dev/null @@ -1,36 +0,0 @@ -package gov.va.vro.api.rrd.requests; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import javax.validation.constraints.NotBlank; - -@AllArgsConstructor -@NoArgsConstructor -@Getter -@Setter -@Schema( - name = "HealthDataAssessmentRequest", - description = "Claim details for the health data assessment") -public class HealthDataAssessmentRequest { - @NotBlank(message = "Veteran Icn cannot be empty") - @Schema(description = "Veteran medical internal control number (EHR id)", example = "9000682") - private String veteranIcn; - - @NotBlank(message = "Diagnostic code cannot be empty") - @Schema(description = "Diagnostic code for the claim contention", example = "7101") - private String diagnosticCode; - - @NotBlank(message = "Claim submission id cannot be empty") - @Schema(description = "Claim submission id", example = "1234") - private String claimSubmissionId; - - @Schema(description = "MAS", example = "NEW") - private String disabilityActionType; - - @Schema(description = "Date of the Claim") - private String claimSubmissionDateTime; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/ClaimMetricsResource.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/ClaimMetricsResource.java deleted file mode 100644 index 01208bff21..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/ClaimMetricsResource.java +++ /dev/null @@ -1,190 +0,0 @@ -package gov.va.vro.api.rrd.resources; - -import gov.va.vro.api.rrd.model.ClaimProcessingException; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimInfoResponse; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimMetricsResponse; -import gov.va.vro.model.rrd.claimmetrics.response.ExamOrderInfoResponse; -import io.micrometer.core.annotation.Timed; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn; -import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import io.swagger.v3.oas.annotations.security.SecurityScheme; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; - -import java.util.List; -import javax.validation.constraints.Min; - -@RequestMapping(value = "/v2", produces = "application/json") -@SecurityRequirement(name = "X-API-Key") -@SecurityScheme(name = "X-API-Key", type = SecuritySchemeType.APIKEY, in = SecuritySchemeIn.HEADER) -@Timed -public interface ClaimMetricsResource { - @Operation( - summary = "Retrieves metrics on the previously processed claims", - description = "This endpoint retrieves metrics on the previously processed claims.") - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "Successful"), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "Internal service error", - content = @Content(schema = @Schema(hidden = true))) - }) - @GetMapping("/claim-metrics") - @ResponseStatus(HttpStatus.OK) - @Timed(value = "claim-metrics") - @Tag(name = "Claim Metrics") - ResponseEntity claimMetrics(); - - @Operation( - summary = "Retrieves claim specific information.", - description = - "Retrieves metrics for the specified claim. Defaults to claims from MAS ('v2'). Specify" - + " the claim's endpoint version ('v1' or 'v2') for claims submitted to that" - + "endpoint version.") - @GetMapping(value = "/claim-info/{claimSubmissionId}") - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "Successful"), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "404", - description = "Not found", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "Internal service error", - content = @Content(schema = @Schema(hidden = true))) - }) - @ResponseStatus(HttpStatus.OK) - @Timed(value = "claim-info-claim-id") - @Tag(name = "Claim Metrics") - @ResponseBody - ResponseEntity claimInfoForClaimId( - @PathVariable String claimSubmissionId, @RequestParam(required = false) String claimVersion) - throws ClaimProcessingException; - - @Operation( - summary = "Retrieves claim specific metrics for all claims.", - description = "This endpoint retrieves claim specific metrics for all claims page by page.") - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "Successful"), - @ApiResponse( - responseCode = "400", - description = "Bad Request", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "Internal service error", - content = @Content(schema = @Schema(hidden = true))) - }) - @ResponseStatus(HttpStatus.OK) - @Timed(value = "claim-info") - @Tag(name = "Claim Metrics") - @RequestMapping(value = "/claim-info", method = RequestMethod.GET) - @ResponseBody - ResponseEntity> claimInfoForAll( - @RequestParam(name = "page", required = false, defaultValue = "0") - @Min(value = 0, message = "invalid page number") - Integer page, - @RequestParam(name = "size", required = false, defaultValue = "10") - @Min(value = 1, message = "invalid size") - Integer size, - @RequestParam(name = "icn", required = false) String icn); - - @Operation( - summary = "Retrieves all exam order records", - description = "This endpoint retrieves exam order metrics for all entries page by page.") - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "Successful"), - @ApiResponse( - responseCode = "400", - description = "Bad Request", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "Internal service error", - content = @Content(schema = @Schema(hidden = true))) - }) - @ResponseStatus(HttpStatus.OK) - @Timed(value = "exam-order-info") - @Tag(name = "Claim Metrics") - @RequestMapping(value = "/exam-order-info", method = RequestMethod.GET) - @ResponseBody - ResponseEntity> allExamOrderInfo( - @RequestParam(name = "page", required = false, defaultValue = "0") - @Min(value = 0, message = "invalid page number") - Integer page, - @RequestParam(name = "size", required = false, defaultValue = "10") - @Min(value = 1, message = "invalid size") - Integer size, - @RequestParam(name = "notOrdered", required = false, defaultValue = "False") - Boolean notOrdered); - - @Operation( - summary = - "Slacks all exam order records that have not been processed by MAS and are at least 24 hours old", - description = "Slacks the list of exam orders that have not been processed.") - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "Successful"), - @ApiResponse( - responseCode = "400", - description = "Bad Request", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "Internal service error", - content = @Content(schema = @Schema(hidden = true))) - }) - @ResponseStatus(HttpStatus.OK) - @Timed(value = "exam-order-slack") - @Tag(name = "Claim Metrics") - @RequestMapping(value = "/exam-order-slack", method = RequestMethod.POST) - @ResponseBody - ResponseEntity> examOrderSlack( - @RequestParam(name = "page", required = false, defaultValue = "0") - @Min(value = 0, message = "invalid page number") - Integer page, - @RequestParam(name = "size", required = false, defaultValue = "10") - @Min(value = 1, message = "invalid size") - Integer size, - @RequestParam(name = "notOrdered", required = false, defaultValue = "False") - Boolean notOrdered) - throws ClaimProcessingException; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/MasResource.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/MasResource.java deleted file mode 100644 index 48374159b6..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/MasResource.java +++ /dev/null @@ -1,118 +0,0 @@ -package gov.va.vro.api.rrd.resources; - -import gov.va.vro.api.rrd.responses.MasResponse; -import gov.va.vro.model.rrd.mas.MasExamOrderStatusPayload; -import gov.va.vro.model.rrd.mas.request.MasAutomatedClaimRequest; -import io.micrometer.core.annotation.Timed; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn; -import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import io.swagger.v3.oas.annotations.security.SecurityScheme; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseStatus; - -import javax.validation.Valid; - -@RequestMapping(value = "/v2", produces = "application/json") -@SecurityRequirement(name = "Bearer Authentication") -@SecurityScheme( - name = "Bearer Authentication", - type = SecuritySchemeType.HTTP, - bearerFormat = "JWT", - scheme = "bearer", - in = SecuritySchemeIn.HEADER) -@Timed -public interface MasResource { - - @Operation( - summary = "MAS Claim Request", - description = - "Receives an initial request for a MAS claim and starts collecting the evidence") - @PostMapping("/automatedClaim") - @ResponseStatus(HttpStatus.CREATED) - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "Successful Request"), - @ApiResponse( - responseCode = "400", - description = "Bad Request", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "404", - description = "Resource Not Found", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "422", - description = "Bad Claim", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "Data Access Server Error", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "503", - description = "BIP Service Error", - content = @Content(schema = @Schema(hidden = true))) - }) - @Timed(value = "mas-automated-claim") - @Tag(name = "MAS Integration") - ResponseEntity automatedClaim( - @Parameter( - description = "Request a MAS Automated Claim", - required = true, - schema = @Schema(implementation = MasAutomatedClaimRequest.class)) - @Valid - @RequestBody - MasAutomatedClaimRequest request); - - @Operation( - summary = "MAS Exam Ordering Status", - description = "Request Ordering Status for an exam") - @PostMapping("/examOrderingStatus") - @ResponseStatus(HttpStatus.CREATED) - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "Successful Request"), - @ApiResponse( - responseCode = "400", - description = "Bad Request", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "422", - description = "Bad Claim", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "Data Access Server Error", - content = @Content(schema = @Schema(hidden = true))) - }) - @Timed(value = "exam-ordering-status") - @Tag(name = "MAS Integration") - ResponseEntity examOrderingStatus( - @Parameter( - description = "Request Exam ordering status", - required = true, - schema = @Schema(implementation = MasExamOrderStatusPayload.class)) - @Valid - @RequestBody - MasExamOrderStatusPayload payload); -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/VerificationResource.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/VerificationResource.java deleted file mode 100644 index d5de060d3d..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/VerificationResource.java +++ /dev/null @@ -1,50 +0,0 @@ -package gov.va.vro.api.rrd.resources; - -import gov.va.vro.api.rrd.responses.BipVerificationResponse; -import io.micrometer.core.annotation.Timed; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn; -import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import io.swagger.v3.oas.annotations.security.SecurityScheme; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseStatus; - -@RequestMapping(value = "/v2", produces = "application/json") -@SecurityRequirement(name = "X-API-Key") -@SecurityScheme(name = "X-API-Key", type = SecuritySchemeType.APIKEY, in = SecuritySchemeIn.HEADER) -@Timed -public interface VerificationResource { - @Operation( - summary = "Executes BIP connectivity verification queries.", - description = - """ - This end-point calls un-consequential GET end-points in BIP Claims and - BIP Claim Evidence APIs to test connectivity. - """) - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "Successful"), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "Internal service error", - content = @Content(schema = @Schema(hidden = true))) - }) - @GetMapping("/bip-verification-test") - @ResponseStatus(HttpStatus.OK) - @Timed(value = "bip-verification-test") - @Tag(name = "Verification Test") - ResponseEntity bipVerificationTest(); -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/VroResource.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/VroResource.java deleted file mode 100644 index c3e2f48cd3..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/resources/VroResource.java +++ /dev/null @@ -1,188 +0,0 @@ -package gov.va.vro.api.rrd.resources; - -import gov.va.vro.api.rrd.model.ClaimProcessingException; -import gov.va.vro.api.rrd.requests.GeneratePdfRequest; -import gov.va.vro.api.rrd.requests.HealthDataAssessmentRequest; -import gov.va.vro.api.rrd.responses.FullHealthDataAssessmentResponse; -import gov.va.vro.api.rrd.responses.GeneratePdfResponse; -import io.micrometer.core.annotation.Timed; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn; -import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.ExampleObject; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import io.swagger.v3.oas.annotations.security.SecurityScheme; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseStatus; - -import javax.validation.Valid; - -@RequestMapping(value = "/v1", produces = "application/json") -@SecurityRequirement(name = "X-API-Key") -@SecurityScheme(name = "X-API-Key", type = SecuritySchemeType.APIKEY, in = SecuritySchemeIn.HEADER) -@Timed -public interface VroResource { - @Operation( - summary = "Generates Evidence PDF", - description = - "This endpoint generates the Evidence PDF for a specific patient and a diagnostic " - + "code. The evidence pdf will be available from 'GET evidence-pdf' endpoint " - + "using claim submission id.") - @PostMapping("/evidence-pdf") - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "Successful Request"), - @ApiResponse( - responseCode = "400", - description = "Bad Request", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "PDF Generator Server Error", - content = @Content(schema = @Schema(hidden = true))) - }) - @Timed(value = "evidence-pdf") - @Tag(name = "Pdf Generation") - ResponseEntity generatePdf( - @Parameter( - description = "metadata for generatePdf", - required = true, - schema = @Schema(implementation = GeneratePdfRequest.class)) - @Valid - @RequestBody - GeneratePdfRequest request) - throws MethodArgumentNotValidException, ClaimProcessingException; - - @Operation( - summary = "Downloads the generated Evidence PDF", - description = - "This endpoint downloads the Evidence PDF previously generated by the " - + "'POST evidence-pdf' endpoint. " - + "The Evidence PDF is identified by the claim submission id.") - @GetMapping( - value = "/evidence-pdf/{claimSubmissionId}", - produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_PDF_VALUE}) - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "Successful Request"), - @ApiResponse( - responseCode = "400", - description = "Bad Request", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "PDF Generator Server Error", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "PDF generation for specified claimSubmissionID not requested", - content = @Content(schema = @Schema(hidden = true))) - }) - @Timed(value = "evidence-pdf") - @Tag(name = "Pdf Generation") - ResponseEntity fetchPdf(@PathVariable String claimSubmissionId) - throws MethodArgumentNotValidException, ClaimProcessingException; - - @Operation( - summary = "Immediate PDF", - description = - "This endpoint generates the Evidence PDF for a specific patient and a diagnostic " - + "code. The endpoint will return the PDF but is also available from the " - + "'GET evidence-pdf' endpoint using claim submission id.") - @PostMapping("/immediate-pdf") - @ApiResponses( - value = { - @ApiResponse(responseCode = "200", description = "Successful Request"), - @ApiResponse( - responseCode = "400", - description = "Bad Request", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "PDF Generator Server Error", - content = @Content(schema = @Schema(hidden = true))) - }) - @Timed(value = "evidence-pdf") - @Tag(name = "Pdf Generation") - ResponseEntity immediatePdf( - @Parameter( - description = "metadata for immediatePdf", - required = true, - schema = @Schema(implementation = GeneratePdfRequest.class)) - @Valid - @RequestBody - GeneratePdfRequest request) - throws MethodArgumentNotValidException, ClaimProcessingException; - - @Operation( - summary = "Provides health data assessment", - description = - "This endpoint provides health data assessment for a Veteran claim " - + "in the form of patient medical data relevant to the specific diagnostic code. " - + "This endpoint only provides a health assessment for v1 claims. To see a health" - + " assessment for v2 claims, please try the v2/health-data-assessment endpoint.") - @PostMapping("/full-health-data-assessment") - @ResponseStatus(HttpStatus.CREATED) - @ApiResponses( - value = { - @ApiResponse(responseCode = "201", description = "Successful Request"), - @ApiResponse( - responseCode = "400", - description = "Bad Request", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "401", - description = "Unauthorized", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "Claim Processing Server Error", - content = @Content(schema = @Schema(hidden = true))), - @ApiResponse( - responseCode = "500", - description = "No evidence found", - content = - @Content( - mediaType = "application/json", - examples = - @ExampleObject( - value = "{claimSubmissionId: 1234, message = No evidence found}"))) - }) - @Timed(value = "full-health-data-assessment") - @Tag(name = "Full Health Assessment") - ResponseEntity postFullHealthAssessment( - @Parameter( - description = "Claim for which health data assessment requested", - required = true, - schema = @Schema(implementation = HealthDataAssessmentRequest.class)) - @Valid - @RequestBody - HealthDataAssessmentRequest claim) - throws MethodArgumentNotValidException, ClaimProcessingException; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipClaimContentionsResponse.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipClaimContentionsResponse.java deleted file mode 100644 index 623a71907a..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipClaimContentionsResponse.java +++ /dev/null @@ -1,22 +0,0 @@ -package gov.va.vro.api.rrd.responses; - -import gov.va.vro.model.rrd.bip.ClaimContention; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; - -import java.util.List; - -/** - * Bip claim contention response. - * - * @author warren @Date 11/16/22 - */ -@Builder -@Getter -@Schema(name = "BIPClaimContentionsResponse", description = "A list of contentions for a claim.") -public class BipClaimContentionsResponse { - private long claimId; - private List contentions; - private String message; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipClaimResponse.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipClaimResponse.java deleted file mode 100644 index 0cdfbb435d..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipClaimResponse.java +++ /dev/null @@ -1,20 +0,0 @@ -package gov.va.vro.api.rrd.responses; - -import gov.va.vro.model.rrd.bip.BipClaim; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; - -/** - * A claim information object. - * - * @author warren @Date 11/16/22 - */ -@Builder -@Getter -@Schema(name = "BIPClaimResponse", description = "Claim information") -public class BipClaimResponse { // TODO: refactor the code to include needed fields. - private long claimId; - private String message; - private BipClaim claim; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipClaimStatusResponse.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipClaimStatusResponse.java deleted file mode 100644 index 53538c662b..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipClaimStatusResponse.java +++ /dev/null @@ -1,20 +0,0 @@ -package gov.va.vro.api.rrd.responses; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; - -/** - * Bip claim status response. - * - * @author warren @Date 11/7/22 - */ -@Builder -@Getter -@Schema( - name = "BIPClaimStatusResponse", - description = "Indicate that the claim status has been updated") -public class BipClaimStatusResponse { - private boolean updated; - private String message; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipContentionCreationResponse.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipContentionCreationResponse.java deleted file mode 100644 index 95eb5b3193..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipContentionCreationResponse.java +++ /dev/null @@ -1,22 +0,0 @@ -package gov.va.vro.api.rrd.responses; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; - -/** - * Bip contention creation response. - * - * @author warren @Date 11/16/22 - */ -@Builder -@Getter -@Schema( - name = "BipContentionCreationResponse", - description = "Indicate that the claim contention has been created or not") -public class BipContentionCreationResponse { - private boolean created; - private long claimId; - private long contentionId; - private String message; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipContentionUpdateResponse.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipContentionUpdateResponse.java deleted file mode 100644 index 73a7089e48..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipContentionUpdateResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package gov.va.vro.api.rrd.responses; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; - -/** - * Bip contention update response. - * - * @author warren @Date 11/16/22 - */ -@Builder -@Getter -@Schema( - name = "BipContentionUpdateResponse", - description = "Indicate that the claim contention has been updated") -public class BipContentionUpdateResponse { - private boolean updated; - private long contentionId; - private String message; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipFileUploadResponse.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipFileUploadResponse.java deleted file mode 100644 index 8127c75e13..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipFileUploadResponse.java +++ /dev/null @@ -1,22 +0,0 @@ -package gov.va.vro.api.rrd.responses; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; - -/** - * Bip file upload response. - * - * @author warren @Date 12/7/22 - */ -@Builder -@Getter -@Setter -@Schema( - name = "BipFileUploadResponse", - description = "Indicate that the claim evidence file upload result.") -public class BipFileUploadResponse { - private boolean uploaded; - private String message; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipVerificationResponse.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipVerificationResponse.java deleted file mode 100644 index abd09a9e21..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/BipVerificationResponse.java +++ /dev/null @@ -1,3 +0,0 @@ -package gov.va.vro.api.rrd.responses; - -public record BipVerificationResponse(boolean verified) {} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/FetchClaimsResponse.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/FetchClaimsResponse.java deleted file mode 100644 index 5b6e71dbcc..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/FetchClaimsResponse.java +++ /dev/null @@ -1,22 +0,0 @@ -package gov.va.vro.api.rrd.responses; - -import gov.va.vro.api.rrd.model.ClaimInfo; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; - -import java.util.List; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -@Builder -@ToString(includeFieldNames = true) -public class FetchClaimsResponse { - private List claims; - private String errorMessage; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/FullHealthDataAssessmentResponse.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/FullHealthDataAssessmentResponse.java deleted file mode 100644 index f2d8f9c0e7..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/FullHealthDataAssessmentResponse.java +++ /dev/null @@ -1,69 +0,0 @@ -package gov.va.vro.api.rrd.responses; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import gov.va.vro.model.rrd.AbdEvidence; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import lombok.Setter; - -import java.util.Map; - -@NoArgsConstructor -@JsonIgnoreProperties(ignoreUnknown = true) -@Getter -@Setter -public class FullHealthDataAssessmentResponse { - @NonNull - @Schema(description = "Veteran medical internal control number (EHR id)", example = "90653535") - private String veteranIcn; - - @NonNull - @Schema(description = "Claim submission id", example = "1234") - private String claimSubmissionId; - - @Schema(description = "Diagnostic code for the claim contention", example = "7101") - private String diagnosticCode; - - @Schema(description = "Medical evidence supporting assessment") - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private AbdEvidence evidence; - - @Schema(description = "Error message in the case of an error") - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private Map errors; - - @Schema(description = "Evidence summary fields") - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private Map evidenceSummary; - - @Schema(description = "Calculated evidence fields") - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private Map calculated; - - @Schema(description = "Decision based on available data") - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private Boolean sufficientForFastTracking; - - @Schema(description = "Date of claim or date of processing if not provided") - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private String claimSubmissionDateTime; - - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private String disabilityActionType; - - /*** - *

Summary.

- * - * @param veteranIcn veteran ICN number - * - * @param diagnosticCode diagnostic code - * - */ - public FullHealthDataAssessmentResponse(String veteranIcn, String diagnosticCode) { - this.veteranIcn = veteranIcn; - this.diagnosticCode = diagnosticCode; - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/GeneratePdfResponse.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/GeneratePdfResponse.java deleted file mode 100644 index 62d201af84..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/GeneratePdfResponse.java +++ /dev/null @@ -1,17 +0,0 @@ -package gov.va.vro.api.rrd.responses; - -import com.fasterxml.jackson.annotation.JsonInclude; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import javax.validation.constraints.NotBlank; - -@Getter -@AllArgsConstructor -@JsonInclude(JsonInclude.Include.NON_EMPTY) -public class GeneratePdfResponse { - - @NotBlank private String claimSubmissionId; - private String status; - private String reason; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/MasResponse.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/MasResponse.java deleted file mode 100644 index 27cc0aaf9c..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/api/rrd/responses/MasResponse.java +++ /dev/null @@ -1,16 +0,0 @@ -package gov.va.vro.api.rrd.responses; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; - -@Builder -@Getter -@Schema( - name = "MASClaimDetailsResponse", - description = "Indicate that the request information has been collected") -public class MasResponse { - - private String id; - private String message; -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasApiConfig.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasApiConfig.java deleted file mode 100644 index 57b14f7648..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasApiConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -package gov.va.vro.config; - -import gov.va.vro.service.provider.MasApiProps; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -// Configure MAS APIs Related Attributes -@Configuration -public class MasApiConfig { - - @Bean - MasApiProps masApiConfigLoad( - @Value("${masAPIProvider.baseURL}") String baseUrl, - @Value("${masAPIProvider.collectionStatusPath}") String collectionStatusPath, - @Value("${masAPIProvider.collectionAnnotsPath}") String collectionAnnotsPath, - @Value("${masAPIProvider.createExamOrderPath}") String createExamOrderPath) { - return new MasApiProps( - baseUrl, collectionStatusPath, collectionAnnotsPath, createExamOrderPath); - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasAuditConfig.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasAuditConfig.java deleted file mode 100644 index 9502934f0b..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasAuditConfig.java +++ /dev/null @@ -1,31 +0,0 @@ -package gov.va.vro.config; - -import gov.va.vro.service.provider.MasConfig; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** Configure mas queues and slack notifications. */ -@Configuration -public class MasAuditConfig { - - @Bean - MasConfig masConfig( - @Value("${mas.processing.initial-delay}") long masProcessingInitialDelay, - @Value("${mas.processing.subsequent-delay}") long masProcessingSubsequentDelay, - @Value("${mas.processing.retry-count}") int masRetryCount, - @Value("${slack.exception.channel:#{null}}") String slackExceptionChannel, - @Value("${slack.exception.webhook:#{null}}") String slackExceptionWebhook) { - var builder = - MasConfig.builder() - .masProcessingInitialDelay(masProcessingInitialDelay) - .masProcessingSubsequentDelay(masProcessingSubsequentDelay) - .masRetryCount(masRetryCount); - if (slackExceptionChannel != null && slackExceptionWebhook != null) { - builder - .slackExceptionChannel(slackExceptionChannel) - .slackExceptionWebhook(slackExceptionWebhook); - } - return builder.build(); - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasOauth2Config.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasOauth2Config.java deleted file mode 100644 index c8470768ce..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasOauth2Config.java +++ /dev/null @@ -1,78 +0,0 @@ -package gov.va.vro.config; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; -import org.springframework.security.oauth2.core.AuthorizationGrantType; -import org.springframework.web.client.RestTemplate; - -@Slf4j -@Configuration -public class MasOauth2Config { - // Created the MAS Authorization Provider Client Registration. - @Bean - ClientRegistration masAuthProviderClientRegistration( - @Value("${spring.security.oauth2.client.provider.mas.uri}") String tokenUri, - @Value("${spring.security.oauth2.client.registration.mas.client-id}") String clientId, - @Value("${spring.security.oauth2.client.registration.mas.client-secret}") String clSecret, - @Value("${spring.security.oauth2.client.registration.mas.scope}") String scope, - @Value("${spring.security.oauth2.client.registration.mas.grant-type}") String grantType) { - return ClientRegistration.withRegistrationId("masAuthProvider") - .tokenUri(tokenUri) - .clientId(clientId) - .clientSecret(clSecret) - .scope(scope) - .authorizationGrantType(new AuthorizationGrantType(grantType)) - .build(); - } - - // Create the client registration repository. - @Bean - public ClientRegistrationRepository clientRegistrationRepository( - ClientRegistration masAuthProviderClientRegistration) { - return new InMemoryClientRegistrationRepository(masAuthProviderClientRegistration); - } - - // Create the authorized client service. - @Bean - public OAuth2AuthorizedClientService auth2AuthorizedClientService( - ClientRegistrationRepository clientRegistrationRepository) { - return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository); - } - - /** - * Create the authorized client manager and service manager using the beans created and - * configured. above - */ - @Bean - public AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientServiceAndManager( - ClientRegistrationRepository clientRegistrationRepository, - OAuth2AuthorizedClientService authorizedClientService) { - - OAuth2AuthorizedClientProvider authorizedClientProvider = - OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials().build(); - - AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = - new AuthorizedClientServiceOAuth2AuthorizedClientManager( - clientRegistrationRepository, authorizedClientService); - authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); - - return authorizedClientManager; - } - - @Bean - @Primary - public RestTemplate restTemplate() { - return new RestTemplate(); - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasVeteranFlashConfig.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasVeteranFlashConfig.java deleted file mode 100644 index b3aa567451..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/config/MasVeteranFlashConfig.java +++ /dev/null @@ -1,17 +0,0 @@ -package gov.va.vro.config; - -import gov.va.vro.model.rrd.mas.MasVeteranFlashProps; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** Configure Veteran Flash IDs. */ -@Configuration -public class MasVeteranFlashConfig { - - @Bean - MasVeteranFlashProps masVeteranFlashConfigLoad( - @Value("${masVeteranFlashIds.agentOrange}") String[] agentOrangeFlashIds) { - return MasVeteranFlashProps.getInstance(agentOrangeFlashIds); - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/ClaimMetricsController.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/ClaimMetricsController.java deleted file mode 100644 index 078fa533cb..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/ClaimMetricsController.java +++ /dev/null @@ -1,121 +0,0 @@ -package gov.va.vro.controller.rrd; - -import gov.va.vro.api.rrd.model.ClaimProcessingException; -import gov.va.vro.api.rrd.resources.ClaimMetricsResource; -import gov.va.vro.model.rrd.claimmetrics.ClaimInfoQueryParams; -import gov.va.vro.model.rrd.claimmetrics.ClaimsInfo; -import gov.va.vro.model.rrd.claimmetrics.ExamOrderInfoQueryParams; -import gov.va.vro.model.rrd.claimmetrics.ExamOrdersInfo; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimInfoResponse; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimMetricsResponse; -import gov.va.vro.model.rrd.claimmetrics.response.ExamOrderInfoResponse; -import gov.va.vro.model.rrd.event.AuditEvent; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.service.provider.CamelEntrance; -import gov.va.vro.service.provider.mas.MasException; -import gov.va.vro.service.spi.model.Claim; -import gov.va.vro.service.spi.services.ClaimMetricsService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; - -@Slf4j -@RestController -@Validated -@RequiredArgsConstructor -public class ClaimMetricsController implements ClaimMetricsResource { - private final ClaimMetricsService claimMetricsService; - - private final CamelEntrance camelEntrance; - - @Override - public ResponseEntity claimMetrics() { - ClaimMetricsResponse response = claimMetricsService.getClaimMetrics(); - return new ResponseEntity<>(response, HttpStatus.OK); - } - - @Override - public ResponseEntity claimInfoForClaimId( - String claimSubmissionId, String claimVersion) throws ClaimProcessingException { - String idType = MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE; - if (claimVersion != null) { - switch (claimVersion) { - case "v1" -> idType = Claim.V1_ID_TYPE; - case "v2" -> idType = MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE; - default -> { - log.warn("Invalid version given to claim info. Must be v1 or v2 if given"); - String msg = HttpStatus.BAD_REQUEST.getReasonPhrase(); - throw new ClaimProcessingException(claimSubmissionId, HttpStatus.BAD_REQUEST, msg); - } - } - } - ClaimInfoResponse response = claimMetricsService.findClaimInfo(claimSubmissionId, idType); - if (response == null) { - log.warn("Claim {} not found", claimSubmissionId); - String msg = HttpStatus.NOT_FOUND.getReasonPhrase(); - throw new ClaimProcessingException(claimSubmissionId, HttpStatus.NOT_FOUND, msg); - } - return new ResponseEntity<>(response, HttpStatus.OK); - } - - @Override - public ResponseEntity> claimInfoForAll( - Integer page, Integer size, String icn) { - ClaimInfoQueryParams params = - ClaimInfoQueryParams.builder().page(page).size(size).icn(icn).build(); - ClaimsInfo claimsInfo = claimMetricsService.findAllClaimInfo(params); - return ResponseEntity.ok(claimsInfo.getClaimInfoList()); - } - - @Override - public ResponseEntity> allExamOrderInfo( - Integer page, Integer size, Boolean notOrdered) { - ExamOrderInfoQueryParams params = - ExamOrderInfoQueryParams.builder().page(page).size(size).notOrdered(notOrdered).build(); - ExamOrdersInfo examOrdersInfo = claimMetricsService.findExamOrderInfo(params); - return ResponseEntity.ok(examOrdersInfo.getExamOrderInfoList()); - } - - @Override - public ResponseEntity> examOrderSlack( - Integer page, Integer size, Boolean notOrdered) throws ClaimProcessingException { - ExamOrderInfoQueryParams params = - ExamOrderInfoQueryParams.builder().page(page).size(size).notOrdered(notOrdered).build(); - ExamOrdersInfo examOrdersInfo = claimMetricsService.findExamOrderInfoOlderThan24(params); - try { - AuditEvent message = - AuditEvent.fromAuditable( - examOrdersInfo, "exam-order-slack", getSlackMessage(examOrdersInfo)); - camelEntrance.examOrderSlack(message); - return ResponseEntity.ok(examOrdersInfo.getExamOrderInfoList()); - } catch (Exception e) { - throw new ClaimProcessingException( - "Error", HttpStatus.INTERNAL_SERVER_ERROR, "Could not slack exam Orders"); - } - } - - private static String getSlackMessage(ExamOrdersInfo exams) { - StringBuilder msg = new StringBuilder(); - if (exams != null) { - for (ExamOrderInfoResponse exam : exams.getExamOrderInfoList()) { - msg.append("[ExamOrder") - .append(" collection ID: ") - .append(exam.getCollectionId()) - .append(" createdAt: ") - .append(exam.getCreatedAt()) - .append(" status: ") - .append(exam.getStatus()) - .append("], "); - } - } else { - log.error("No exam orders were available to slack."); - throw new MasException("No exam orders were available to slack."); - } - return msg.toString(); - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/MasController.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/MasController.java deleted file mode 100644 index 259ac821d2..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/MasController.java +++ /dev/null @@ -1,92 +0,0 @@ -package gov.va.vro.controller.rrd; - -import gov.va.vro.api.rrd.model.ClaimProcessingException; -import gov.va.vro.api.rrd.resources.MasResource; -import gov.va.vro.api.rrd.responses.MasResponse; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.MasExamOrderStatusPayload; -import gov.va.vro.model.rrd.mas.request.MasAutomatedClaimRequest; -import gov.va.vro.service.provider.bip.BipException; -import gov.va.vro.service.provider.mas.service.MasProcessingService; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RestController; - -import java.util.UUID; - -@Slf4j -@RestController -@RequiredArgsConstructor -public class MasController implements MasResource { - - private final MasProcessingService masProcessingService; - - /** Initiate MAS integration. */ - @SneakyThrows - @Override - public ResponseEntity automatedClaim(MasAutomatedClaimRequest request) { - log.info( - "Received MAS automated claim request with collection ID {}", request.getCollectionId()); - String correlationId = UUID.randomUUID().toString(); - var payload = - MasAutomatedClaimPayload.builder() - .claimDetail(request.getClaimDetail()) - .collectionId(request.getCollectionId()) - .correlationId(correlationId) - .firstName(request.getFirstName()) - .gender(request.getGender()) - .lastName(request.getLastName()) - .dateOfBirth(request.getDateOfBirth().replaceAll("Z", "")) - .veteranIdentifiers(request.getVeteranIdentifiers()) - .veteranFlashIds(request.getVeteranFlashIds()) - .build(); - - if (!hasValidClaimId(request)) { - throw new BipException( - HttpStatus.BAD_REQUEST, "The request does not have a valid BenefitClaimId."); - } - log.info( - "MAS collection related claim ID: {}, veteranId (icn): {}", - payload.getBenefitClaimId(), - payload.getVeteranIcn()); // TODO: remove after test. - masProcessingService.processIncomingClaimSaveToDB(payload); - // Any reason here will return a 422 - String message = masProcessingService.processIncomingClaimGetUnprocessableReason(payload); - if (message != null) { - throw new ClaimProcessingException( - payload.getBenefitClaimId(), HttpStatus.UNPROCESSABLE_ENTITY, message); - } - // Only condition in which we will off ramp message or return a valid message - message = masProcessingService.processIncomingClaimPresumptiveOffRampClaimCheck(payload); - MasResponse response = MasResponse.builder().id(correlationId).message(message).build(); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity examOrderingStatus(MasExamOrderStatusPayload payload) { - int collectionId = payload.getCollectionId(); - log.info("Received MAS order status request with collection ID {}", collectionId); - String correlationId = UUID.randomUUID().toString(); - payload.setCorrelationId(correlationId); - masProcessingService.examOrderingStatus(payload, MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - String message = - String.format("Received Exam Order Status for collection Id %d.", collectionId); - MasResponse response = MasResponse.builder().id(correlationId).message(message).build(); - return ResponseEntity.ok(response); - } - - // TODO: Add this test method for now. It'd better add some logic in MasAutomatedClaimRequest. - private boolean hasValidClaimId(MasAutomatedClaimRequest request) { - try { - String claimId = request.getClaimDetail().getBenefitClaimId(); - log.info("claim ID to check: {}", claimId); // TODO: remove after test. - long validId = Long.parseLong(claimId); - return validId > 0L; - } catch (Exception e) { - return false; - } - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/VerificationController.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/VerificationController.java deleted file mode 100644 index 4670b23a88..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/VerificationController.java +++ /dev/null @@ -1,29 +0,0 @@ -package gov.va.vro.controller.rrd; - -import gov.va.vro.api.rrd.resources.VerificationResource; -import gov.va.vro.api.rrd.responses.BipVerificationResponse; -import gov.va.vro.service.provider.bip.service.IBipApiService; -import gov.va.vro.service.provider.bip.service.IBipCeApiService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RestController; - -@Slf4j -@RestController -@Validated -@RequiredArgsConstructor -public class VerificationController implements VerificationResource { - private final IBipApiService bipApiService; - private final IBipCeApiService bipCeApiService; - - @Override - public ResponseEntity bipVerificationTest() { - boolean result = - bipApiService.verifySpecialIssueTypes() && bipCeApiService.verifyDocumentTypes(); - BipVerificationResponse response = new BipVerificationResponse(result); - return new ResponseEntity<>(response, HttpStatus.OK); - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/VroController.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/VroController.java deleted file mode 100644 index 57e8cbedb6..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/VroController.java +++ /dev/null @@ -1,187 +0,0 @@ -package gov.va.vro.controller.rrd; - -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.api.rrd.model.ClaimProcessingException; -import gov.va.vro.api.rrd.requests.GeneratePdfRequest; -import gov.va.vro.api.rrd.requests.HealthDataAssessmentRequest; -import gov.va.vro.api.rrd.resources.VroResource; -import gov.va.vro.api.rrd.responses.FullHealthDataAssessmentResponse; -import gov.va.vro.api.rrd.responses.GeneratePdfResponse; -import gov.va.vro.controller.rrd.mapper.GeneratePdfRequestMapper; -import gov.va.vro.controller.rrd.mapper.PostClaimRequestMapper; -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.model.rrd.mas.response.FetchPdfResponse; -import gov.va.vro.service.provider.CamelEntrance; -import gov.va.vro.service.spi.model.Claim; -import gov.va.vro.service.spi.model.GeneratePdfPayload; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.core.io.InputStreamResource; -import org.springframework.http.ContentDisposition; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RestController; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.Base64; - -@Slf4j -@RestController -@RequiredArgsConstructor -public class VroController implements VroResource { - - private final CamelEntrance camelEntrance; - private final GeneratePdfRequestMapper generatePdfRequestMapper; - private final PostClaimRequestMapper postClaimRequestMapper; - private final ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Fetch PDF and turn it into an HTTP response. - * - * @param claimSubmissionId Claim submission ID - * @param response response - * @return PDF document - * @throws ClaimProcessingException PDF document not found - */ - public ResponseEntity fetchProcess(String claimSubmissionId, String response) - throws ClaimProcessingException { - try { - FetchPdfResponse pdfResponse = objectMapper.readValue(response, FetchPdfResponse.class); - log.info("RESPONSE from fetchPdf returned status: {}", pdfResponse.getStatus()); - if (pdfResponse.hasContent()) { - byte[] decoder = Base64.getDecoder().decode(pdfResponse.getPdfData()); - try (InputStream is = new ByteArrayInputStream(decoder)) { - InputStreamResource resource = new InputStreamResource(is); - String diagnosis = StringUtils.capitalize(pdfResponse.getDiagnosis()); - HttpHeaders headers = getHttpHeaders(diagnosis); - return new ResponseEntity<>(resource, headers, HttpStatus.OK); - } - } else { - if (pdfResponse.getStatus().equals("NOT_FOUND")) { - return new ResponseEntity<>(pdfResponse, HttpStatus.BAD_REQUEST); - } else if (pdfResponse.getStatus().equals("ERROR")) { - log.info("RESPONSE from generatePdf returned error reason: {}", pdfResponse.getReason()); - return new ResponseEntity<>(pdfResponse, HttpStatus.INTERNAL_SERVER_ERROR); - } - return new ResponseEntity<>(pdfResponse, HttpStatus.OK); - } - } catch (Exception ex) { - log.error("Error in fetch pdf", ex); - throw new ClaimProcessingException(claimSubmissionId, HttpStatus.INTERNAL_SERVER_ERROR, ex); - } - } - - @Override - public ResponseEntity generatePdf(GeneratePdfRequest request) - throws ClaimProcessingException { - log.info( - "Generating pdf for claim: {} and diagnostic code {}", - request.getClaimSubmissionId(), - request.getDiagnosticCode()); - try { - GeneratePdfPayload model = generatePdfRequestMapper.toModel(request); - if (model.getPdfTemplate() == null - || model.getPdfTemplate().isEmpty() - || model.getPdfTemplate().isBlank()) { - model.setPdfTemplate("v1"); - } - log.info(model.toString()); - String response = camelEntrance.generatePdf(model); - GeneratePdfResponse pdfResponse = objectMapper.readValue(response, GeneratePdfResponse.class); - log.info(pdfResponse.toString()); - log.info("RESPONSE from generatePdf returned status: {}", pdfResponse.getStatus()); - if (pdfResponse.getStatus().equals("ERROR")) { - log.info("RESPONSE from generatePdf returned error reason: {}", pdfResponse.getReason()); - return new ResponseEntity<>(pdfResponse, HttpStatus.INTERNAL_SERVER_ERROR); - } - return new ResponseEntity<>(pdfResponse, HttpStatus.OK); - } catch (Exception ex) { - log.error("Error in generate pdf", ex); - throw new ClaimProcessingException( - request.getClaimSubmissionId(), HttpStatus.INTERNAL_SERVER_ERROR, ex); - } - } - - @Override - public ResponseEntity fetchPdf(String claimSubmissionId) throws ClaimProcessingException { - - log.info("Fetching pdf for claim: {}", claimSubmissionId); - try { - String response = camelEntrance.fetchPdf(claimSubmissionId); - return fetchProcess(claimSubmissionId, response); - } catch (Exception ex) { - log.error("Error in fetch pdf", ex); - throw new ClaimProcessingException(claimSubmissionId, HttpStatus.INTERNAL_SERVER_ERROR, ex); - } - } - - @Override - public ResponseEntity immediatePdf(GeneratePdfRequest request) - throws ClaimProcessingException { - log.info( - "Generating pdf for claim: {} and diagnostic code {}", - request.getClaimSubmissionId(), - request.getDiagnosticCode()); - try { - GeneratePdfPayload model = generatePdfRequestMapper.toModel(request); - log.info(model.toString()); - String response = camelEntrance.immediatePdf(model); - return fetchProcess(request.getClaimSubmissionId(), response); - } catch (Exception ex) { - log.error("Error in generate fetch pdf", ex); - throw new ClaimProcessingException( - request.getClaimSubmissionId(), HttpStatus.INTERNAL_SERVER_ERROR, ex); - } - } - - @Override - public ResponseEntity postFullHealthAssessment( - HealthDataAssessmentRequest claim) throws ClaimProcessingException { - log.info( - "Getting full health assessment for claim {} and veteran icn {}", - claim.getClaimSubmissionId(), - claim.getVeteranIcn()); - try { - Claim model = postClaimRequestMapper.toModel(claim); - String responseAsString = camelEntrance.submitClaimFull(model); - - AbdEvidenceWithSummary response = - objectMapper.readValue(responseAsString, AbdEvidenceWithSummary.class); - if (response.getEvidence() == null) { - log.info( - "Response from condition processor returned error message: {}", - response.getErrorMessage()); - throw new ClaimProcessingException( - claim.getClaimSubmissionId(), - HttpStatus.INTERNAL_SERVER_ERROR, - "Internal error while processing claim data."); - } - FullHealthDataAssessmentResponse httpResponse = - objectMapper.convertValue(response, FullHealthDataAssessmentResponse.class); - log.info("Returning health assessment for: {}", claim.getVeteranIcn()); - httpResponse.setVeteranIcn(claim.getVeteranIcn()); - httpResponse.setDiagnosticCode(claim.getDiagnosticCode()); - return new ResponseEntity<>(httpResponse, HttpStatus.CREATED); - } catch (Exception ex) { - log.error("Error in full health assessment", ex); - throw new ClaimProcessingException( - claim.getClaimSubmissionId(), HttpStatus.INTERNAL_SERVER_ERROR, ex); - } - } - - private static HttpHeaders getHttpHeaders(String diagnosis) { - - ContentDisposition disposition = - ContentDisposition.attachment() - .filename(GeneratePdfPayload.createPdfFilename(diagnosis)) - .build(); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_PDF); - headers.setContentDisposition(disposition); - return headers; - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/advice/InputSanitizerAdvice.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/advice/InputSanitizerAdvice.java deleted file mode 100644 index 2e96af28e4..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/advice/InputSanitizerAdvice.java +++ /dev/null @@ -1,95 +0,0 @@ -package gov.va.vro.controller.rrd.advice; - -import gov.va.vro.controller.rrd.exception.DisallowedPatternException; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.core.MethodParameter; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpInputMessage; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Type; -import java.nio.charset.StandardCharsets; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -@ControllerAdvice -@ComponentScan -public class InputSanitizerAdvice implements RequestBodyAdvice { - - // https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/regex/Pattern.html - private static final Pattern NON_PRINTABLE = Pattern.compile("\\P{Print}&&[^{}]"); - private static final Pattern NUL_CHARACTER = Pattern.compile("(\\u0000|%00)"); - - @Override - public boolean supports( - MethodParameter methodParameter, - Type targetType, - Class> converterType) { - // Return true to indicate that this advice should be applied to all request - // bodies - return true; - } - - @Override - public HttpInputMessage beforeBodyRead( - HttpInputMessage inputMessage, - MethodParameter parameter, - Type targetType, - Class> converterType) - throws IOException { - // Create a custom HttpInputMessage that sanitizes the request body before it is - // read - return new HttpInputMessage() { - @Override - public InputStream getBody() throws IOException { - // Read the request body and remove non-printable and NUL characters from it - String requestBody = - new String(inputMessage.getBody().readAllBytes(), StandardCharsets.UTF_8); - - Matcher nonPrintableMatcher = NON_PRINTABLE.matcher(requestBody); - boolean nonPrintableMatches = nonPrintableMatcher.find(); - - Matcher nullCharacterMatcher = NUL_CHARACTER.matcher(requestBody); - boolean nullCharacterMatches = nullCharacterMatcher.find(); - - if (nonPrintableMatches || nullCharacterMatches) { - throw new DisallowedPatternException(); - } else { - return new ByteArrayInputStream(requestBody.getBytes(StandardCharsets.UTF_8)); - } - } - - @Override - public HttpHeaders getHeaders() { - return inputMessage.getHeaders(); - } - }; - } - - // The following methods are not used in this implementation and can be left - // blank - @Override - public Object afterBodyRead( - Object body, - HttpInputMessage inputMessage, - MethodParameter parameter, - Type targetType, - Class> converterType) { - return body; - } - - @Override - public Object handleEmptyBody( - Object body, - HttpInputMessage inputMessage, - MethodParameter parameter, - Type targetType, - Class> converterType) { - return body; - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/exception/ClaimProcessingError.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/exception/ClaimProcessingError.java deleted file mode 100644 index 5201d013d1..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/exception/ClaimProcessingError.java +++ /dev/null @@ -1,28 +0,0 @@ -package gov.va.vro.controller.rrd.exception; - -import com.fasterxml.jackson.annotation.JsonInclude; -import gov.va.vro.api.rrd.model.ClaimProcessingException; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -public class ClaimProcessingError { - - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private String claimSubmissionId; - - private String message; - - public ClaimProcessingError(ClaimProcessingException exception) { - this.claimSubmissionId = exception.getClaimSubmissionId(); - this.message = exception.getOriginalMessage(); - } - - public ClaimProcessingError(String message) { - this.claimSubmissionId = null; - this.message = message; - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/exception/DisallowedPatternException.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/exception/DisallowedPatternException.java deleted file mode 100644 index a30446ef5d..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/exception/DisallowedPatternException.java +++ /dev/null @@ -1,9 +0,0 @@ -package gov.va.vro.controller.rrd.exception; - -public class DisallowedPatternException extends IllegalArgumentException { - public DisallowedPatternException() { - super( - "Disallowed patterns were found in the Request Body." - + " Please sanitize your Request Body input data and try again."); - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/exception/GlobalExceptionHandler.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/exception/GlobalExceptionHandler.java deleted file mode 100644 index bf4ee59844..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/exception/GlobalExceptionHandler.java +++ /dev/null @@ -1,157 +0,0 @@ -package gov.va.vro.controller.rrd.exception; - -import com.fasterxml.jackson.core.JsonParseException; -import gov.va.vro.api.rrd.model.ClaimProcessingException; -import gov.va.vro.service.provider.bip.BipException; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.MethodParameter; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.http.converter.HttpMessageNotReadableException; -import org.springframework.validation.FieldError; -import org.springframework.web.HttpRequestMethodNotSupportedException; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; - -import javax.validation.ConstraintViolationException; - -@ControllerAdvice -@Slf4j -public class GlobalExceptionHandler { - - /** - * Handles method argument not valid. - * - * @param exception the exception - * @return returns exception - */ - @ExceptionHandler(MethodArgumentNotValidException.class) - public ResponseEntity handleMethodArgumentNotValidException( - MethodArgumentNotValidException exception) { - log.error("Validation error", exception); - final StringBuffer errors = new StringBuffer(); - for (final FieldError error : exception.getBindingResult().getFieldErrors()) { - if (!errors.isEmpty()) { - errors.append("\n"); - } - errors.append(error.getField() + ": " + error.getDefaultMessage()); - } - ClaimProcessingError cpe = new ClaimProcessingError(errors.toString()); - return new ResponseEntity<>(cpe, HttpStatus.BAD_REQUEST); - } - - /** - * Handles method argument not valid type. - * - * @param exception the exception - * @return returns exception - */ - @ExceptionHandler(MethodArgumentTypeMismatchException.class) - public ResponseEntity handleMethodArgumentNotValidException( - MethodArgumentTypeMismatchException exception) { - log.error("Validation error", exception); - MethodParameter parameter = exception.getParameter(); - String name = parameter.getParameterName() + " is of wrong type."; - ClaimProcessingError cpe = new ClaimProcessingError(name); - return new ResponseEntity<>(cpe, HttpStatus.BAD_REQUEST); - } - - /** - * Handles constraint violations such as min or max limits. - * - * @param exception the exception - * @return returns exception - */ - @ExceptionHandler(ConstraintViolationException.class) - public ResponseEntity handleMethodArgumentNotValidException( - ConstraintViolationException exception) { - log.error("Validation error", exception); - ClaimProcessingError cpe = new ClaimProcessingError("invalid parameters"); - return new ResponseEntity<>(cpe, HttpStatus.BAD_REQUEST); - } - - /** - * Handles claim processing exception. - * - * @param exception the exception - * @return returns exception - */ - @ExceptionHandler(ClaimProcessingException.class) - public ResponseEntity handleClaimProcessingException( - ClaimProcessingException exception) { - log.info("Claim processing error", exception); - return new ResponseEntity<>(new ClaimProcessingError(exception), exception.getHttpStatus()); - } - - /** - * Detects unallowed character sequences in JSON Request Body input data. - * - * @param exception the exception - * @return returns exception - */ - @ExceptionHandler(DisallowedPatternException.class) - public ResponseEntity handleUnallowedPatternException( - DisallowedPatternException exception) { - log.error("Unallowed patterns were found in the Request Body.", exception); - ClaimProcessingError cpe = new ClaimProcessingError(HttpStatus.BAD_REQUEST.getReasonPhrase()); - return new ResponseEntity<>(cpe, HttpStatus.BAD_REQUEST); - } - - /** - * Handles JSON parsing. - * - * @param exception the exception - * @return returns exception - */ - @ExceptionHandler(HttpMessageNotReadableException.class) - public ResponseEntity handleJsonParseException( - JsonParseException exception) { - log.error("Bad Request: Malformed JSON", exception); - ClaimProcessingError cpe = new ClaimProcessingError(HttpStatus.BAD_REQUEST.getReasonPhrase()); - return new ResponseEntity<>(cpe, HttpStatus.BAD_REQUEST); - } - - /** - * Handles unsupported HTTP Methods. - * - * @param exception the exception - * @return new exception - */ - @ExceptionHandler(HttpRequestMethodNotSupportedException.class) - public ResponseEntity handleUnsupportedHttpMethodException( - HttpRequestMethodNotSupportedException exception) { - log.error("HTTP Method Not Supported"); - ClaimProcessingError cpe = - new ClaimProcessingError(HttpStatus.METHOD_NOT_ALLOWED.getReasonPhrase()); - return new ResponseEntity(cpe, HttpStatus.METHOD_NOT_ALLOWED); - } - - /** - * Handles general, unspecified exceptions (catch-all). - * - * @param exception the exception - * @return returns exception - */ - @ExceptionHandler(Exception.class) - public ResponseEntity handleException(Exception exception) { - log.error("Unexpected error", exception); - ClaimProcessingError cpe = - new ClaimProcessingError(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()); - return new ResponseEntity<>(cpe, HttpStatus.INTERNAL_SERVER_ERROR); - } - - /** - * Handles BIP Exceptions. - * - * @param exception the exception - * @return returns response - */ - @ExceptionHandler(BipException.class) - public ResponseEntity handleBipClaimException(BipException exception) { - log.error("BIP exception: {}", exception.getMessage(), exception); - ClaimProcessingError cpe = new ClaimProcessingError(exception.getMessage()); - return new ResponseEntity<>(cpe, exception.getStatus()); - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/mapper/GeneratePdfRequestMapper.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/mapper/GeneratePdfRequestMapper.java deleted file mode 100644 index dd4432995b..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/mapper/GeneratePdfRequestMapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package gov.va.vro.controller.rrd.mapper; - -import gov.va.vro.api.rrd.requests.GeneratePdfRequest; -import gov.va.vro.api.rrd.responses.GeneratePdfResponse; -import gov.va.vro.service.spi.model.GeneratePdfPayload; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -import java.util.Optional; - -@Mapper(componentModel = "spring") -public interface GeneratePdfRequestMapper { - - @Mapping(target = "status", ignore = true) - @Mapping(target = "reason", ignore = true) - GeneratePdfPayload toModel(GeneratePdfRequest request); - - @Mapping(target = "status") - @Mapping(target = "reason") - GeneratePdfResponse toGeneratePdfResponse(GeneratePdfPayload src); - - default GeneratePdfResponse toGeneratePdfResponse(Optional src) { - return toGeneratePdfResponse(src.orElse(null)); - } -} diff --git a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/mapper/PostClaimRequestMapper.java b/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/mapper/PostClaimRequestMapper.java deleted file mode 100644 index ec5d01a772..0000000000 --- a/domain-rrd/rrd-api-controller/src/main/java/gov/va/vro/controller/rrd/mapper/PostClaimRequestMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package gov.va.vro.controller.rrd.mapper; - -import gov.va.vro.api.rrd.requests.HealthDataAssessmentRequest; -import gov.va.vro.service.spi.model.Claim; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.ReportingPolicy; - -@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) -public interface PostClaimRequestMapper { - - // Requests from v2/health-data-assessment use claimSubmissionId, - // which needs to map to collectionId (to be used as the reference_id field in ClaimSubmission) - @Mapping(target = "collectionId", source = "claimSubmissionId") - Claim toModel(HealthDataAssessmentRequest request); -} diff --git a/domain-rrd/rrd-api-controller/src/test/resources/bip-ce-payload-example.json b/domain-rrd/rrd-api-controller/src/test/resources/bip-ce-payload-example.json deleted file mode 100644 index 2e6eb5785d..0000000000 --- a/domain-rrd/rrd-api-controller/src/test/resources/bip-ce-payload-example.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "contentSource": "VRO", - "claimantFirstName": "John", - "claimantMiddleInitial": "M", - "claimantLastName": "Smith", - "claimantSsn": "123456789", - "documentTypeId": 1489, - "notes": "John Smith's 2nd application" -} diff --git a/domain-rrd/rrd-app-test/build.gradle.bak b/domain-rrd/rrd-app-test/build.gradle.bak deleted file mode 100644 index 5440e22472..0000000000 --- a/domain-rrd/rrd-app-test/build.gradle.bak +++ /dev/null @@ -1,53 +0,0 @@ -plugins { - id 'local.std.java.library-spring-conventions' - id 'org.unbroken-dome.test-sets' version '4.0.0' -} - -testSets { - end2endTest -} - -tasks.withType(Test).named("end2endTest") { - useJUnitPlatform() - testLogging { - // https://wjw465150.github.io/blog/Gradle/my_data/Gradle_Goodness/Show_Standard_Out_or_Error_Output_from_Tests.htm - showStandardStreams = true - events "skipped", "failed", "passed" - exceptionFormat = 'full' - showStackTraces = true - showExceptions = true - showCauses = true - } -} - -dependencies { - implementation project(':app') - implementation project(':persistence:model') - implementation project(':domain-rrd:rrd-shared') - implementation project(':domain-rrd:rrd-api-controller') - implementation project(':domain-rrd:rrd-workflows') - - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation "org.springframework.security:spring-security-core:${spring_security_version}" - implementation "org.springframework.security:spring-security-config:${spring_security_version}" - implementation "org.springframework.security:spring-security-web:${spring_security_version}" - - //MAS oAuth2 webclient libs - implementation "org.springframework.boot:spring-boot-starter-webflux:${sb_webflux}" - implementation "org.springframework.security:spring-security-oauth2-client:${spring_security_version}" - implementation "org.springframework.boot:spring-boot-starter-security:${sb_security}" - - implementation group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1' - implementation 'org.apache.commons:commons-lang3:3.12.0' - - runtimeOnly "org.postgresql:postgresql:${postgresql_version}" - testRuntimeOnly "com.h2database:h2:${h2_version}" - - testImplementation "org.apache.camel:camel-test-spring-junit5:${camel_version}" - - // end to end dependencies - end2endTestImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" - end2endTestImplementation "org.springframework.boot:spring-boot-starter-webflux:${spring_boot_version})" - end2endTestImplementation "org.skyscreamer:jsonassert:${json_assert_version}" - end2endTestImplementation "org.apache.pdfbox:pdfbox:2.0.28" -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/VroV1Tests.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/VroV1Tests.java deleted file mode 100644 index 787969ede6..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/VroV1Tests.java +++ /dev/null @@ -1,128 +0,0 @@ -package gov.va.vro.end2end; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrowsExactly; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.JsonNode; -import gov.va.vro.end2end.util.PdfText; -import gov.va.vro.end2end.util.RestHelper; -import gov.va.vro.end2end.util.TestSetup; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; -import org.skyscreamer.jsonassert.JSONCompareMode; -import org.springframework.http.ContentDisposition; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.HttpClientErrorException; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; - -@Slf4j -public class VroV1Tests { - private void testAssessment(TestSetup setup, RestHelper helper) throws Exception { - ResponseEntity response = helper.getAssessment(setup); - Assertions.assertEquals(HttpStatus.CREATED, response.getStatusCode()); - - String actual = response.getBody(); - String expected = setup.getAssessment(); - JSONAssert.assertEquals(expected, actual, JSONCompareMode.STRICT); - } - - private void testPdfGeneration(TestSetup setup, RestHelper helper) throws Exception { - ResponseEntity response = helper.generatePdf(setup); - Assertions.assertEquals(HttpStatus.OK, response.getStatusCode()); - - String actual = response.getBody(); - String expected = setup.getGeneratePdfResponse(); - JSONAssert.assertEquals(expected, actual, JSONCompareMode.STRICT); - } - - private void testGeneratedPdf(TestSetup setup, RestHelper helper) throws Exception { - ResponseEntity response = helper.getPdf(setup); - Assertions.assertEquals(HttpStatus.OK, response.getStatusCode()); - - HttpHeaders responseHeaders = response.getHeaders(); - log.info("Response headers: {}", responseHeaders); - ContentDisposition actualCd = responseHeaders.getContentDisposition(); - Assertions.assertEquals(setup.getContentDispositionFilename(), actualCd.getFilename()); - - checkPdfText(setup, response.getBody()); - } - - private void checkPdfText(TestSetup setup, byte[] pdf) throws Exception { - if (Boolean.parseBoolean(System.getenv("VRO_SAVE_PDF"))) { - savePdfFile(pdf, setup.getName() + "-" + setup.getContentDispositionFilename()); - } - PdfText pdfText = PdfText.getInstance(pdf); - log.info("PDF text: {}", pdfText.getPdfText()); - - JsonNode bpReadings = setup.getBpReadingsNode(); - if (bpReadings != null) { - assertTrue(bpReadings.isArray()); - assertEquals(bpReadings.size(), pdfText.countBpReadings()); - } else { - assertEquals(0, pdfText.countBpReadings()); - } - - JsonNode meds = setup.getMedicationsNode(); - assertTrue(meds.isArray()); - assertEquals(meds.size(), pdfText.countMedications()); - - JsonNode vetInfo = setup.getVeteranInfoNode(); - assertTrue(pdfText.hasVeteranInfo(vetInfo)); - } - - private void savePdfFile(byte[] pdfContents, String filename) { - try { - Files.write(Paths.get(filename), pdfContents); - log.info("Saved pdf to: {}", filename); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void testEnd2End(TestSetup setup, RestHelper helper) throws Exception { - testAssessment(setup, helper); - testPdfGeneration(setup, helper); - testGeneratedPdf(setup, helper); - } - - @Test - public void positive7101Case01() throws Exception { - TestSetup setup = TestSetup.getInstance("test-7101-01"); - - RestHelper helper = new RestHelper(); - helper.setApiKey("test-key-01"); - - testEnd2End(setup, helper); - } - - @Test - public void positive6602Case01() throws Exception { - TestSetup setup = TestSetup.getInstance("test-6602-01"); - - RestHelper helper = new RestHelper(); - helper.setApiKey("test-key-01"); - - testEnd2End(setup, helper); - } - - @Test - public void attemptWithoutApiKey() throws Exception { - TestSetup setup = TestSetup.getInstance("test-7101-01"); - - RestHelper helper = new RestHelper(); - helper.setApiKey("bad-key-01"); - - HttpClientErrorException.Unauthorized exception = - assertThrowsExactly( - HttpClientErrorException.Unauthorized.class, () -> helper.getAssessment(setup)); - assertEquals("401 : [no body]", exception.getMessage()); - } -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/VroV2Tests.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/VroV2Tests.java deleted file mode 100644 index 7915211909..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/VroV2Tests.java +++ /dev/null @@ -1,977 +0,0 @@ -package gov.va.vro.end2end; - -import static gov.va.vro.service.provider.camel.MasIntegrationRoutes.LIGHTHOUSE_ERROR_MSG; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.api.rrd.responses.MasResponse; -import gov.va.vro.end2end.util.AutomatedClaimTestSpec; -import gov.va.vro.end2end.util.ContentionUpdatesResponse; -import gov.va.vro.end2end.util.LifecycleUpdatesResponse; -import gov.va.vro.end2end.util.OrderExamCheckResponse; -import gov.va.vro.end2end.util.PdfTextV2; -import gov.va.vro.end2end.util.SuccessResponse; -import gov.va.vro.end2end.util.TempJurisdictionStationRequest; -import gov.va.vro.model.rrd.bip.ClaimContention; -import gov.va.vro.model.rrd.bip.ClaimStatus; -import gov.va.vro.model.rrd.claimmetrics.AssessmentInfo; -import gov.va.vro.model.rrd.claimmetrics.ContentionInfo; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimInfoResponse; -import gov.va.vro.model.rrd.claimmetrics.response.ExamOrderInfoResponse; -import gov.va.vro.model.rrd.event.EventReason; -import gov.va.vro.model.rrd.mas.VeteranIdentifiers; -import gov.va.vro.model.rrd.mas.request.MasAutomatedClaimRequest; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Test; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.util.FileCopyUtils; -import org.springframework.web.client.HttpStatusCodeException; -import org.springframework.web.client.RestTemplate; - -import java.io.File; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -@Slf4j -public class VroV2Tests { - - private static final String BASE_URL = "http://localhost:8080/v2"; - private static final String EXAM_ORDERING_STATUS_URL = BASE_URL + "/examOrderingStatus"; - private static final String AUTOMATED_CLAIM_URL = BASE_URL + "/automatedClaim"; - private static final String CLAIM_INFO_URL = BASE_URL + "/claim-info/"; - private static final String EXAM_ORDER_INFO_URL = BASE_URL + "/exam-order-info"; - private static final String UPDATES_URL = "http://localhost:20306/updates/"; - private static final String RECEIVED_FILES_URL = "http://localhost:20316/received-files/"; - private static final String ORDER_EXAM_URL = "http://localhost:20400/checkExamOrdered/"; - private static final String SLACK_URL = "http://localhost:20100/slack-messages/"; - - private static final String JWT_TOKEN = - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImMwOTI5NTJlLTM4ZDYtNDNjNi05MzBlLWZmOTNiYTUx" - + "YjA4ZiJ9.eyJleHAiOjk5OTk5OTk5OTksImlhdCI6MTY0MTA2Nzk0OSwianRpIjoiNzEwOTAyMGEtMzlkOS00M" - + "WE4LThlNzgtNTllZjAwYTlkNDJlIiwiaXNzIjoiaHR0cHM6Ly9zYW5kYm94LWFwaS52YS5nb3YvaW50ZXJuYWw" - + "vYXV0aC92Mi92YWxpZGF0aW9uIiwiYXVkIjoibWFzX2RldiIsInN1YiI6IjhjNDkyY2NmLTk0OGYtNDQ1Zi05N" - + "mY4LTMxZTdmODU5MDlkMiIsInR5cCI6IkJlYXJlciIsImF6cCI6Im1hc19kZXYiLCJzY29wZSI6Im9wZW5pZCB" - + "2cm9fbWFzIiwiY2xpZW50SWQiOiJtYXNfZGV2In0.Qb41CR1JIGGRlryi-XVtqyeNW73cU1YeBVqs9Bps3TA"; - - private static final String MAS_ORDER_NOTIFY_STATUS = "VRONOTIFED"; - - private final ObjectMapper objectMapper = new ObjectMapper(); - - private final RestTemplate restTemplate = new RestTemplate(); - - @Test - @SneakyThrows - void testUniqueAutomatedClaimPayloads() { - var resource = this.getClass().getClassLoader().getResource("test-mas"); - List files = - Files.walk(Paths.get(resource.toURI())) - .filter(Files::isRegularFile) - .filter(p -> p.getFileName().toString().endsWith(".json")) - .map(x -> x.toFile()) - .collect(Collectors.toList()); - - Set collectionIds = new HashSet<>(); - Set icns = new HashSet<>(); - Set claimIds = new HashSet<>(); - Set fileids = new HashSet<>(); - for (File file : files) { - String content = Files.readString(file.toPath()); - var request = objectMapper.readValue(content, MasAutomatedClaimRequest.class); - Integer collectionId = request.getCollectionId(); - assertNotNull(collectionId); - assertFalse( - collectionIds.contains(collectionId), - String.format("collection id {} is not unique", collectionId)); - collectionIds.add(collectionId); - - VeteranIdentifiers identifiers = request.getVeteranIdentifiers(); - assertNotNull(identifiers); - - String icn = identifiers.getIcn(); - assertNotNull(icn); - assertFalse(icns.contains(icn), String.format("icn %s is not unique", icn)); - icns.add(icn); - - String fileId = identifiers.getVeteranFileId(); - assertNotNull(fileId); - assertFalse(fileids.contains(fileId), String.format("file id %s is not unique", fileId)); - fileids.add(fileId); - - var claimDetail = request.getClaimDetail(); - assertNotNull(claimDetail); - String claimId = claimDetail.getBenefitClaimId(); - assertNotNull(claimId); - assertFalse(claimIds.contains(claimId), String.format("claim id %s is not unique", claimId)); - claimIds.add(claimId); - } - } - - /* - * This test checks the RequestBodyAdvice sanitizing logic for disallowed characters. - * Eventually we should refactor this out into its own test suite with other endpoints - * for any security-related HTTP tests. - */ - @Test - void testExamOrderingStatusDisallowedCharacters() { - var request = getOrderingStatusDisallowedCharacters(); - var requestEntity = getBearerAuthEntity(request); - try { - restTemplate.postForEntity(EXAM_ORDERING_STATUS_URL, requestEntity, String.class); - fail("Should have thrown exception"); - } catch (Exception e) { - assertTrue("400 : \"{\"message\":\"Bad Request\"}\"".equals(e.getMessage())); - } - } - - @Test - void testExamOrderingStatusInvalidRequest() { - var request = getOrderingStatusInvalidRequest(); - var requestEntity = getBearerAuthEntity(request); - try { - restTemplate.postForEntity(EXAM_ORDERING_STATUS_URL, requestEntity, String.class); - fail("Should have thrown exception"); - } catch (Exception e) { - assertTrue( - ("400 : \"{\"message\":\"collectionId: Collection ID is required\\ncollectionStatus:" - + " Collection Status is required\"}\"") - .equals(e.getMessage()) - || ("400 : \"{\"message\":\"collectionStatus: Collection Status is required\\" - + "ncollectionId: Collection ID is required\"}\"") - .equals(e.getMessage())); - } - } - - private void testExamOrderingStatus(String collectionId) { - var request = getOrderingStatusValidRequest(collectionId); - var requestEntity = getBearerAuthEntity(request); - var response = - restTemplate.postForEntity(EXAM_ORDERING_STATUS_URL, requestEntity, MasResponse.class); - assertEquals(HttpStatus.OK, response.getStatusCode()); - var masResponse = response.getBody(); - String expectedMessage = "Received Exam Order Status for collection Id " + collectionId + "."; - assertEquals(expectedMessage, masResponse.getMessage()); - } - - /** - * This returns the lifecycle status. Lifecycle status is updated before the contention update so - * this method can directly returns without polling. - * - * @param claimId claim identifier - * @return the lifestyle status found - */ - @SneakyThrows - private String getUpdatedLifecycleStatus(String claimId) { - String url = UPDATES_URL + claimId + "/" + "lifecycle_status"; - var testResponse = restTemplate.getForEntity(url, LifecycleUpdatesResponse.class); - assertEquals(HttpStatus.OK, testResponse.getStatusCode()); - LifecycleUpdatesResponse body = testResponse.getBody(); - // Do not check isFound for now. We now do not update when necessary - return body.getStatus(); - } - - /** - * Contentions will always be updated since we check existence of RDR1 (anchor) before processing - * begins and at least RDR1 will need to be removed. - * - * @param claimId claim identifier - * @return all the contentions - */ - @SneakyThrows - private List getUpdatedContentions(String claimId) { - for (int pollNumber = 0; pollNumber < 20; ++pollNumber) { - String url = UPDATES_URL + claimId + "/" + "contentions"; - var testResponse = restTemplate.getForEntity(url, ContentionUpdatesResponse.class); - assertEquals(HttpStatus.OK, testResponse.getStatusCode()); - ContentionUpdatesResponse body = testResponse.getBody(); - if (body.isFound()) { - log.info("Claim {} contentions are updated.", claimId); - return body.getContentions(); - } else { - log.info("Claim {} contentions are not updated. Retrying...", claimId); - } - Thread.sleep(5000); - } - return null; - } - - @SneakyThrows - private MasAutomatedClaimRequest startAutomatedClaim(AutomatedClaimTestSpec spec) { - final String collectionId = spec.getCollectionId(); - - // Load the test case - var path = spec.getPayloadPath(); - var content = resourceToString(path); - - // Extract claim id and file number and reset previous actions for those in mocks - final MasAutomatedClaimRequest request = - objectMapper.readValue(content, MasAutomatedClaimRequest.class); - final String claimId = request.getClaimDetail().getBenefitClaimId(); - final String fileNumber = request.getVeteranIdentifiers().getVeteranFileId(); - log.info("Reset data in the mock servers."); - restTemplate.delete(UPDATES_URL + claimId); - restTemplate.delete(RECEIVED_FILES_URL + fileNumber); - restTemplate.delete(ORDER_EXAM_URL + collectionId); - restTemplate.delete(SLACK_URL + collectionId); - - // Start automated claim - var requestEntity = getBearerAuthEntity(content); - try { - var response = - restTemplate.postForEntity(AUTOMATED_CLAIM_URL, requestEntity, MasResponse.class); - assertEquals(spec.getExpectedStatusCode(), response.getStatusCode()); - var masResponse = response.getBody(); - assertEquals(spec.getExpectedMessage(), masResponse.getMessage()); - return request; - } catch (HttpStatusCodeException exception) { - assertEquals(spec.getExpectedStatusCode(), exception.getStatusCode()); - return null; - } - } - - private AutomatedClaimTestSpec specFor200(String collectionId) { - AutomatedClaimTestSpec spec = new AutomatedClaimTestSpec(); - spec.setCollectionId(collectionId); - spec.setPayloadPath(String.format("test-mas/claim-%s-7101.json", collectionId)); - spec.setExpectedMessage(String.format("Received Claim for collection Id %s.", collectionId)); - return spec; - } - - @SneakyThrows - private String testPdfUpload(MasAutomatedClaimRequest request) { - // Wait until the evidence pdf is uploaded - final String fileNumber = request.getVeteranIdentifiers().getVeteranFileId(); - log.info("Wait until the evidence pdf is uploaded"); - boolean successUploading = false; - String evidencePdfText = null; - for (int pollNumber = 0; pollNumber < 15; ++pollNumber) { - Thread.sleep(20000); - String url = RECEIVED_FILES_URL + fileNumber; - try { - ResponseEntity testResponse = restTemplate.getForEntity(url, byte[].class); - assertEquals(HttpStatus.OK, testResponse.getStatusCode()); - PdfTextV2 pdfTextV2 = PdfTextV2.getInstance(testResponse.getBody()); - evidencePdfText = pdfTextV2.getPdfText(); - log.info("PDF text: {}", evidencePdfText); - assertTrue(pdfTextV2.hasVeteranName(request.getFirstName(), request.getLastName())); - successUploading = true; - break; - } catch (HttpStatusCodeException exception) { - log.info("Did not find veteran {}. Retrying...", fileNumber); - assertEquals(HttpStatus.NOT_FOUND, exception.getStatusCode()); - } - } - - // Verify evidence pdf is uploaded - assertTrue(successUploading); - return evidencePdfText; - } - - /** - * Test the exam ordered endpoint. - * - * @param collectionId collection ID - */ - @SneakyThrows - private void testExamOrdered(String collectionId) { - boolean successOrdering = false; - String url = ORDER_EXAM_URL + collectionId; - log.info("Wait for examOrder code to execute."); - for (int pollNumber = 0; pollNumber < 15; ++pollNumber) { - Thread.sleep(20000); - var testResponse = restTemplate.getForEntity(url, OrderExamCheckResponse.class); - assertEquals(HttpStatus.OK, testResponse.getStatusCode()); - boolean examOrdered = testResponse.getBody().isOrdered(); - if (examOrdered) { - log.info("{} had exam ordered", collectionId); - } else { - log.info("{} did NOT have exam ordered", collectionId); - } - if (examOrdered) { - successOrdering = true; - break; - } else { - log.info("Exam not ordered yet for collection {}. Waiting and rechecking...", collectionId); - } - } - assertTrue(successOrdering, "Exam is not ordered"); - } - - private ClaimInfoResponse getClaimInfoForCollection(String collectionId) { - try { - String url = CLAIM_INFO_URL + collectionId; - HttpEntity requestEntity = getTokenAuthHeaders(); - ResponseEntity response = - restTemplate.exchange(url, HttpMethod.GET, requestEntity, ClaimInfoResponse.class); - assertEquals(HttpStatus.OK, response.getStatusCode()); - ClaimInfoResponse body = response.getBody(); - assertNotNull(body, "Claim Info Response was null, cannot continue"); - return body; - } catch (HttpStatusCodeException exception) { - assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode()); - return null; - } - } - - @SneakyThrows - private void testClaimSufficientStatus(String collectionId, Boolean expectedSufficientValue) { - AssessmentInfo foundAssessment = null; - - log.info("Waiting for claim processing to finish and assessment database results"); - for (int pollNumber = 0; pollNumber < 60; ++pollNumber) { - ClaimInfoResponse cir = getClaimInfoForCollection(collectionId); - if (cir == null) { - log.info( - "Did not find assessment result for collection id {} with message .. retrying", - collectionId); - Thread.sleep(5000); - continue; - } - List contentionList = cir.getContentions(); - // Just take the 0'th of now. If you run multiple times all should be same - assertTrue(contentionList.size() > 0); - List assessmentList = contentionList.get(0).getAssessments(); - assertTrue(assessmentList.size() > 0); - foundAssessment = assessmentList.get(0); - break; - } - assertNotNull(foundAssessment); - assertEquals(expectedSufficientValue, foundAssessment.getSufficientEvidenceFlag()); - } - - private void overrideTempJurisdictionStation(String claimId, String station) { - String url = UPDATES_URL + claimId + "/" + "temp_jurisdiction_station"; - TempJurisdictionStationRequest payload = new TempJurisdictionStationRequest(station); - HttpEntity request = new HttpEntity<>(payload); - var response = restTemplate.postForEntity(url, request, SuccessResponse.class); - assertEquals(HttpStatus.OK, response.getStatusCode()); - } - - /** - * Runs a full end-to-end test for the collection id using mock services. Collection id used here - * should be one of the preloaded ones in mock-mas-api amd the benefit claim id should one of the - * ones in mock-bip-claims-api. This verifies rest message, pdf upload, rdr1 special issue removal - * and lifecycle status update. - */ - @SneakyThrows - private String testAutomatedClaimFullPositive(AutomatedClaimTestSpec spec) { - String collectionId = spec.getCollectionId(); - MasAutomatedClaimRequest request = startAutomatedClaim(spec); - - long extraSleep = spec.getExtraSleep(); - if (extraSleep > 0) { // sleep before checks start - Thread.sleep(extraSleep); - } - - final String claimId = request.getClaimDetail().getBenefitClaimId(); - String tempJurisdictionStationOverride = spec.getTempJurisdictionStationOverride(); - if (tempJurisdictionStationOverride != null) { - overrideTempJurisdictionStation(claimId, tempJurisdictionStationOverride); - } - - String pdfText = testPdfUpload(request); - if (!spec.isBipUpdateClaimError()) { - testUpdatedContentions(claimId, false, true, ClaimStatus.RFD); - testLifecycleStatus(claimId, ClaimStatus.RFD); - } - if (tempJurisdictionStationOverride != null || spec.isBipUpdateClaimError()) { - testSlackMessage(collectionId, spec.getExpectedSlackMessage()); - } - return pdfText; - } - - /* - * This uses the single available collection from MAS development server. Since the collection has - * no blood pressure it is matched with a LH Health sandbox example without any recent blood - * pressure to result in a off ramping example. - */ - // Commenting out this for now. Looks like 350 is not working anymore. Throws exception. - // @Test - // void testAutomatedClaimMasExample() { - // AutomatedClaimTestSpec spec = specFor200("350"); - // spec.setCheckSlack(true); - // testAutomatedClaimOffRamp(spec); - // } - - /** Tests if Bip Claim Api 404 for non-existent claim results in 400 on our end. */ - @Test - @SneakyThrows - void testAutomatedClaimNonExistentClaimId() { - var path = "test-mas/claim-801-7101-nonexistent-claimid.json"; - var content = resourceToString(path); - var requestEntity = getBearerAuthEntity(content); - try { - restTemplate.postForEntity(AUTOMATED_CLAIM_URL, requestEntity, MasResponse.class); - fail("Collection 801 should have received 400."); - } catch (HttpStatusCodeException exception) { - assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode()); - } - } - - @SneakyThrows - private boolean testSlackMessage(String collectionId, String expectedSlackMessage) { - for (int pollNumber = 0; pollNumber < 60; ++pollNumber) { - Thread.sleep(5000); - String url = SLACK_URL + collectionId; - try { - ResponseEntity testResponse = restTemplate.getForEntity(url, String.class); - assertEquals(HttpStatus.OK, testResponse.getStatusCode()); - String body = testResponse.getBody(); - assertNotNull(body); - assertNotNull(expectedSlackMessage); - assertTrue(expectedSlackMessage.length() > 0); - assertTrue(body.contains(expectedSlackMessage)); - return true; - } catch (HttpStatusCodeException exception) { - log.info("Did not find slack message for {}. Retrying...", collectionId); - assertEquals(HttpStatus.NOT_FOUND, exception.getStatusCode()); - } - } - return false; - } - - private void testSpecialIssuesRemoved( - String claimId, ClaimContention contention, boolean rrdShouldBeRemoved) { - List specialIssueCodes = contention.getSpecialIssueCodes(); - assertNotNull(specialIssueCodes); - - String[] remainingRrdOrRdr1 = - specialIssueCodes.stream() - .filter(code -> code.equals("RDR1") || code.equals("RRD")) - .toArray(String[]::new); - - if (rrdShouldBeRemoved) { - String[] emptyArray = {}; - assertArrayEquals(emptyArray, remainingRrdOrRdr1, "RRD or RDR1 should have been removed"); - } else { - String[] onlyRrd = {"RRD"}; - assertArrayEquals(onlyRrd, remainingRrdOrRdr1, "only RRD should have remained"); - } - } - - private void testUpdatedContentions( - String claimId, - boolean rrdShouldBeRemoved, - boolean automationIndicator, - ClaimStatus claimStatus) { - List contentions = getUpdatedContentions(claimId); - assertNotNull(contentions, "Contentions are not updated to remove special issue(s)."); - log.info("Claim {} contentions have been updated.", claimId); - - // Only have single issue claims for now - assertEquals(1, contentions.size()); - ClaimContention contention = contentions.get(0); - - testSpecialIssuesRemoved(claimId, contention, rrdShouldBeRemoved); - assertEquals(automationIndicator, contention.isAutomationIndicator()); - } - - private void testLifecycleStatus(String claimId, ClaimStatus expectedStatus) { - String status = getUpdatedLifecycleStatus(claimId); - assertNotNull(status, "Lifecycle status has not been updated."); - log.info("Claim {} lifecycle status is: {}", claimId, status); - assertEquals(expectedStatus.getDescription(), status); - } - - private void testAutomatedClaimOffRamp(AutomatedClaimTestSpec spec) { - MasAutomatedClaimRequest request = startAutomatedClaim(spec); - - boolean slackResult = testSlackMessage(spec.getCollectionId(), spec.getExpectedSlackMessage()); - assertTrue(slackResult, "No or unexpected slack messages received by slack server"); - - if (!spec.isBipUpdateClaimError()) { - final String claimId = request.getClaimDetail().getBenefitClaimId(); - testUpdatedContentions(claimId, true, false, ClaimStatus.OPEN); - testLifecycleStatus(claimId, ClaimStatus.OPEN); - } - } - - /** Out of scope test case because of disability action type. 422 response is verified. */ - @Test - @SneakyThrows - void testAutomatedClaimOutOfScopeDisabilityAction() { - AutomatedClaimTestSpec spec = new AutomatedClaimTestSpec("10"); - spec.setPayloadPath("test-mas/claim-10-7101-out-of-scope.json"); - spec.setExpectedStatusCode(HttpStatus.UNPROCESSABLE_ENTITY); - spec.setExpectedMessage( - "Claim with collection id: 10, diagnostic code: 7101, and " - + "disability action type: DECREASE is not in scope."); - startAutomatedClaim(spec); - } - - /** Out of scope test case because of diagnostic code. 422 response is verified. */ - @Test - @SneakyThrows - void testAutomatedClaimOutOfScopeDiagnosticCode() { - AutomatedClaimTestSpec spec = new AutomatedClaimTestSpec("15"); - spec.setPayloadPath("test-mas/claim-15-6602-out-of-scope.json"); - spec.setExpectedStatusCode(HttpStatus.UNPROCESSABLE_ENTITY); - spec.setExpectedMessage( - "Claim with collection id: 15, diagnostic code: 6602, and " - + "disability action type: INCREASE is not in scope."); - startAutomatedClaim(spec); - } - - /** - * Missing anchor test case because of wrong temporary jurisdiction station. 422 response is - * verified. - */ - @Test - @SneakyThrows - void testAutomatedClaimMissingAnchorJurisdiction() { - AutomatedClaimTestSpec spec = new AutomatedClaimTestSpec("20"); - spec.setPayloadPath("test-mas/claim-20-7101-no-anchor-jurisdiction.json"); - spec.setExpectedStatusCode(HttpStatus.UNPROCESSABLE_ENTITY); - spec.setExpectedMessage( - "Claim with collection id: 20 does not qualify for " - + "automated processing because it is missing anchors."); - startAutomatedClaim(spec); - } - - /** Missing RDR1 test case. 422 response is verified.. */ - @Test - void testAutomatedClaimMissingSpecialIssueRrd1() { - AutomatedClaimTestSpec spec = new AutomatedClaimTestSpec("30"); - spec.setPayloadPath("test-mas/claim-30-7101-no-anchor-rdr1-missing.json"); - spec.setExpectedStatusCode(HttpStatus.UNPROCESSABLE_ENTITY); - spec.setExpectedMessage( - "Claim with [collection id = 30] does not qualify for " - + "automated processing because it is missing anchors."); - startAutomatedClaim(spec); - } - - /** Missing RRD test case. 422 response is verified.. */ - @Test - void testAutomatedClaimMissingSpecialIssueRrd() { - AutomatedClaimTestSpec spec = new AutomatedClaimTestSpec("31"); - spec.setPayloadPath("test-mas/claim-31-7101-no-anchor-rrd-missing.json"); - spec.setExpectedStatusCode(HttpStatus.UNPROCESSABLE_ENTITY); - spec.setExpectedMessage( - "Claim with [collection id = 31] does not qualify for " - + "automated processing because it is missing anchors."); - startAutomatedClaim(spec); - } - - /** Missing RDR1 and RRD test case. 422 response is verified.. */ - @Test - void testAutomatedClaimMissingSpecialIssueBoth() { - AutomatedClaimTestSpec spec = new AutomatedClaimTestSpec("32"); - spec.setPayloadPath("test-mas/claim-32-7101-no-anchor-both-missing.json"); - spec.setExpectedStatusCode(HttpStatus.UNPROCESSABLE_ENTITY); - spec.setExpectedMessage( - "Claim with [collection id = 32] does not qualify for " - + "automated processing because it is missing anchors."); - startAutomatedClaim(spec); - } - - /** Missing contentions test case. 422 response is verified.. */ - @Test - void testAutomatedClaimMissingContentions() { - AutomatedClaimTestSpec spec = new AutomatedClaimTestSpec("35"); - spec.setPayloadPath("test-mas/claim-35-7101-no-anchor-no-contentions.json"); - spec.setExpectedStatusCode(HttpStatus.UNPROCESSABLE_ENTITY); - spec.setExpectedMessage( - "Claim with [collection id = 35] does not qualify for " - + "automated processing because it is missing anchors."); - startAutomatedClaim(spec); - } - - /** Empty contentions test case. 422 response is verified.. */ - @Test - void testAutomatedClaimEmptyContentions() { - AutomatedClaimTestSpec spec = new AutomatedClaimTestSpec("37"); - spec.setPayloadPath("test-mas/claim-37-7101-no-anchor-empty-contentions.json"); - spec.setExpectedStatusCode(HttpStatus.UNPROCESSABLE_ENTITY); - spec.setExpectedMessage( - "Claim with [collection id = 37] does not qualify for " - + "automated processing because it is missing anchors."); - startAutomatedClaim(spec); - } - - /** Multi contentions test case. 422 response is verified.. */ - @Test - void testAutomatedClaimMultiContentions() { - AutomatedClaimTestSpec spec = new AutomatedClaimTestSpec("40"); - spec.setPayloadPath("test-mas/claim-40-7101-no-anchor-multi-contentions.json"); - spec.setExpectedStatusCode(HttpStatus.UNPROCESSABLE_ENTITY); - spec.setExpectedMessage( - "Claim with [collection id = 40] does not qualify for " - + "automated processing because it is missing anchors."); - startAutomatedClaim(spec); - } - - private ExamOrderInfoResponse findExamOrderInfoForCollectionId( - ExamOrderInfoResponse[] infoArray, String collectionId) { - for (ExamOrderInfoResponse info : infoArray) { - if (collectionId.equals(info.getCollectionId())) { - return info; - } - } - return null; - } - - private void checkExamOrderInfo(String collectionId, String status, boolean isOrderedAtNull) { - log.info("Getting exam order info from "); - HttpEntity requestEntity = getTokenAuthHeaders(); - - ResponseEntity response = - restTemplate.exchange( - EXAM_ORDER_INFO_URL, HttpMethod.GET, requestEntity, ExamOrderInfoResponse[].class); - assertEquals(HttpStatus.OK, response.getStatusCode()); - ExamOrderInfoResponse[] infoArray = response.getBody(); - ExamOrderInfoResponse info = findExamOrderInfoForCollectionId(infoArray, collectionId); - assertNotNull(info, "Cannot find database entry for collection " + collectionId); - assertEquals(status, info.getStatus()); - assertEquals(isOrderedAtNull, info.getOrderedAt() == null); - } - - private void testAutomatedClaimOrderExam(AutomatedClaimTestSpec spec) { - String collectionId = spec.getCollectionId(); - log.info("testing ordering exam for collection {}", collectionId); - MasAutomatedClaimRequest request = startAutomatedClaim(spec); - if (spec.isMasError()) { - boolean slackResult = - testSlackMessage(spec.getCollectionId(), spec.getExpectedSlackMessage()); - assertTrue(slackResult, "No or unexpected slack messages received by slack server"); - String claimId = request.getClaimDetail().getBenefitClaimId(); - testUpdatedContentions(claimId, true, false, ClaimStatus.OPEN); - } else { - testExamOrdered(collectionId); - if (spec.isBipError()) { - boolean slackResult = - testSlackMessage(spec.getCollectionId(), spec.getExpectedSlackMessage()); - assertTrue(slackResult, "No or unexpected slack messages received by slack server"); - } else { - testPdfUpload(request); - } - String claimId = request.getClaimDetail().getBenefitClaimId(); - testUpdatedContentions(claimId, false, true, ClaimStatus.OPEN); - testLifecycleStatus(claimId, ClaimStatus.OPEN); - checkExamOrderInfo(collectionId, "ORDER_SUBMITTED", true); - testExamOrderingStatus(collectionId); - checkExamOrderInfo(collectionId, MAS_ORDER_NOTIFY_STATUS, false); - } - } - - /** - * Test Case that ensures that exam order *is* called. The data underlying follows the NEW claim, - * one relevant condition, not enough information path. Rest response message, exam being ordered, - * pdf upload, and removal of RDR1 special issue are verified. - */ - @Test - void testAutomatedClaimOrderExamNewClaim() { - AutomatedClaimTestSpec spec = specFor200("377"); - testAutomatedClaimOrderExam(spec); - } - - /** - * Test Case that ensures that exam order *is* called. The data underlying follows the "increase" - * claim path where not enough blood pressure readings exist. Rest response message, exam being - * ordered, pdf upload, and removal of RDR1 special issue are verified. - */ - @Test - void testAutomatedClaimOrderExamIncreaseClaim() { - AutomatedClaimTestSpec spec = specFor200("378"); - testAutomatedClaimOrderExam(spec); - } - - /** - * Test Case that ensures bip claim evidence api upload evidence errors are handled properly. - * Copied from 378; this sends an error message instead of uploading the pdf. - */ - @Test - void testAutomatedClaimOrderExamBipError() { - AutomatedClaimTestSpec spec = specFor200("390"); - spec.setBipError(true); - spec.setExpectedSlackMessage(EventReason.PDF_UPLOAD_FAILED_AFTER_ORDER_EXAM.getReasonMessage()); - testAutomatedClaimOrderExam(spec); - } - - /** - * Test Case that ensures mas order exam errors are handled properly. Copied from 378; this sends - * an error message instead of ordering the exam or uploading the pdf. - */ - @Test - void testAutomatedClaimOrderExamMasError() { - AutomatedClaimTestSpec spec = specFor200("391"); - spec.setMasError(true); - spec.setExpectedSlackMessage(EventReason.EXAM_ORDER_FAILED.getReasonMessage()); - testAutomatedClaimOrderExam(spec); - } - - /** - * Test for an automated claim that does NOT order exam, and then fails PDF upload (Bip Errors on - * this fileID) Ensures that we handle the pdf failure correctly. - */ - @Test - void testAutomatedClaimNoExamPDFError() { - String collectionId = "392"; - AutomatedClaimTestSpec spec = specFor200(collectionId); - spec.setExpectedSlackMessage(EventReason.PDF_UPLOAD_FAILED_AFTER_RFD.getReasonMessage()); - testAutomatedClaimOffRamp(spec); - } - - /** Test Case that ensures that exam order *is* called based on LH data with no MAS annotations */ - @Test - void testLHDataOnlyClaimOrderExamIncreaseClaim() { - AutomatedClaimTestSpec spec = specFor200("401"); - testAutomatedClaimOrderExam(spec); - } - - @SneakyThrows - private String resourceToString(String path) { - var io = this.getClass().getClassLoader().getResourceAsStream(path); - try (Reader reader = new InputStreamReader(io)) { - return FileCopyUtils.copyToString(reader); - } - } - - @SneakyThrows - private String getOrderingStatusDisallowedCharacters() { - return objectMapper.writeValueAsString( - Map.of( - "collectionId", "999", - "collectionStatus", - "http://localhost:8080/v1/fetch-claims/%00%255c%252e%252e%255c/%252e%252e%255c/%252e%252e%255c/%252e%252e%255c/%252e%252e%255c/windows/system.ini\b\u007F\u0081\u0088/%00", - "examOrderDateTime", "2018-11-04T17:45:61Z")); - } - - @SneakyThrows - private String getOrderingStatusInvalidRequest() { - return objectMapper.writeValueAsString(Map.of("key1", "value1", "key2", "value2")); - } - - @SneakyThrows - private String getOrderingStatusValidRequest(String collectionId) { - var payload = - Map.of( - "collectionId", - collectionId, - "collectionStatus", - MAS_ORDER_NOTIFY_STATUS, - "examOrderDateTime", - "2022-12-08T17:45:59Z", - "eventId", - "None"); - return objectMapper.writeValueAsString(payload); - } - - // Authorization for Claim Info e2e - private HttpEntity getTokenAuthHeaders() { - HttpHeaders headers = new HttpHeaders(); - headers.add("X-API-Key", "test-key-01"); - return new HttpEntity<>(headers); - } - - private HttpEntity getBearerAuthEntity(String content) { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.setBearerAuth(JWT_TOKEN); - return new HttpEntity<>(content, headers); - } - - /** - * This is a full positive end-to-end test for an increase case. See - * testAutomatedClaimFullPositive to see what is being verified. After the run get the pdf from - * http://localhost:20316/received-files/9999375 - */ - @Test - void testAutomatedClaimFullPositiveIncrease() { - AutomatedClaimTestSpec spec = specFor200("375"); - testAutomatedClaimFullPositive(spec); - } - - /** This is a full positive end-to-end test for an increase case with LightHouse data only. */ - @Test - void testLHDataOnlyClaimFullPositiveIncrease() { - AutomatedClaimTestSpec spec = specFor200("400"); - testAutomatedClaimFullPositive(spec); - } - - /** - * This is a full positive end-to-end test for an presumptive case. See - * testAutomatedClaimFullPositive to see what is being verified. After the run get the pdf from - * http://localhost:20316/received-files/9999376 - */ - @Test - void testAutomatedClaimFullPositivePresumptive() { - AutomatedClaimTestSpec spec = specFor200("376"); - testAutomatedClaimFullPositive(spec); - } - - /** - * This is an off-ramp test case with a NEW claim that is not presumptive. Rest message, Slack - * message, removal of rdr1, and database update are verified. This case both returns a message - * and slacks. - */ - @Test - void testAutomatedClaimNewNotPresumptive() { - AutomatedClaimTestSpec spec = specFor200("379"); - spec.setExpectedMessage(EventReason.NEW_NOT_PRESUMPTIVE.getReasonMessage()); - spec.setExpectedSlackMessage(EventReason.NEW_NOT_PRESUMPTIVE.getReasonMessage()); - testAutomatedClaimOffRamp(spec); - } - - /** - * This is a full positive end-to-end test for a case with incomplete blood pressures. See - * testAutomatedClaimFullPositiveTwo to see what is being verified. After the run get the pdf from - * http://localhost:20316/received-files/9999380 - */ - @Test - void testAutomatedClaimFullPositiveIncompleteBloodPressures() { - AutomatedClaimTestSpec spec = specFor200("380"); - String pdfText = testAutomatedClaimFullPositive(spec); - // Check for evidence from mock MAS evidence API. - assertTrue(pdfText.contains("143/-")); - assertTrue(pdfText.contains("-/92")); - // Check for evidence from mock LH API. - assertTrue(pdfText.contains("190/-")); - assertTrue(pdfText.contains("-/93")); - // Check for evidence from mock LH API. These are missing value examples. - assertTrue(pdfText.contains("177/-")); - assertTrue(pdfText.contains("-/88")); - - // Check that BP with missing systolic and diastolic is not included as evidence. - assertFalse(pdfText.contains("-/-")); - } - - /** This is a full positive end-to-end test for a case with duplicate blood pressures. */ - @Test - void testAutomatedClaimFullPositiveDuplicateBloodPressures() { - AutomatedClaimTestSpec spec = specFor200("381"); - String pdfText = testAutomatedClaimFullPositive(spec); - // Check for evidence from mock MAS evidence API. - assertTrue(pdfText.contains("139/77 8/11/2022 VAMC Other Output Reports")); - assertTrue(pdfText.contains("167/93 5/11/2022 Medical Treatment Record - Government")); - // Check for evidence from mock LH API. - assertTrue(pdfText.contains("167/93 5/11/2022 VAMC record - LYONS VA MEDICAL CENTER")); - assertTrue(pdfText.contains("153/115 6/21/2022 VAMC record - WASHINGTON VA MEDICAL")); - - // Check that duplicate BP from LH is not included as evidence. - assertFalse(pdfText.contains("153/115 6/20/2021 VAMC record -WASHINGTON VA MEDICAL")); - } - /** - * This is a full positive end-to-end test for an increase case. It is copied from 375 and tests - * the Slack message when temporary station of jurisdiction changes during VRO processing. - */ - @Test - void testAutomatedClaimFullPositiveChangedStation() { - AutomatedClaimTestSpec spec = specFor200("385"); - spec.setTempJurisdictionStationOverride("456"); - spec.setExpectedSlackMessage( - "Claim 1085 is in station 456 not in 398. claim ID: 1085, collection ID: 385"); - testAutomatedClaimFullPositive(spec); - } - - /** - * This is a full positive end-to-end test for an increase case. It is copied from 375 and tests - * the Slack message when bip claims api goes down during VRO processing. - */ - @Test - void testAutomatedClaimFullPositiveBipGoesDown() { - AutomatedClaimTestSpec spec = specFor200("386"); - spec.setBipUpdateClaimError(true); - spec.setExpectedSlackMessage(EventReason.BIP_UPDATE_FAILED.getReasonMessage()); - testAutomatedClaimFullPositive(spec); - } - - /** - * This is an off-ramp test case with missing blood pressure data for presumptive. Rest message, - * Slack message, removal of rdr1, and database update are verified. - */ - @Test - void testAutomatedClaimSufficiencyIsNull() { - String collectionId = "500"; - AutomatedClaimTestSpec spec = specFor200(collectionId); - spec.setExpectedSlackMessage(EventReason.SUFFICIENCY_UNDETERMINED.getReasonMessage()); - testAutomatedClaimOffRamp(spec); - testClaimSufficientStatus(collectionId, null); - } - - /** - * This is an end-to-end test for an increase case based on 375. It is used to test mas - * exceptions. - */ - @Test - void testAutomatedClaimMasException() { - AutomatedClaimTestSpec spec = specFor200("369"); - spec.setExpectedSlackMessage(EventReason.ANNOTATIONS_FAILED.getReasonMessage()); - testAutomatedClaimOffRamp(spec); - } - - /** - * This is an end-to-end test for an increase case based on 375. It is used to test lh 500 - * exceptions. This is on Observation retrieval. - */ - @Test - void testAutomatedClaimLh500Exception() { - String collectionId = "365"; - AutomatedClaimTestSpec spec = specFor200(collectionId); - testAutomatedClaimFullPositive(spec); - boolean slackResult = testSlackMessage(collectionId, LIGHTHOUSE_ERROR_MSG); - assertTrue(slackResult, "No or unexpected slack messages received by slack server"); - } - - /** - * This is an end-to-end test for an increase case based on 375. It is used to test lh timeout - * exceptions. - */ - @Test - void testAutomatedClaimLhTimeoutException() { - String collectionId = "366"; - AutomatedClaimTestSpec spec = specFor200(collectionId); - spec.setExtraSleep(250000); // expected sleep time - spec.setExpectedSlackMessage(LIGHTHOUSE_ERROR_MSG); - testAutomatedClaimFullPositive(spec); - boolean slackResult = testSlackMessage(collectionId, spec.getExpectedSlackMessage()); - assertTrue(slackResult, "No or unexpected slack messages received by slack server"); - } - - /** - * This is an end-to-end test for an increase case based on 375. It is used to test lh 504 - * exceptions. This is on Condition retrieval. - */ - @Test - void testAutomatedClaimLh504Exception() { - String collectionId = "367"; - AutomatedClaimTestSpec spec = specFor200(collectionId); - testAutomatedClaimFullPositive(spec); - spec.setExpectedSlackMessage(LIGHTHOUSE_ERROR_MSG); - boolean slackResult = testSlackMessage(collectionId, spec.getExpectedSlackMessage()); - assertTrue(slackResult, "No or unexpected slack messages received by slack server"); - } - - /** - * End to End Test that validates multiple VRO errors get sent in a slack message if this case - * occurs. Currently this happens with offramping + BIP Claim Error Based on Claim 369 - */ - @Test - void testAutomatedClaimMultipleError() { - AutomatedClaimTestSpec spec = specFor200("370"); - spec.setMasError(true); - spec.setBipUpdateClaimError(true); - String comboError = - EventReason.ANNOTATIONS_FAILED.getReasonMessage() - + " claim ID: 1370, collection ID: 370, " - + EventReason.BIP_UPDATE_FAILED.getReasonMessage(); - spec.setExpectedSlackMessage(comboError); - testAutomatedClaimOffRamp(spec); - } -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/AutomatedClaimTestSpec.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/AutomatedClaimTestSpec.java deleted file mode 100644 index 742e9e6804..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/AutomatedClaimTestSpec.java +++ /dev/null @@ -1,26 +0,0 @@ -package gov.va.vro.end2end.util; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.springframework.http.HttpStatus; - -@Getter -@Setter -@NoArgsConstructor -public class AutomatedClaimTestSpec { - private String collectionId; - private String expectedMessage; - private String expectedSlackMessage; - private HttpStatus expectedStatusCode = HttpStatus.OK; - private String payloadPath; - private boolean bipError = false; - private boolean masError = false; - private boolean bipUpdateClaimError = false; - private String tempJurisdictionStationOverride; - private long extraSleep = 0; - - public AutomatedClaimTestSpec(String collectionId) { - this.collectionId = collectionId; - } -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/ContentionUpdatesResponse.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/ContentionUpdatesResponse.java deleted file mode 100644 index 8fb12b54bc..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/ContentionUpdatesResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package gov.va.vro.end2end.util; - -import gov.va.vro.model.rrd.bip.ClaimContention; -import lombok.Getter; -import lombok.Setter; - -import java.util.List; - -@Getter -@Setter -public class ContentionUpdatesResponse { - private boolean found; - private List contentions; -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/LifecycleUpdatesResponse.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/LifecycleUpdatesResponse.java deleted file mode 100644 index d8af5d989a..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/LifecycleUpdatesResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package gov.va.vro.end2end.util; - -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class LifecycleUpdatesResponse { - private boolean found; - private String status; -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/OrderExamCheckResponse.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/OrderExamCheckResponse.java deleted file mode 100644 index f245f31dee..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/OrderExamCheckResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package gov.va.vro.end2end.util; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class OrderExamCheckResponse { - private boolean ordered; -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/PdfText.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/PdfText.java deleted file mode 100644 index e901eb8352..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/PdfText.java +++ /dev/null @@ -1,56 +0,0 @@ -package gov.va.vro.end2end.util; - -import com.fasterxml.jackson.databind.JsonNode; -import lombok.Getter; -import org.apache.commons.lang3.StringUtils; - -/** - * This class represents the text of the evidence pdf as extracted by Apache PDFBox. It is used for - * sanity checks for now until a more sophisticated parser extracts all data. - */ -@Getter -public class PdfText { - private String pdfText; - - public PdfText(String pdfText) { - this.pdfText = pdfText; - } - - public int countBpReadings() { - return StringUtils.countMatches(pdfText, "Blood pressure:"); - } - - public int countMedications() { - return StringUtils.countMatches(pdfText, "Prescribed on:"); - } - - /** - * Checks if the veteran full name is the document. - * - * @param veteranInfo veteran demographics spec - * @return if the pdf text has veteran full name - */ - public boolean hasVeteranInfo(JsonNode veteranInfo) { - // Assume all exists for now. That is how test data is set up. - String first = veteranInfo.get("first").asText(); - String middle = veteranInfo.get("middle").asText(); - String last = veteranInfo.get("last").asText(); - String suffix = veteranInfo.get("suffix").asText(); - - String searchValue = String.format("%s %s %s %s", first, middle, last, suffix); - - return pdfText.indexOf(searchValue) > -1; - } - - /** - * Extracts text from the pdf file and caches for later use. - * - * @param pdfContent the evidence pdf file as byte array - * @return newed PDFText - * @throws Exception any error to fail the test - */ - public static PdfText getInstance(byte[] pdfContent) throws Exception { - String text = PdfUtil.getText(pdfContent); - return new PdfText(text); - } -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/PdfTextV2.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/PdfTextV2.java deleted file mode 100644 index 1339bdf88a..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/PdfTextV2.java +++ /dev/null @@ -1,40 +0,0 @@ -package gov.va.vro.end2end.util; - -import lombok.Getter; - -/** - * This class represents the text of the evidence pdf as extracted by Apache PDFBox. It is used for - * sanity checks for now until a more sophisticated parser extracts all data. - */ -@Getter -public class PdfTextV2 { - private String pdfText; - - public PdfTextV2(String pdfText) { - this.pdfText = pdfText; - } - - /** - * Checks if the veteran name is in the document. - * - * @param firstName first name of the Veteran - * @param lastName last name of the Veteran - * @return if the pdf text has the Veteran full name - */ - public boolean hasVeteranName(String firstName, String lastName) { - String fullName = firstName + " " + lastName; - return pdfText.indexOf(fullName) > -1; - } - - /** - * Extracts text from the pdf file and caches for later use. - * - * @param pdfContent the evidence pdf file as byte array - * @return newed PDFTextV2 - * @throws Exception any error to fail the test - */ - public static PdfTextV2 getInstance(byte[] pdfContent) throws Exception { - String text = PdfUtil.getText(pdfContent); - return new PdfTextV2(text); - } -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/PdfUtil.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/PdfUtil.java deleted file mode 100644 index fcc6399f49..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/PdfUtil.java +++ /dev/null @@ -1,29 +0,0 @@ -package gov.va.vro.end2end.util; - -import lombok.SneakyThrows; -import org.apache.pdfbox.io.RandomAccessBuffer; -import org.apache.pdfbox.pdfparser.PDFParser; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.text.PDFTextStripper; - -public class PdfUtil { - /** - * Extracts text from the pdf file. - * - * @param pdfContent the evidence pdf file as byte array - * @return newed PDFText - * @throws Exception any error to fail the test - */ - @SneakyThrows - public static String getText(byte[] pdfContent) { - RandomAccessBuffer buffer = new RandomAccessBuffer(pdfContent); - PDFParser parser = new PDFParser(buffer); - parser.parse(); - - PDDocument document = parser.getPDDocument(); - - PDFTextStripper stripper = new PDFTextStripper(); - stripper.setSortByPosition(true); - return stripper.getText(document); - } -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/RestHelper.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/RestHelper.java deleted file mode 100644 index 377678a01d..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/RestHelper.java +++ /dev/null @@ -1,85 +0,0 @@ -package gov.va.vro.end2end.util; - -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; - -@Getter -@Setter -@Slf4j -public class RestHelper { - private static final String BASE_URL = "http://localhost:8080/v1"; - private static final String API_KEY = "X-API-KEY"; - private static final String ASSESSMENT_END_POINT = "/full-health-data-assessment"; - private static final String PDF_END_POINT = "/evidence-pdf"; - - private RestTemplate restTemplate = new RestTemplate(); - - private String apiKey; - - private HttpHeaders buildHeaders() { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.set(API_KEY, apiKey); - return headers; - } - - /** - * Generates the health assessment. - * - * @param setup test settings - * @return ResponseEntity containing health assessment - * @throws Exception any error to fail the test - */ - public ResponseEntity getAssessment(TestSetup setup) { - HttpEntity requestEntity = - new HttpEntity<>(setup.getAssessmentRequest(), buildHeaders()); - String url = BASE_URL + ASSESSMENT_END_POINT; - log.info("POST to {} with request: {}", url, requestEntity); - ResponseEntity response = restTemplate.postForEntity(url, requestEntity, String.class); - log.info("Got response: {}", response); - return response; - } - - /** - * Generates the evidence pdf. - * - * @param setup test settings - * @return ResponseEntity containing generate pdf metadata - * @throws Exception any error to fail the test - */ - public ResponseEntity generatePdf(TestSetup setup) { - HttpEntity requestEntity = - new HttpEntity<>(setup.getGeneratePdfRequest(), buildHeaders()); - String url = BASE_URL + PDF_END_POINT; - log.info("POST to {} with request: {}", url, requestEntity); - ResponseEntity response = restTemplate.postForEntity(url, requestEntity, String.class); - log.info("Got response: {}", response); - return response; - } - - /** - * Gets the evidence pdf as a byte array. - * - * @param setup test settings - * @return ResponseEntity containing evidence pdf as byte array - */ - public ResponseEntity getPdf(TestSetup setup) { - String claimSubmissionId = setup.getClaimSubmissionId(); - - HttpHeaders headers = buildHeaders(); - HttpEntity requestEntity = new HttpEntity<>(headers); - String url = BASE_URL + PDF_END_POINT + "/" + claimSubmissionId; - log.info("GET to {} with request: {}", url, requestEntity); - ResponseEntity response = - restTemplate.exchange(url, HttpMethod.GET, requestEntity, byte[].class); - log.info("Got response of type: {}", response.getBody().getClass().getSimpleName()); - return response; - } -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/SuccessResponse.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/SuccessResponse.java deleted file mode 100644 index 1c89d5b9e0..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/SuccessResponse.java +++ /dev/null @@ -1,3 +0,0 @@ -package gov.va.vro.end2end.util; - -public record SuccessResponse(boolean success) {} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/TempJurisdictionStationRequest.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/TempJurisdictionStationRequest.java deleted file mode 100644 index a87255adf1..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/TempJurisdictionStationRequest.java +++ /dev/null @@ -1,3 +0,0 @@ -package gov.va.vro.end2end.util; - -public record TempJurisdictionStationRequest(String tempJurisdictionStation) {} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/TestSetup.java b/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/TestSetup.java deleted file mode 100644 index ff5fe0d192..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/java/gov/va/vro/end2end/util/TestSetup.java +++ /dev/null @@ -1,138 +0,0 @@ -package gov.va.vro.end2end.util; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import gov.va.vro.service.provider.utils.DiagnosisLookup; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; - -/** - * This class drives end-to-end tests based on two gold files in a resource directory. The file - * assessment.json is the expected response from the server for assessment. The file - * veteranInfo.json provides the veteran information needed for pdf generation. - */ -@Getter -@RequiredArgsConstructor -public class TestSetup { - - private final String name; - - private String assessment; - private String veteranInfo; - - private JsonNode assessmentNode; - private JsonNode veteranInfoNode; - - private final ObjectMapper mapper = new ObjectMapper(); - - private String getResource(String path) throws Exception { - InputStream stream = this.getClass().getResourceAsStream(path); - return new String(stream.readAllBytes(), StandardCharsets.UTF_8); - } - - public String getDiagnosticCode() { - return assessmentNode.get("diagnosticCode").asText(); - } - - public String getClaimSubmissionId() { - return assessmentNode.get("claimSubmissionId").asText(); - } - - /** - * Provides assessment request for server. - * - * @return json assessment request - */ - public String getAssessmentRequest() { - String veteranIcn = assessmentNode.get("veteranIcn").asText(); - - ObjectNode result = mapper.createObjectNode(); - result.put("claimSubmissionId", getClaimSubmissionId()); - result.put("veteranIcn", veteranIcn); - result.put("diagnosticCode", getDiagnosticCode()); - - return result.toString(); - } - - /** - * Provides generate pdf request for server. - * - * @return json generate pdf request - */ - public String getGeneratePdfRequest() { - JsonNode evidence = assessmentNode.get("evidence"); - - ObjectNode result = mapper.createObjectNode(); - result.put("claimSubmissionId", getClaimSubmissionId()); - result.put("diagnosticCode", getDiagnosticCode()); - result.set("veteranInfo", veteranInfoNode); - result.set("evidence", evidence); - - return result.toString(); - } - - /** - * Returns expected json generate pdf response. - * - * @return expected json request - */ - public String getGeneratePdfResponse() { - ObjectNode result = mapper.createObjectNode(); - result.put("claimSubmissionId", getClaimSubmissionId()); - result.put("status", "COMPLETE"); - - return result.toString(); - } - - public JsonNode getBpReadingsNode() { - JsonNode evidence = assessmentNode.get("evidence"); - return evidence.get("bp_readings"); - } - - public JsonNode getMedicationsNode() { - JsonNode evidence = assessmentNode.get("evidence"); - return evidence.get("medications"); - } - - /** - * Returns expected content disposition filename. - * - * @return expected content disposition filename - */ - public String getContentDispositionFilename() { - Instant instant = Instant.now(); - DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd").withZone(ZoneId.of("UTC")); - String date = dtf.format(instant); - String diagnosticCode = getDiagnosticCode(); - String dcName = DiagnosisLookup.getDiagnosis(diagnosticCode); - return "VAMC_" + dcName + "_Rapid_Decision_Evidence--" + date + ".pdf"; - } - - /** - * Constructs a new test set up based on gold files in the resource directory. - * - * @param resourceDir resource directory - * @return newed TestSetup - * @throws Exception any error to fail the test - */ - public static TestSetup getInstance(String resourceDir) throws Exception { - TestSetup result = new TestSetup(resourceDir); - - String assessmentPath = String.format("/%s/assessment.json", resourceDir); - result.assessment = result.getResource(assessmentPath); - result.assessmentNode = result.mapper.readTree(result.assessment); - - String veteranInfoPath = String.format("/%s/veteranInfo.json", resourceDir); - result.veteranInfo = result.getResource(veteranInfoPath); - result.veteranInfoNode = result.mapper.readTree(result.veteranInfo); - - return result; - } -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/logback.xml b/domain-rrd/rrd-app-test/src/end2endTest/resources/logback.xml deleted file mode 100644 index 0433c6d07c..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/logback.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - %d{HH:mm:ss.SSS} %-5level %logger{36}.%M:%line - %msg%n - - - - - - - - - - - diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-6602-01/assessment.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-6602-01/assessment.json deleted file mode 100644 index 127b53e78e..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-6602-01/assessment.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "claimSubmissionId": "7002", - "diagnosticCode": "6602", - "evidence": { - "medications": [ - { - "asthmaRelevant": false, - "authoredOn": "2009-08-06T13:17:22Z", - "dataSource": "LH", - "description": "Levothyroxine Sodium 0.075 MG Oral Tablet", - "dosageInstructions": [ - "Take 1 time(s) every 60.0 day(s) - spread out evenly.", - "As directed by physician." - ], - "notes": [ - "Levothyroxine Sodium 0.075 MG Oral Tablet" - ], - "refills": 0, - "route": "As directed by physician.", - "status": "Active" - }, - { - "asthmaRelevant": false, - "authoredOn": "2008-04-23T13:17:22Z", - "dataSource": "LH", - "description": "Clopidogrel 75 MG Oral Tablet", - "notes": [ - "Clopidogrel 75 MG Oral Tablet" - ], - "refills": 0, - "status": "Active" - }, - { - "asthmaRelevant": false, - "authoredOn": "2008-04-23T13:17:22Z", - "dataSource": "LH", - "description": "24 HR metoprolol succinate 100 MG Extended Release Oral Tablet", - "notes": [ - "24 HR metoprolol succinate 100 MG Extended Release Oral Tablet" - ], - "refills": 0, - "status": "Active" - }, - { - "asthmaRelevant": false, - "authoredOn": "2008-04-23T13:17:22Z", - "dataSource": "LH", - "description": "Simvastatin 20 MG Oral Tablet", - "refills": 3, - "status": "Active" - }, - { - "asthmaRelevant": false, - "authoredOn": "2008-04-23T13:17:22Z", - "dataSource": "LH", - "description": "Nitroglycerin 0.4 MG/ACTUAT Mucosal Spray", - "refills": 1, - "status": "Active" - }, - { - "asthmaRelevant": false, - "authoredOn": "1999-01-20T15:27:05Z", - "dataSource": "LH", - "description": "Sertraline 100 MG Oral Tablet", - "notes": [ - "Sertraline 100 MG Oral Tablet" - ], - "refills": 0, - "status": "Active" - }, - { - "asthmaRelevant": false, - "authoredOn": "1999-01-20T15:27:05Z", - "dataSource": "LH", - "description": "Acetaminophen/Hydrocodone", - "notes": [ - "Acetaminophen/Hydrocodone" - ], - "refills": 0, - "status": "Active" - } - ] - }, - "evidenceSummary": { - "relevantMedCount": 0, - "totalMedCount": 7 - }, - "veteranIcn": "9000682" -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-6602-01/veteranInfo.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-6602-01/veteranInfo.json deleted file mode 100644 index 886ddd42dd..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-6602-01/veteranInfo.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "first": "Mary", - "middle": "Y", - "last": "Buck", - "suffix": "Jr", - "birthdate": "05/23/1975" -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-7101-01/assessment.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-7101-01/assessment.json deleted file mode 100644 index 5084c06a92..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-7101-01/assessment.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "veteranIcn": "1012666073V986297", - "diagnosticCode": "7101", - "evidence": { - "medications": [ - { - "status": "Active", - "description": "ALBUTEROL SO4 90MCG/ACTUAT (CFC-F) INHL,ORAL,6.7GM", - "refills": 0, - "authoredOn": "2022-03-23T01:43:31Z", - "dosageInstructions": [ - "INHALE 2 PUFFS BY INHALATION FOUR TIMES A DAY AS NEEDED FOR SHORTNESS OF BREATH OR WHEEZING", - "As directed by physician." - ], - "route": "", - "dataSource": "LH" - }, - { - "status": "Active", - "description": "MIRTAZAPINE 15MG TAB", - "refills": 2, - "authoredOn": "2022-03-06T01:43:31Z", - "dosageInstructions": [ - "TAKE ONE TABLET BY MOUTH AT BEDTIME AS NEEDED FOR SLEEP", - "As directed by physician." - ], - "route": "ORAL", - "dataSource": "LH" - }, - { - "status": "Active", - "description": "SERTRALINE HCL 100MG TA", - "refills": 0, - "authoredOn": "2022-03-06T01:43:31Z", - "dosageInstructions": [ - "TAKE ONE TABLET BY MOUTH DAILY FOR ANXIETY, MOOD, AND SLEEP", - "As directed by physician." - ], - "route": "", - "dataSource": "LH" - }, - { - "status": "Active", - "description": "Omeprazole 10 MG", - "refills": 0, - "authoredOn": "2021-04-15T08:00:00Z", - "dataSource": "LH" - }, - { - "status": "Active", - "description": "Amlodipine 5 MG Oral Tablet", - "refills": 0, - "authoredOn": "2020-08-14T08:00:00Z", - "dosageInstructions": [ - "Once Per Day", - "Twice Per Day" - ], - "route": "ORAL", - "dataSource": "LH" - }, - { - "status": "Active", - "description": "MOMETASONE FUROATE 200MCG/ACTUAT INHL,ORAL,120D,13GM", - "refills": 0, - "authoredOn": "2020-03-23T01:43:31Z", - "dosageInstructions": [], - "route": "INHALATION", - "dataSource": "LH" - }, - { - "status": "Active", - "description": "Escitalopram 10 MG", - "refills": 0, - "authoredOn": "2018-02-03T08:00:00Z", - "dosageInstructions": [ - "Once Per Day" - ], - "route": "ORAL", - "dataSource": "LH" - } - ], - "bp_readings": [ - { - "date": "2022-07-20", - "dateFormatted": "7/20/2022", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 93.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 167.0 - }, - "practitioner": "DR. JOHN248 SMITH811 MD", - "organization": "WASHINGTON VA MEDICAL CENTER", - "dataSource": "LH" - }, - { - "date": "2022-06-20", - "dateFormatted": "6/20/2022", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 93.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 167.0 - }, - "practitioner": "DR. JOHN248 SMITH811 MD", - "organization": "WASHINGTON VA MEDICAL CENTER", - "dataSource": "LH" - }, - { - "date": "2022-05-20", - "dateFormatted": "5/20/2022", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 104.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 190.0 - }, - "practitioner": "DR. JOHN248 SMITH811 MD", - "organization": "WASHINGTON VA MEDICAL CENTER", - "dataSource": "LH" - } - ] - }, - "evidenceSummary": { - "totalBpCount": 8, - "recentBpCount": 3, - "medicationsCount": 7 - }, - "claimSubmissionId": "7001" -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-7101-01/veteranInfo.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-7101-01/veteranInfo.json deleted file mode 100644 index c135483275..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-7101-01/veteranInfo.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "first": "Joe", - "middle": "M", - "last": "Doe", - "suffix": "Jr", - "birthdate": "01/04/1971" -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-10-7101-out-of-scope.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-10-7101-out-of-scope.json deleted file mode 100644 index 71578d0e8a..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-10-7101-out-of-scope.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "2000-02-19", - "firstName": "Rick", - "lastName": "Outofscope", - "gender": "male", - "collectionId": 10, - "veteranIdentifiers": { - "icn": "icn-not-needed-10", - "ssn": "010-11-1111", - "veteranFileId": "file-id-not-needed-010", - "edipn": "edipn-10", - "participantId": "participant-id-010" - }, - "claimDetail": { - "benefitClaimId": "3010", - "claimSubmissionDateTime": "2017-10-06T18:45:59Z", - "claimSubmissionSource": "VA.GOV", - "conditions": { - "name": "blood pressure", - "diagnosticCode": "7101", - "disabilityActionType": "DECREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "unknown" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-15-6602-out-of-scope.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-15-6602-out-of-scope.json deleted file mode 100644 index 4552cfbbbc..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-15-6602-out-of-scope.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "2000-02-19", - "firstName": "Rick", - "lastName": "Diagnosticcodewrong", - "gender": "male", - "collectionId": 15, - "veteranIdentifiers": { - "icn": "icn-not-needed-15", - "ssn": "015-11-1111", - "veteranFileId": "file-id-not-needed-015", - "edipn": "edipn-15", - "participantId": "participant-id-015" - }, - "claimDetail": { - "benefitClaimId": "3015", - "claimSubmissionDateTime": "2017-10-06T18:45:59Z", - "claimSubmissionSource": "VA.GOV", - "conditions": { - "name": "blood pressure", - "diagnosticCode": "6602", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "unknown" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-20-7101-no-anchor-jurisdiction.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-20-7101-no-anchor-jurisdiction.json deleted file mode 100644 index 57cf40df41..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-20-7101-no-anchor-jurisdiction.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "2000-02-19", - "firstName": "Rick", - "lastName": "Noanchor", - "gender": "make", - "collectionId": 20, - "veteranIdentifiers": { - "icn": "icn-not-needed-20", - "ssn": "020-11-1111", - "veteranFileId": "file-id-not-needed-020", - "edipn": "edipn-20", - "participantId": "participant-id-020" - }, - "claimDetail": { - "benefitClaimId": "3020", - "claimSubmissionDateTime": "2018-11-04T17:45:59Z", - "claimSubmissionSource": "VA.GOV", - "conditions": { - "name": "blood pressure", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "string" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-30-7101-no-anchor-rdr1-missing.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-30-7101-no-anchor-rdr1-missing.json deleted file mode 100644 index 6aa1b8b4cc..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-30-7101-no-anchor-rdr1-missing.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "2000-02-19", - "firstName": "Rick", - "lastName": "NoRDRD1", - "gender": "male", - "collectionId": 30, - "veteranIdentifiers": { - "icn": "icn-not-needed-30", - "ssn": "030-11-1111", - "veteranFileId": "file-id-not-needed-030", - "edipn": "edipn-30", - "participantId": "participant-id-030" - }, - "claimDetail": { - "benefitClaimId": "3030", - "claimSubmissionDateTime": "2017-10-06T18:45:59Z", - "claimSubmissionSource": "VA.GOV", - "conditions": { - "name": "blood pressure", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "unknown" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-31-7101-no-anchor-rrd-missing.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-31-7101-no-anchor-rrd-missing.json deleted file mode 100644 index 798cf0cd69..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-31-7101-no-anchor-rrd-missing.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "2000-02-19", - "firstName": "Rick", - "lastName": "Norrd", - "gender": "male", - "collectionId": 31, - "veteranIdentifiers": { - "icn": "icn-not-needed-31", - "ssn": "031-11-1111", - "veteranFileId": "file-id-not-needed-031", - "edipn": "edipn-31", - "participantId": "participant-id-031" - }, - "claimDetail": { - "benefitClaimId": "3031", - "claimSubmissionDateTime": "2017-10-06T18:45:59Z", - "claimSubmissionSource": "VA.GOV", - "conditions": { - "name": "blood pressure", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "unknown" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-32-7101-no-anchor-both-missing.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-32-7101-no-anchor-both-missing.json deleted file mode 100644 index 2e19f14d07..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-32-7101-no-anchor-both-missing.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "2000-02-19", - "firstName": "Rick", - "lastName": "Norrdorrrdone", - "gender": "male", - "collectionId": 32, - "veteranIdentifiers": { - "icn": "icn-not-needed-32", - "ssn": "032-11-1111", - "veteranFileId": "file-id-not-needed-032", - "edipn": "edipn-32", - "participantId": "participant-id-032" - }, - "claimDetail": { - "benefitClaimId": "3032", - "claimSubmissionDateTime": "2017-10-06T18:45:59Z", - "claimSubmissionSource": "VA.GOV", - "conditions": { - "name": "blood pressure", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "unknown" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-35-7101-no-anchor-no-contentions.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-35-7101-no-anchor-no-contentions.json deleted file mode 100644 index edbac60946..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-35-7101-no-anchor-no-contentions.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "2000-02-19", - "firstName": "Rick", - "lastName": "Nocontentions", - "gender": "male", - "collectionId": 35, - "veteranIdentifiers": { - "icn": "icn-not-needed-35", - "ssn": "035-11-1111", - "veteranFileId": "file-id-not-needed-035", - "edipn": "edipn-35", - "participantId": "participant-id-035" - }, - "claimDetail": { - "benefitClaimId": "3035", - "claimSubmissionDateTime": "2017-10-06T18:45:59Z", - "claimSubmissionSource": "VA.GOV", - "conditions": { - "name": "blood pressure", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "unknown" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-350-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-350-7101.json deleted file mode 100644 index eb0fbf7bd7..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-350-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "2000-02-19", - "firstName": "Rick", - "lastName": "Smith", - "gender": "string", - "collectionId": 350, - "veteranIdentifiers": { - "icn": "9000682", - "ssn": "111-11-1111", - "veteranFileId": "736444", - "edipn": "string", - "participantId": "participant1" - }, - "claimDetail": { - "benefitClaimId": "1010", - "claimSubmissionDateTime": "2018-11-04T17:45:59Z", - "claimSubmissionSource": "VA.GOV", - "conditions": { - "name": "blood pressure", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "string" - } - }, - "veteranFlashIds": [ - "999" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-365-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-365-7101.json deleted file mode 100644 index e5487f33e7..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-365-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1974-02-19", - "firstName": "Michael", - "lastName": "Lhfivehundred", - "gender": "male", - "collectionId": 365, - "veteranIdentifiers": { - "icn": "mock1012666073V986365", - "ssn": "111-11-1365", - "veteranFileId": "9999365", - "edipn": "1010234-365", - "participantId": "88888365" - }, - "claimDetail": { - "benefitClaimId": "1365", - "claimSubmissionDateTime": "2023-01-05Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-366-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-366-7101.json deleted file mode 100644 index 87044dea7b..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-366-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1974-02-19", - "firstName": "Michael", - "lastName": "Lhtimeouting", - "gender": "male", - "collectionId": 366, - "veteranIdentifiers": { - "icn": "mock1012666073V986366", - "ssn": "111-11-1366", - "veteranFileId": "9999366", - "edipn": "1010234-366", - "participantId": "88888366" - }, - "claimDetail": { - "benefitClaimId": "1366", - "claimSubmissionDateTime": "2023-01-05Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-367-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-367-7101.json deleted file mode 100644 index 52b1ae4494..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-367-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1974-02-19", - "firstName": "Michael", - "lastName": "Lhfivehundredfour", - "gender": "male", - "collectionId": 367, - "veteranIdentifiers": { - "icn": "mock1012666073V986367", - "ssn": "111-11-1367", - "veteranFileId": "9999367", - "edipn": "1010234-367", - "participantId": "88888367" - }, - "claimDetail": { - "benefitClaimId": "1367", - "claimSubmissionDateTime": "2023-01-05Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-369-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-369-7101.json deleted file mode 100644 index 6481b2eb5d..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-369-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1970-02-19", - "firstName": "Michael", - "lastName": "Masexception", - "gender": "male", - "collectionId": 369, - "veteranIdentifiers": { - "icn": "1012666073V986369", - "ssn": "111-11-1369", - "veteranFileId": "9999369", - "edipn": "1010234-369", - "participantId": "88888369" - }, - "claimDetail": { - "benefitClaimId": "1369", - "claimSubmissionDateTime": "2023-01-05Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-37-7101-no-anchor-empty-contentions.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-37-7101-no-anchor-empty-contentions.json deleted file mode 100644 index 747d265e16..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-37-7101-no-anchor-empty-contentions.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "2000-02-19", - "firstName": "Rick", - "lastName": "Nocontentions", - "gender": "male", - "collectionId": 37, - "veteranIdentifiers": { - "icn": "icn-not-needed-37", - "ssn": "037-11-1111", - "veteranFileId": "file-id-not-needed-037", - "edipn": "edipn-37", - "participantId": "participant-id-037" - }, - "claimDetail": { - "benefitClaimId": "3037", - "claimSubmissionDateTime": "2017-10-06T18:45:59Z", - "claimSubmissionSource": "VA.GOV", - "conditions": { - "name": "blood pressure", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "unknown" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-370-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-370-7101.json deleted file mode 100644 index 28b800c50f..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-370-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1970-02-19", - "firstName": "Michael", - "lastName": "MasBipexception", - "gender": "male", - "collectionId": 370, - "veteranIdentifiers": { - "icn": "mock1012666073V986370", - "ssn": "111-11-1370", - "veteranFileId": "9999370", - "edipn": "1010234-370", - "participantId": "88888370" - }, - "claimDetail": { - "benefitClaimId": "1370", - "claimSubmissionDateTime": "2023-01-05Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-375-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-375-7101.json deleted file mode 100644 index c2ae789cc1..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-375-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1970-02-19", - "firstName": "Michael", - "lastName": "Streetwalker", - "gender": "male", - "collectionId": 375, - "veteranIdentifiers": { - "icn": "1012666073V986297", - "ssn": "111-11-1375", - "veteranFileId": "9999375", - "edipn": "1010234-375", - "participantId": "88888375" - }, - "claimDetail": { - "benefitClaimId": "1015", - "claimSubmissionDateTime": "2023-01-05Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-376-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-376-7101.json deleted file mode 100644 index 7be3e3f03b..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-376-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1968-02-19", - "firstName": "David", - "lastName": "Skyscraper", - "gender": "male", - "collectionId": 376, - "veteranIdentifiers": { - "icn": "mock1012666073V986297", - "ssn": "111-11-1376", - "veteranFileId": "9999376", - "edipn": "1010234-376", - "participantId": "88888376" - }, - "claimDetail": { - "benefitClaimId": "1020", - "claimSubmissionDateTime": "2023-02-08T18:45:59Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "NEW", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-377-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-377-7101.json deleted file mode 100644 index d8cfbbe20c..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-377-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1970-02-19", - "firstName": "Janet", - "lastName": "Baristanew", - "gender": "female", - "collectionId": 377, - "veteranIdentifiers": { - "icn": "mock1012666073V986377", - "ssn": "111-11-1377", - "veteranFileId": "9999377", - "edipn": "1010234-377", - "participantId": "88888377" - }, - "claimDetail": { - "benefitClaimId": "1040", - "claimSubmissionDateTime": "2023-02-27Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hypertension", - "diagnosticCode": "7101", - "disabilityActionType": "NEW", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-378-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-378-7101.json deleted file mode 100644 index 8a2640042d..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-378-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1970-02-19", - "firstName": "Janet", - "lastName": "Baristaincrease", - "gender": "female", - "collectionId": 378, - "veteranIdentifiers": { - "icn": "mock1012666073V986378", - "ssn": "111-11-1378", - "veteranFileId": "9999378", - "edipn": "1010234-378", - "participantId": "88888378" - }, - "claimDetail": { - "benefitClaimId": "1041", - "claimSubmissionDateTime": "2023-02-27Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hypertension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-379-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-379-7101.json deleted file mode 100644 index 3d779d5b9f..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-379-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1968-02-19", - "firstName": "David", - "lastName": "NotPresumptive", - "gender": "male", - "collectionId": 379, - "veteranIdentifiers": { - "icn": "mock1012666073V986379", - "ssn": "111-11-1379", - "veteranFileId": "9999379", - "edipn": "1010234-379", - "participantId": "88888379" - }, - "claimDetail": { - "benefitClaimId": "1379", - "claimSubmissionDateTime": "2023-02-08T18:45:59Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "NEW", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "NotPresumptive" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-380-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-380-7101.json deleted file mode 100644 index c0b1c9da8e..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-380-7101.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "dob": "1965-02-19", - "firstName": "Michael", - "lastName": "Imcompletebps", - "gender": "male", - "collectionId": 380, - "veteranIdentifiers": { - "icn": "mock1012666073V986380", - "ssn": "111-11-1380", - "veteranFileId": "9999380", - "edipn": "1010234-380", - "participantId": "88888380" - }, - "claimDetail": { - "benefitClaimId": "1055", - "claimSubmissionDateTime": "2023-01-05Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375", - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-381-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-381-7101.json deleted file mode 100644 index 5f7a3a685c..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-381-7101.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "dob": "1965-02-19", - "firstName": "Michael", - "lastName": "Duplicatebps", - "gender": "male", - "collectionId": 381, - "veteranIdentifiers": { - "icn": "mock1012666073V986381", - "ssn": "111-11-1381", - "veteranFileId": "9999381", - "edipn": "1010234-381", - "participantId": "88888381" - }, - "claimDetail": { - "benefitClaimId": "1056", - "claimSubmissionDateTime": "2023-01-05Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375", - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-385-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-385-7101.json deleted file mode 100644 index 852af68d56..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-385-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1975-08-29", - "firstName": "Betty", - "lastName": "Changingstation", - "gender": "female", - "collectionId": 385, - "veteranIdentifiers": { - "icn": "1012666073V986385", - "ssn": "111-11-1375", - "veteranFileId": "9999385", - "edipn": "1010234-385", - "participantId": "88888385" - }, - "claimDetail": { - "benefitClaimId": "1085", - "claimSubmissionDateTime": "2023-01-05Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-386-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-386-7101.json deleted file mode 100644 index 913e93c227..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-386-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1975-08-29", - "firstName": "Mary", - "lastName": "Bipdown", - "gender": "female", - "collectionId": 386, - "veteranIdentifiers": { - "icn": "1012666073V986386", - "ssn": "111-11-1375", - "veteranFileId": "9999386", - "edipn": "1010234-386", - "participantId": "88888386" - }, - "claimDetail": { - "benefitClaimId": "1086", - "claimSubmissionDateTime": "2023-01-05Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-390-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-390-7101.json deleted file mode 100644 index a1d5a8fed9..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-390-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1963-05-13", - "firstName": "Noah", - "lastName": "Cannotuploadpdfforexam", - "gender": "male", - "collectionId": 390, - "veteranIdentifiers": { - "icn": "mock1012666073V986390", - "ssn": "111-11-1390", - "veteranFileId": "9999390", - "edipn": "1010234-390", - "participantId": "88888390" - }, - "claimDetail": { - "benefitClaimId": "1390", - "claimSubmissionDateTime": "2023-03-12Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hypertension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-391-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-391-7101.json deleted file mode 100644 index eee84667fa..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-391-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1963-05-13", - "firstName": "Noah", - "lastName": "CannotOrderExam", - "gender": "male", - "collectionId": 391, - "veteranIdentifiers": { - "icn": "mock1012666073V986391", - "ssn": "111-11-1391", - "veteranFileId": "9999391", - "edipn": "1010234-391", - "participantId": "88888391" - }, - "claimDetail": { - "benefitClaimId": "1391", - "claimSubmissionDateTime": "2023-03-12Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hypertension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-392-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-392-7101.json deleted file mode 100644 index e243855f2d..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-392-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1970-02-19", - "firstName": "Michael", - "lastName": "NoExamPDFFAILURE", - "gender": "male", - "collectionId": 392, - "veteranIdentifiers": { - "icn": "mock1012666073V986392", - "ssn": "111-11-1375", - "veteranFileId": "9999392", - "edipn": "1010234-375", - "participantId": "88888392" - }, - "claimDetail": { - "benefitClaimId": "1392", - "claimSubmissionDateTime": "2023-01-05Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-40-7101-no-anchor-multi-contentions.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-40-7101-no-anchor-multi-contentions.json deleted file mode 100644 index f7cdd41209..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-40-7101-no-anchor-multi-contentions.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "2000-02-19", - "firstName": "Rick", - "lastName": "Multicontentions", - "gender": "male", - "collectionId": 40, - "veteranIdentifiers": { - "icn": "icn-not-needed-40", - "ssn": "040-11-1111", - "veteranFileId": "file-id-not-needed-040", - "edipn": "edipn-40", - "participantId": "participant-id-040" - }, - "claimDetail": { - "benefitClaimId": "3040", - "claimSubmissionDateTime": "2017-10-06T18:45:59Z", - "claimSubmissionSource": "VA.GOV", - "conditions": { - "name": "blood pressure", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "unknown" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-400-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-400-7101.json deleted file mode 100644 index 9293385de1..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-400-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1970-02-19", - "firstName": "Janet", - "lastName": "NoMasOrderExam", - "gender": "female", - "collectionId": 400, - "veteranIdentifiers": { - "icn": "mock1012666073V986400", - "ssn": "111-11-1400", - "veteranFileId": "9999400", - "edipn": "1010234-400", - "participantId": "88888400" - }, - "claimDetail": { - "benefitClaimId": "2010", - "claimSubmissionDateTime": "2023-02-27Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hypertension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-401-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-401-7101.json deleted file mode 100644 index 6818811e49..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-401-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1970-02-19", - "firstName": "Janet", - "lastName": "NoMasRRD", - "gender": "female", - "collectionId": 401, - "veteranIdentifiers": { - "icn": "mock1012666073V986401", - "ssn": "111-11-1400", - "veteranFileId": "9999401", - "edipn": "1010234-400", - "participantId": "88888401" - }, - "claimDetail": { - "benefitClaimId": "2020", - "claimSubmissionDateTime": "2023-02-27Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hypertension", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "999375" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-500-7101.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-500-7101.json deleted file mode 100644 index a2f5a1c7dc..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-500-7101.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "1968-02-19", - "firstName": "Marano", - "lastName": "Ucamata", - "gender": "male", - "collectionId": 500, - "veteranIdentifiers": { - "icn": "mock1012666073V986500", - "ssn": "111-11-1500", - "veteranFileId": "099999500", - "edipn": "1010234-500", - "participantId": "88888500" - }, - "claimDetail": { - "benefitClaimId": "1030", - "claimSubmissionDateTime": "2023-02-08T18:45:59Z", - "claimSubmissionSource": "MAS", - "conditions": { - "name": "Hyperotension", - "diagnosticCode": "7101", - "disabilityActionType": "NEW", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "7645" - } - }, - "veteranFlashIds": [ - "Agent Orange Exposure Verified" - ] -} diff --git a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-801-7101-nonexistent-claimid.json b/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-801-7101-nonexistent-claimid.json deleted file mode 100644 index c8d4126836..0000000000 --- a/domain-rrd/rrd-app-test/src/end2endTest/resources/test-mas/claim-801-7101-nonexistent-claimid.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "dob": "2000-08-01", - "firstName": "Richard", - "lastName": "Malone", - "gender": "male", - "collectionId": 801, - "veteranIdentifiers": { - "icn": "9000355", - "ssn": "111-11-1801", - "veteranFileId": "736801", - "edipn": "6377716VV801", - "participantId": "7677801" - }, - "claimDetail": { - "benefitClaimId": "998899", - "claimSubmissionDateTime": "2018-11-04T17:45:59Z", - "claimSubmissionSource": "VA.GOV", - "conditions": { - "name": "HYPERTENSION", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "disabilityClassificationCode": "3460", - "ratedDisabilityId": "234555" - } - }, - "veteranFlashIds": [ - "888" - ] -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/BaseIntegrationTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/BaseIntegrationTest.java deleted file mode 100644 index be1bc80ad0..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/BaseIntegrationTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package gov.va.vro; - -import gov.va.vro.persistence.repository.AuditEventRepository; -import gov.va.vro.persistence.repository.ClaimRepository; -import gov.va.vro.persistence.repository.ClaimSubmissionRepository; -import gov.va.vro.persistence.repository.VeteranRepository; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -@SpringBootTest -@ActiveProfiles("test") -public abstract class BaseIntegrationTest { - - @Autowired protected ClaimRepository claimRepository; - - @Autowired protected ClaimSubmissionRepository claimSubmissionRepository; - - @Autowired protected VeteranRepository veteranRepository; - - @Autowired protected AuditEventRepository auditEventRepository; - - /** Delete all from repositories. */ - @BeforeEach - @AfterEach - public void delete() { - claimRepository.deleteAll(); - // Claim repository will cascade delete from claimSubmission - veteranRepository.deleteAll(); - auditEventRepository.deleteAll(); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/BipServiceTestConfiguration.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/BipServiceTestConfiguration.java deleted file mode 100644 index 119b9b0049..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/BipServiceTestConfiguration.java +++ /dev/null @@ -1,22 +0,0 @@ -package gov.va.vro; - -import gov.va.vro.service.MockBipApiService; -import gov.va.vro.service.provider.bip.service.IBipApiService; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; - -/** - * BIP test configuration. - * - * @author warren @Date 2/10/23 - */ -@TestConfiguration -public class BipServiceTestConfiguration { - - @Bean - @Primary - public IBipApiService getBipApiService() { - return new MockBipApiService(); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/ClaimRepositoryTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/ClaimRepositoryTest.java deleted file mode 100644 index 612f213754..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/ClaimRepositoryTest.java +++ /dev/null @@ -1,104 +0,0 @@ -package gov.va.vro; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import gov.va.vro.persistence.model.AssessmentResultEntity; -import gov.va.vro.persistence.model.ContentionEntity; -import gov.va.vro.persistence.model.EvidenceSummaryDocumentEntity; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -class ClaimRepositoryTest extends BaseIntegrationTest { - - @Test - void insertQuery() { - Date icnTimestamp = new Date(); - - var veteran = TestDataSupplier.createVeteran("X", "Y", icnTimestamp); - veteranRepository.save(veteran); - assertNotNull(veteran.getIcn()); - assertNotNull(veteran.getIcnTimestamp()); - assertNotNull(veteran.getCreatedAt()); - assertNotNull(veteran.getUpdatedAt()); - - EvidenceSummaryDocumentEntity evidenceSummaryDocument1 = new EvidenceSummaryDocumentEntity(); - Map count1 = new HashMap<>(); - count1.put("count", "1"); - evidenceSummaryDocument1.setEvidenceCount(count1); - evidenceSummaryDocument1.setDocumentName("documentName1"); - EvidenceSummaryDocumentEntity evidenceSummaryDocument2 = new EvidenceSummaryDocumentEntity(); - Map count2 = new HashMap<>(); - count2.put("count2", "2"); - evidenceSummaryDocument2.setEvidenceCount(count2); - evidenceSummaryDocument2.setDocumentName("documentName2"); - Map evidence = new HashMap<>(); - evidence.put("medicationsCount", "10"); - AssessmentResultEntity assessmentResult = new AssessmentResultEntity(); - assessmentResult.setEvidenceCountSummary(evidence); - ContentionEntity contention1 = new ContentionEntity("c1"); - contention1.addAssessmentResult(assessmentResult); - contention1.addEvidenceSummaryDocument(evidenceSummaryDocument1); - contention1.addEvidenceSummaryDocument(evidenceSummaryDocument2); - - ContentionEntity contention2 = new ContentionEntity("c2"); - Map evidence2 = new HashMap<>(); - AssessmentResultEntity ar2 = new AssessmentResultEntity(); - evidence2.put("medicationsCount", "10"); - ar2.setEvidenceCountSummary(evidence2); - contention2.addAssessmentResult(ar2); - - var claim = TestDataSupplier.createClaim("123", veteran, "refId"); - claim.addContention(contention1); - claim.addContention(contention2); - - claim = claimRepository.save(claim); - assertNotNull(claim.getId()); - assertNotNull(claim.getCreatedAt()); - - List contentions = claim.getContentions(); - assertEquals(2, contentions.size()); - contentions.forEach(contention -> assertNotNull(contention.getId())); - contentions.stream() - .filter(contention -> "c1".equals(contention.getDiagnosticCode())) - .findAny() - .ifPresentOrElse( - contention -> assertEquals(2, contention1.getEvidenceSummaryDocuments().size()), - Assertions::fail); - contentions.stream() - .filter(contention -> "c1".equals(contention.getDiagnosticCode())) - .findAny() - .ifPresentOrElse( - contention -> - assertEquals( - evidence, contention1.getAssessmentResults().get(0).getEvidenceCountSummary()), - Assertions::fail); - contentions.stream() - .filter(contention -> "c2".equals(contention.getDiagnosticCode())) - .findAny() - .ifPresentOrElse( - contention -> assertEquals(1, contention2.getAssessmentResults().size()), - Assertions::fail); - contentions.stream() - .filter(contention -> "c2".equals(contention.getDiagnosticCode())) - .findAny() - .ifPresentOrElse( - contention -> - assertEquals( - evidence2, contention2.getAssessmentResults().get(0).getEvidenceCountSummary()), - Assertions::fail); - assertEquals( - contention1.getEvidenceSummaryDocuments().get(0).getDocumentName(), "documentName1"); - assertEquals(contention1.getEvidenceSummaryDocuments().get(0).getEvidenceCount().size(), 1); - assertEquals(contention1.getEvidenceSummaryDocuments().get(0).getEvidenceCount(), count1); - assertEquals( - contention1.getEvidenceSummaryDocuments().get(1).getDocumentName(), "documentName2"); - assertEquals(contention1.getEvidenceSummaryDocuments().get(1).getEvidenceCount().size(), 1); - assertEquals(contention1.getEvidenceSummaryDocuments().get(1).getEvidenceCount(), count2); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/EvidenceSummaryDocumentProcessorTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/EvidenceSummaryDocumentProcessorTest.java deleted file mode 100644 index 2c52c4fb84..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/EvidenceSummaryDocumentProcessorTest.java +++ /dev/null @@ -1,104 +0,0 @@ -package gov.va.vro; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.api.rrd.requests.GeneratePdfRequest; -import gov.va.vro.api.rrd.responses.GeneratePdfResponse; -import gov.va.vro.config.AppTestConfig; -import gov.va.vro.controller.BaseControllerTest; -import gov.va.vro.persistence.model.ContentionEntity; -import gov.va.vro.persistence.model.EvidenceSummaryDocumentEntity; -import gov.va.vro.persistence.repository.ClaimRepository; -import gov.va.vro.service.spi.model.GeneratePdfPayload; -import org.apache.camel.test.spring.junit5.CamelSpringBootTest; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Import; -import org.springframework.core.io.Resource; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ActiveProfiles; - -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Date; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@ActiveProfiles("test") -@Import(AppTestConfig.class) -@CamelSpringBootTest -public class EvidenceSummaryDocumentProcessorTest extends BaseControllerTest { - - @Value("classpath:test-data/pdf-generator-input-01.json") - private Resource pdfGeneratorInput01; - - @Autowired protected ClaimRepository claimRepository; - - Date icnTimestamp = new Date(); - - @Test - @DirtiesContext - void positiveEvidenceSummaryDocumentProcessor() throws Exception { - // Create veteran, claim, and contention and save. - Date icnTimestamp = new Date(); - var veteran = TestDataSupplier.createVeteran("X", "Y", icnTimestamp); - veteranRepository.save(veteran); - ContentionEntity contention = new ContentionEntity("7101"); - // ReferenceId, is also claimSubmissionId in v1. When we create the claim and submission, that - // referenceId must match in the PDF requests sent later. - var claim = TestDataSupplier.createClaim(null, veteran, "1234"); - claim.addContention(contention); - claim = claimRepository.save(claim); - - // Call generate-pdf endpoint to activate the Evidence Summary Document processor. - var mapper = new ObjectMapper(); - InputStream stream = pdfGeneratorInput01.getInputStream(); - String inputAsString = new String(stream.readAllBytes(), StandardCharsets.UTF_8); - GeneratePdfRequest input = mapper.readValue(inputAsString, GeneratePdfRequest.class); - post("/v1/evidence-pdf", input, GeneratePdfResponse.class); - - // Verify that the evidence summary document is created and saved correctly. - assertNotNull(claim.getId()); - var claim2 = claimRepository.findById(claim.getId()).orElse(null); - assertNotNull(claim2); - assertEquals(claim2.getContentions().get(0).getEvidenceSummaryDocuments().size(), 1); - EvidenceSummaryDocumentEntity evidenceSummaryDocument = - claim2.getContentions().get(0).getEvidenceSummaryDocuments().get(0); - assertEquals(evidenceSummaryDocument.getEvidenceCount().get("medicationsCount"), "2"); - assertEquals(evidenceSummaryDocument.getEvidenceCount().get("totalBpReadings"), "3"); - String diagnosis = "Hypertension"; - String documentName = GeneratePdfPayload.createPdfFilename(diagnosis); - assertEquals(evidenceSummaryDocument.getDocumentName(), documentName); - assertEquals(evidenceSummaryDocument.getContention().getId(), contention.getId()); - } - - @Test - @DirtiesContext - void negativeEvidenceSummaryDocumentProcessorWrongDiagnosticCode() throws Exception { - // Create veteran and save. - var veteran = TestDataSupplier.createVeteran("X", "Y", icnTimestamp); - veteranRepository.save(veteran); - - // Create a contention and set an invalid diagnostic code, then create claim and add. - ContentionEntity contention = new ContentionEntity("1111"); - var claim = TestDataSupplier.createClaim(null, veteran, "refId"); - claim.addContention(contention); - claim = claimRepository.save(claim); - - // Call generate-pdf endpoint to activate the Evidence Summary Document processor. - var mapper = new ObjectMapper(); - InputStream stream = pdfGeneratorInput01.getInputStream(); - String inputAsString = new String(stream.readAllBytes(), StandardCharsets.UTF_8); - GeneratePdfRequest input = mapper.readValue(inputAsString, GeneratePdfRequest.class); - post("/v1/evidence-pdf", input, GeneratePdfResponse.class); - - // Verify that the evidence summary document is not created or saved. - assertNotNull(claim.getId()); - var claim2 = claimRepository.findById(claim.getId()).orElse(null); - assertNotNull(claim2); - assertEquals(claim2.getContentions().get(0).getEvidenceSummaryDocuments().size(), 0); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/MasTestData.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/MasTestData.java deleted file mode 100644 index 09870bb005..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/MasTestData.java +++ /dev/null @@ -1,106 +0,0 @@ -package gov.va.vro; - -import gov.va.vro.model.rrd.mas.ClaimCondition; -import gov.va.vro.model.rrd.mas.ClaimDetail; -import gov.va.vro.model.rrd.mas.MasAnnotation; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.MasDocument; -import gov.va.vro.model.rrd.mas.VeteranIdentifiers; -import gov.va.vro.model.rrd.mas.request.MasAutomatedClaimRequest; - -import java.util.Collections; -import java.util.UUID; - -public class MasTestData { - - public static MasAutomatedClaimPayload getMasAutomatedClaimPayload() { - return getMasAutomatedClaimPayload(123, "7101", "999"); - } - - /** - * Gets the automated claim payload. - * - * @param collectionId collection ID. - * @param diagnosticCode diagnostic code. - * @param claimId claim ID. - * @return Claim payload. - */ - public static MasAutomatedClaimPayload getMasAutomatedClaimPayload( - int collectionId, String diagnosticCode, String claimId) { - VeteranIdentifiers veteranIdentifiers = getVeteranIdentifiers(); - ClaimDetail claimDetail = getClaimDetail(diagnosticCode, claimId); - - return MasAutomatedClaimPayload.builder() - .dateOfBirth("2002-12-12") - .collectionId(collectionId) - .firstName("Rick") - .lastName("Smith") - .veteranIdentifiers(veteranIdentifiers) - .claimDetail(claimDetail) - .correlationId(UUID.randomUUID().toString()) - .build(); - } - - public static MasAutomatedClaimRequest getMasAutomatedClaimRequest() { - return getMasAutomatedClaimRequest(123, "1233", "999"); - } - - /** - * Build claim request. - * - * @param collectionId collection ID. - * @param diagnosticCode diagnostic code. - * @param benefitClaimId benefit claim ID - * @return Claim request - */ - public static MasAutomatedClaimRequest getMasAutomatedClaimRequest( - int collectionId, String diagnosticCode, String benefitClaimId) { - VeteranIdentifiers veteranIdentifiers = getVeteranIdentifiers(); - ClaimDetail claimDetail = getClaimDetail(diagnosticCode, benefitClaimId); - - return MasAutomatedClaimRequest.builder() - .dateOfBirth("2002-12-12") - .collectionId(collectionId) - .firstName("Rick") - .lastName("Smith") - .veteranIdentifiers(veteranIdentifiers) - .claimDetail(claimDetail) - .build(); - } - - private static ClaimDetail getClaimDetail(String diagnosticCode, String claimId) { - ClaimCondition conditions = new ClaimCondition(); - conditions.setDiagnosticCode(diagnosticCode); - conditions.setDisabilityActionType("INCREASE"); - ClaimDetail claimDetail = new ClaimDetail(); - claimDetail.setClaimSubmissionDateTime("2022-02-04T17:45:59Z"); - claimDetail.setConditions(conditions); - claimDetail.setBenefitClaimId(claimId); - return claimDetail; - } - - private static VeteranIdentifiers getVeteranIdentifiers() { - VeteranIdentifiers veteranIdentifiers = new VeteranIdentifiers(); - veteranIdentifiers.setEdipn("X"); - veteranIdentifiers.setParticipantId("X"); - veteranIdentifiers.setIcn("X"); - veteranIdentifiers.setSsn("X"); - veteranIdentifiers.setVeteranFileId("X"); - return veteranIdentifiers; - } - - /** - * Creates hypertension document. - * - * @return the document. - */ - public static MasDocument createHypertensionDocument() { - var document = new MasDocument(); - document.setCondition("Hypertension"); - var annotation = new MasAnnotation(); - annotation.setAnnotType("Medication"); - annotation.setAnnotVal("Placebo"); - document.setAnnotations(Collections.singletonList(annotation)); - return document; - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/TestDataSupplier.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/TestDataSupplier.java deleted file mode 100644 index aab4ed8ccd..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/TestDataSupplier.java +++ /dev/null @@ -1,52 +0,0 @@ -package gov.va.vro; - -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.persistence.model.ClaimEntity; -import gov.va.vro.persistence.model.ClaimSubmissionEntity; -import gov.va.vro.persistence.model.VeteranEntity; -import gov.va.vro.service.spi.model.Claim; - -import java.util.Date; - -public class TestDataSupplier { - /*** - *

Summary.

- * - * @param icn veteran ICN - * - * @param participantId participant ID - * - * @return return value - */ - public static VeteranEntity createVeteran(String icn, String participantId, Date icnTimestamp) { - VeteranEntity veteran = new VeteranEntity(); - veteran.setIcn(icn); - veteran.setParticipantId(participantId); - veteran.setIcnTimestamp(icnTimestamp); - return veteran; - } - - /*** - *

Summary.

- * - * @param benefitClaimId ID , this may be null in v1 calls - * @param veteran veteran - * @param referenceId also known as claimSubmissionId - * @return return - */ - public static ClaimEntity createClaim( - String benefitClaimId, VeteranEntity veteran, String referenceId) { - ClaimEntity claim = new ClaimEntity(); - claim.setVbmsId(benefitClaimId); - claim.setVeteran(veteran); - ClaimSubmissionEntity claimSubmission = new ClaimSubmissionEntity(); - claimSubmission.setReferenceId(referenceId); - if (benefitClaimId == null) { - claimSubmission.setIdType(Claim.V1_ID_TYPE); - } else { - claimSubmission.setIdType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - } - claim.addClaimSubmission(claimSubmission); - return claim; - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/VroApplicationTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/VroApplicationTest.java deleted file mode 100644 index 729a5c9cd4..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/VroApplicationTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package gov.va.vro; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -@SpringBootTest -@ActiveProfiles("test") -class VroApplicationTest { - - @Test - void contextLoads() {} -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/config/AppTestConfig.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/config/AppTestConfig.java deleted file mode 100644 index a133b157b7..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/config/AppTestConfig.java +++ /dev/null @@ -1,12 +0,0 @@ -package gov.va.vro.config; - -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; - -@TestConfiguration -public class AppTestConfig { - @Bean - public AppTestUtil appTestUtil() { - return new AppTestUtil(); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/config/AppTestUtil.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/config/AppTestUtil.java deleted file mode 100644 index a6e2d677d2..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/config/AppTestUtil.java +++ /dev/null @@ -1,45 +0,0 @@ -package gov.va.vro.config; - -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.HealthDataAssessment; -import gov.va.vro.service.spi.model.Claim; -import lombok.SneakyThrows; - -/** Common utility methods used by the app tests. */ -public class AppTestUtil { - private final ObjectMapper mapper = new ObjectMapper(); - - /** - * JSON object to string. - * - * @param o object to stringify. - * @return json as string. - */ - @SneakyThrows - public String toJsonString(Object o) { - return mapper.writeValueAsString(o); - } - - /** - * Claim object to string response. - * - * @param claim claim. - * @param evidence evidence. - * @return claim response to string. - */ - @SneakyThrows - public String claimToResponse(Claim claim, boolean evidence, String errorMessage) { - var response = new HealthDataAssessment(); - response.setDiagnosticCode(claim.getDiagnosticCode()); - response.setVeteranIcn(claim.getVeteranIcn()); - // CollectionId is equivalent to the reference_id on the claim_submission table, which is what - // other entities expect to see as the claimSubmissionId. - response.setClaimSubmissionId(claim.getCollectionId()); - response.setErrorMessage(errorMessage); - if (evidence) { - response.setEvidence(new AbdEvidence()); - } - return mapper.writeValueAsString(response); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/config/MasAuthTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/config/MasAuthTest.java deleted file mode 100644 index 155cb542ad..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/config/MasAuthTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package gov.va.vro.config; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import gov.va.vro.controller.BaseControllerTest; -import gov.va.vro.security.ApiAuthKeyManager; -import gov.va.vro.security.JwtValidator; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.security.core.Authentication; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ActiveProfiles; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@ActiveProfiles("test") -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) -public class MasAuthTest extends BaseControllerTest { - @Mock Authentication authentication; - - @InjectMocks @Autowired JwtValidator jwtValidator; - @InjectMocks @Autowired ApiAuthKeyManager apiAuthKeyManager; - - @Test - void testNotAuthenticated() { - assertFalse(apiAuthKeyManager.authenticate(authentication).isAuthenticated()); - } - - @Test - void testAuthenticateHeader() { - - MockHttpServletRequest httpServletRequest = new MockHttpServletRequest(); - httpServletRequest.setRequestURI("/v2/automatedClaim"); - apiAuthKeyManager.setHttpServletRequest(httpServletRequest); - String sampleJwt = - """ - eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImMwOTI5NTJlLTM4ZDYtNDNjNi0\ - 5MzBlLWZmOTNiYTUxYjA4ZiJ9.eyJleHAiOjk5OTk5OTk5OTksImlhdCI6MTY0MTA2Nzk0O\ - SwianRpIjoiNzEwOTAyMGEtMzlkOS00MWE4LThlNzgtNTllZjAwYTlkNDJlIiwiaXNzIjoi\ - aHR0cHM6Ly9zYW5kYm94LWFwaS52YS5nb3YvaW50ZXJuYWwvYXV0aC92Mi92YWxpZGF0aW9\ - uIiwiYXVkIjoibWFzX2RldiIsInN1YiI6IjhjNDkyY2NmLTk0OGYtNDQ1Zi05NmY4LTMxZT\ - dmODU5MDlkMiIsInR5cCI6IkJlYXJlciIsImF6cCI6Im1hc19kZXYiLCJzY29wZSI6Im9wZ\ - W5pZCB2cm9fbWFzIiwiY2xpZW50SWQiOiJtYXNfZGV2In0.Qb41CR1JIGGRlryi-XVtqyeN\ - W73cU1YeBVqs9Bps3TA"""; - - String authorizationHdr = "Bearer " + sampleJwt; - when(authentication.getPrincipal()).thenReturn(authorizationHdr); - apiAuthKeyManager.authenticate(authentication); - verify(authentication).setAuthenticated(true); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/BaseControllerTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/BaseControllerTest.java deleted file mode 100644 index 00236669ba..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/BaseControllerTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package gov.va.vro.controller; - -import gov.va.vro.BaseIntegrationTest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; - -import java.util.Map; - -public abstract class BaseControllerTest extends BaseIntegrationTest { - - @Autowired protected TestRestTemplate testRestTemplate; - - protected ResponseEntity post(String url, I request, Class responseType) { - return exchange(url, request, HttpMethod.POST, responseType); - } - - protected ResponseEntity post( - String url, I request, Map headers, Class responseType) { - return exchange(url, request, HttpMethod.POST, headers, responseType); - } - - protected ResponseEntity put( - String url, I request, Map headers, Class responseType) { - return exchange(url, request, HttpMethod.PUT, headers, responseType); - } - - protected ResponseEntity get(String url, I request, Class responseType) { - return exchange(url, request, HttpMethod.GET, responseType); - } - - protected ResponseEntity get( - String url, I request, Map headers, Class responseType) { - return exchange(url, request, HttpMethod.GET, headers, responseType); - } - - protected ResponseEntity exchange( - String url, - I request, - HttpMethod method, - Map headersIn, - Class responseType) { - HttpHeaders headers = new HttpHeaders(); - headers.add("X-API-Key", "test-key-01"); - headers.add("Authorization", "Bearer " + sampleJwt); - if (headersIn != null) { - headersIn.forEach( - (key, value) -> { - headers.add(key, value); - }); - } - var httpEntity = new HttpEntity<>(request, headers); - return testRestTemplate.exchange(url, method, httpEntity, responseType); - } - - protected ResponseEntity exchange( - String url, I request, HttpMethod method, Class responseType) { - return exchange(url, request, method, null, responseType); - } - - String sampleJwt = - """ - eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImMwOTI5NTJlLTM4ZD\ - YtNDNjNi05MzBlLWZmOTNiYTUxYjA4ZiJ9.eyJleHAiOjk5OTk5OTk5OTksIml\ - hdCI6MTY0MTA2Nzk0OSwianRpIjoiNzEwOTAyMGEtMzlkOS00MWE4LThlNzgtN\ - TllZjAwYTlkNDJlIiwiaXNzIjoiaHR0cHM6Ly9zYW5kYm94LWFwaS52YS5nb3Y\ - vaW50ZXJuYWwvYXV0aC92Mi92YWxpZGF0aW9uIiwiYXVkIjoibWFzX2RldiIsI\ - nN1YiI6IjhjNDkyY2NmLTk0OGYtNDQ1Zi05NmY4LTMxZTdmODU5MDlkMiIsInR\ - 5cCI6IkJlYXJlciIsImF6cCI6Im1hc19kZXYiLCJzY29wZSI6Im9wZW5pZCB2c\ - m9fbWFzIiwiY2xpZW50SWQiOiJtYXNfZGV2In0.Qb41CR1JIGGRlryi-XVtqye\ - NW73cU1YeBVqs9Bps3TA"""; -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/ClaimMetricsControllerApiTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/ClaimMetricsControllerApiTest.java deleted file mode 100644 index 2ced86691a..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/ClaimMetricsControllerApiTest.java +++ /dev/null @@ -1,380 +0,0 @@ -package gov.va.vro.controller; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import com.tngtech.archunit.thirdparty.com.google.common.collect.ImmutableMap; -import gov.va.vro.model.rrd.claimmetrics.AssessmentInfo; -import gov.va.vro.model.rrd.claimmetrics.ClaimInfoQueryParams; -import gov.va.vro.model.rrd.claimmetrics.ClaimsInfo; -import gov.va.vro.model.rrd.claimmetrics.ContentionInfo; -import gov.va.vro.model.rrd.claimmetrics.DocumentInfo; -import gov.va.vro.model.rrd.claimmetrics.ExamOrderInfoQueryParams; -import gov.va.vro.model.rrd.claimmetrics.ExamOrdersInfo; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimInfoResponse; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimMetricsResponse; -import gov.va.vro.model.rrd.claimmetrics.response.ExamOrderInfoResponse; -import gov.va.vro.service.spi.model.Claim; -import gov.va.vro.service.spi.services.ClaimMetricsService; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.ActiveProfiles; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@ActiveProfiles("test") -@ExtendWith(MockitoExtension.class) -public class ClaimMetricsControllerApiTest extends BaseControllerTest { - private static final AtomicInteger counter = new AtomicInteger(0); - - @MockBean private ClaimMetricsService service; - - @Autowired TestRestTemplate restTemplate; - - public ObjectMapper createObjectMapper() { - return JsonMapper.builder().addModule(new JavaTimeModule()).build(); - } - - private final ObjectMapper mapper = createObjectMapper(); - - // Generates a generic ClaimInfoResponse object. - private ClaimInfoResponse generateClaimInfoResponse() { - int index = counter.getAndIncrement(); - - ClaimInfoResponse result = new ClaimInfoResponse(); - - result.setClaimSubmissionId("claimSubmissionId_" + index); - result.setIdType(Claim.V1_ID_TYPE); - result.setVeteranIcn("icn_" + index); - - ContentionInfo contentionInfo = new ContentionInfo(); - contentionInfo.setDiagnosticCode("7101"); - - Map summary = - ImmutableMap.of("ka" + index, "va" + index, "kb" + index, "vb" + index); - - AssessmentInfo assessmentInfo = new AssessmentInfo(); - assessmentInfo.setEvidenceInfo(summary); - contentionInfo.setAssessments(Collections.singletonList(assessmentInfo)); - - DocumentInfo documentInfo = new DocumentInfo(); - documentInfo.setDocumentName("documentName_" + index); - documentInfo.setEvidenceInfo(summary); - - contentionInfo.setDocuments(Collections.singletonList(documentInfo)); - - result.setContentions(Collections.singletonList(contentionInfo)); - return result; - } - - // Generates a generic ClaimsInfo object. - private ClaimsInfo generateClaimsInfo(int size) { - ClaimsInfo result = new ClaimsInfo(); - List claimInfoResponses = new ArrayList<>(); - for (int i = 0; i < size; ++i) { - claimInfoResponses.add(generateClaimInfoResponse()); - } - result.setClaimInfoList(claimInfoResponses); - int total = counter.getAndIncrement() + size + 1; - result.setTotal(total); - return result; - } - - @Test - void testClaimInfoAllUnAuthorized() { - var responseEntity = - restTemplate.exchange("/v2/claim-info", HttpMethod.GET, null, String.class); - - assertEquals(HttpStatus.UNAUTHORIZED, responseEntity.getStatusCode()); - } - - private HttpEntity getAuthorizationHeader() { - HttpHeaders headers = new HttpHeaders(); - headers.add("X-API-Key", "test-key-01"); - return new HttpEntity<>(headers); - } - - @Test - void testClaimInfoAllWrongVerb() { - HttpEntity requestEntity = getAuthorizationHeader(); - - var responseEntity = - restTemplate.exchange("/v2/claim-info", HttpMethod.POST, requestEntity, String.class); - - assertEquals(HttpStatus.METHOD_NOT_ALLOWED, responseEntity.getStatusCode()); - } - - private ResponseEntity callRestWithAuthorization(String uri) { - HttpEntity requestEntity = getAuthorizationHeader(); - - return restTemplate.exchange(uri, HttpMethod.GET, requestEntity, String.class); - } - - @Test - void testClaimInfoAllInvalidQueryParam() { - ResponseEntity re0 = callRestWithAuthorization("/v2/claim-info?size=0"); - assertEquals(HttpStatus.BAD_REQUEST, re0.getStatusCode()); - - ResponseEntity re1 = callRestWithAuthorization("/v2/claim-info?page=x"); - assertEquals(HttpStatus.BAD_REQUEST, re1.getStatusCode()); - - ResponseEntity re2 = callRestWithAuthorization("/v2/claim-info?page=-1"); - assertEquals(HttpStatus.BAD_REQUEST, re2.getStatusCode()); - } - - // Verifies happy path where service returns an expected object. - @Test - void testClaimInfoAll() throws JsonProcessingException { - int size = 5; - - ClaimInfoQueryParams params = new ClaimInfoQueryParams(0, size, null); - ClaimsInfo serviceOutput = generateClaimsInfo(size); - - // Return an expected exception if argument does not match. - Mockito.when(service.findAllClaimInfo(ArgumentMatchers.any(ClaimInfoQueryParams.class))) - .thenThrow(new IllegalStateException("Unexpected input to service.")); - Mockito.when(service.findAllClaimInfo(ArgumentMatchers.eq(params))).thenReturn(serviceOutput); - - ResponseEntity responseEntity = callRestWithAuthorization("/v2/claim-info?size=5"); - - assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); - String body = responseEntity.getBody(); - assertNotNull(body); - ClaimInfoResponse[] actual = mapper.readValue(body, ClaimInfoResponse[].class); - assertNotNull(actual); - assertEquals(size, actual.length); - - List responses = serviceOutput.getClaimInfoList(); - for (int index = 0; index < size; ++index) { - assertEquals(responses.get(index), actual[index]); - } - } - - // Checks if a specific uri results in the expected argument to the service call. - private void testClaimInfoAllQueryParamDefaults(String uri, ClaimInfoQueryParams expectedParams) { - Mockito.reset(service); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(ClaimInfoQueryParams.class); - - callRestWithAuthorization(uri); - - Mockito.verify(service).findAllClaimInfo(captor.capture()); - ClaimInfoQueryParams actualParams = captor.getValue(); - - assertEquals(expectedParams.getPage(), actualParams.getPage()); - assertEquals(expectedParams.getSize(), actualParams.getSize()); - assertEquals(expectedParams.getIcn(), actualParams.getIcn()); - } - - // Verifies default query parameters results in the expected argument to the service call. - @Test - void testClaimInfoAllQueryParamDefaults() { - String uri0 = "/v2/claim-info"; - ClaimInfoQueryParams params0 = new ClaimInfoQueryParams(0, 10, null); - testClaimInfoAllQueryParamDefaults(uri0, params0); - - String uri1 = "/v2/claim-info?size=15"; - ClaimInfoQueryParams params1 = new ClaimInfoQueryParams(0, 15, null); - testClaimInfoAllQueryParamDefaults(uri1, params1); - - String uri2 = "/v2/claim-info?page=1"; - ClaimInfoQueryParams params2 = new ClaimInfoQueryParams(1, 10, null); - testClaimInfoAllQueryParamDefaults(uri2, params2); - - String uri3 = "/v2/claim-info?page=1&size=15"; - ClaimInfoQueryParams params3 = new ClaimInfoQueryParams(1, 15, null); - testClaimInfoAllQueryParamDefaults(uri3, params3); - - String uri4 = "/v2/claim-info?icn=12345"; - ClaimInfoQueryParams params4 = new ClaimInfoQueryParams(0, 10, "12345"); - testClaimInfoAllQueryParamDefaults(uri4, params4); - - String uri5 = "/v2/claim-info?page=2&size=16&icn=11145"; - ClaimInfoQueryParams params5 = new ClaimInfoQueryParams(2, 16, "11145"); - testClaimInfoAllQueryParamDefaults(uri5, params5); - } - - // Verifies happy path where service returns an expected object. - @Test - void testClaimInfo() throws JsonProcessingException { - ClaimInfoResponse claimInfo = generateClaimInfoResponse(); - - String claimSubmissionId = claimInfo.getClaimSubmissionId(); - - // Return an expected exception if argument does not match. - Mockito.when(service.findClaimInfo(ArgumentMatchers.anyString(), ArgumentMatchers.isNull())) - .thenThrow(new IllegalStateException("Unexpected input to service.")); - Mockito.when( - service.findClaimInfo( - ArgumentMatchers.eq(claimSubmissionId), ArgumentMatchers.anyString())) - .thenReturn(claimInfo); - - String path = "/v2/claim-info/" + claimSubmissionId + "?claimVersion=v1"; - ResponseEntity responseEntity = callRestWithAuthorization(path); - - assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); - String body = responseEntity.getBody(); - assertNotNull(body); - ClaimInfoResponse actual = mapper.readValue(body, ClaimInfoResponse.class); - assertNotNull(actual); - assertEquals(claimInfo, actual); - } - - @Test - void testClaimInfoNotValidId() { - Mockito.when(service.findClaimInfo(ArgumentMatchers.anyString(), ArgumentMatchers.anyString())) - .thenReturn(null); - - String path = "/v2/claim-info/not_an_id/v1"; - ResponseEntity responseEntity = callRestWithAuthorization(path); - - assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); - } - - @Test - void testClaimMetrics() throws JsonProcessingException { - ClaimMetricsResponse info = new ClaimMetricsResponse(5, 4, 3); - - Mockito.when(service.getClaimMetrics()).thenReturn(info); - - String path = "/v2/claim-metrics"; - ResponseEntity responseEntity = callRestWithAuthorization(path); - - assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); - String body = responseEntity.getBody(); - assertNotNull(body); - ClaimMetricsResponse actual = mapper.readValue(body, ClaimMetricsResponse.class); - assertNotNull(actual); - assertEquals(info, actual); - } - - // Generates a generic ClaimInfoResponse object. - private ExamOrderInfoResponse generateExamOrderInfoResponse() { - int index = counter.getAndIncrement(); - - ExamOrderInfoResponse result = new ExamOrderInfoResponse(); - - result.setCollectionId("collectionId_" + index); - result.setOrderedAt(LocalDateTime.now()); - result.setStatus("DRAFT"); - result.setCreatedAt(LocalDateTime.now()); - result.setUpdatedAt(LocalDateTime.now()); - result.setHasAssociatedClaimSubmission(false); - - return result; - } - - // Generates a generic ExamsOrdersInfo object. - private ExamOrdersInfo generateExamOrdersInfo(int size) { - ExamOrdersInfo result = new ExamOrdersInfo(); - List examOrderInfoResponses = new ArrayList<>(); - for (int i = 0; i < size; ++i) { - examOrderInfoResponses.add(generateExamOrderInfoResponse()); - } - result.setExamOrderInfoList(examOrderInfoResponses); - int total = counter.getAndIncrement() + size + 1; - result.setTotal(total); - return result; - } - - // Verifies happy path where service returns an expected object. - @Test - void testExamOrderInfo() throws JsonProcessingException { - int size = 5; - - ExamOrderInfoQueryParams params = new ExamOrderInfoQueryParams(0, size, Boolean.FALSE); - ExamOrdersInfo serviceOutput = generateExamOrdersInfo(size); - - // Return an expected exception if argument does not match. - Mockito.when(service.findExamOrderInfo(ArgumentMatchers.any(ExamOrderInfoQueryParams.class))) - .thenThrow(new IllegalStateException("Unexpected input to service.")); - Mockito.when(service.findExamOrderInfo(ArgumentMatchers.eq(params))).thenReturn(serviceOutput); - - ResponseEntity responseEntity = callRestWithAuthorization("/v2/exam-order-info?size=5"); - - assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); - String body = responseEntity.getBody(); - assertNotNull(body); - ExamOrderInfoResponse[] actual = mapper.readValue(body, ExamOrderInfoResponse[].class); - assertNotNull(actual); - assertEquals(size, actual.length); - - List responses = serviceOutput.getExamOrderInfoList(); - for (int index = 0; index < size; ++index) { - assertEquals(responses.get(index), actual[index]); - } - } - - // Checks if a specific uri results in the expected argument to the service call. - private void testExamInfoQueryParamDefaults(String uri, ExamOrderInfoQueryParams expectedParams) { - Mockito.reset(service); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(ExamOrderInfoQueryParams.class); - - callRestWithAuthorization(uri); - - Mockito.verify(service).findExamOrderInfo(captor.capture()); - ExamOrderInfoQueryParams actualParams = captor.getValue(); - - assertEquals(expectedParams.getPage(), actualParams.getPage()); - assertEquals(expectedParams.getSize(), actualParams.getSize()); - assertEquals(expectedParams.getNotOrdered(), actualParams.getNotOrdered()); - } - - // Verifies default query parameters results in the expected argument to the service call. - @Test - void testExamInfoAllQueryParamDefaults() { - String uri0 = "/v2/exam-order-info"; - ExamOrderInfoQueryParams params0 = new ExamOrderInfoQueryParams(0, 10, Boolean.FALSE); - testExamInfoQueryParamDefaults(uri0, params0); - - String uri1 = "/v2/exam-order-info?size=15"; - ExamOrderInfoQueryParams params1 = new ExamOrderInfoQueryParams(0, 15, Boolean.FALSE); - testExamInfoQueryParamDefaults(uri1, params1); - - String uri2 = "/v2/exam-order-info?page=1"; - ExamOrderInfoQueryParams params2 = new ExamOrderInfoQueryParams(1, 10, Boolean.FALSE); - testExamInfoQueryParamDefaults(uri2, params2); - - String uri3 = "/v2/exam-order-info?page=1&size=15"; - ExamOrderInfoQueryParams params3 = new ExamOrderInfoQueryParams(1, 15, Boolean.FALSE); - testExamInfoQueryParamDefaults(uri3, params3); - } - - @Test - void testExamOrderInfoAllInvalidQueryParam() { - ResponseEntity re0 = callRestWithAuthorization("/v2/exam-order-info?size=0"); - assertEquals(HttpStatus.BAD_REQUEST, re0.getStatusCode()); - - ResponseEntity re1 = callRestWithAuthorization("/v2/exam-order-info?page=x"); - assertEquals(HttpStatus.BAD_REQUEST, re1.getStatusCode()); - - ResponseEntity re2 = callRestWithAuthorization("/v2/exam-order-info?page=-1"); - assertEquals(HttpStatus.BAD_REQUEST, re2.getStatusCode()); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/ClaimMetricsControllerTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/ClaimMetricsControllerTest.java deleted file mode 100644 index a241e37507..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/ClaimMetricsControllerTest.java +++ /dev/null @@ -1,129 +0,0 @@ -package gov.va.vro.controller; - -import static org.apache.camel.builder.AdviceWith.adviceWith; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import gov.va.vro.model.rrd.claimmetrics.ExamOrderInfoQueryParams; -import gov.va.vro.model.rrd.claimmetrics.response.ExamOrderInfoResponse; -import gov.va.vro.persistence.model.ExamOrderEntity; -import gov.va.vro.persistence.repository.ExamOrderRepository; -import gov.va.vro.service.provider.camel.MasIntegrationRoutes; -import org.apache.camel.CamelContext; -import org.apache.camel.EndpointInject; -import org.apache.camel.component.mock.MockEndpoint; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.ActiveProfiles; - -import java.lang.reflect.Field; -import java.time.LocalDateTime; -import java.time.temporal.ChronoUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@ActiveProfiles("test") -public class ClaimMetricsControllerTest { - - @Autowired private ExamOrderRepository examOrderRepository; - - @EndpointInject("mock: exam-order-slack") - private MockEndpoint mockExamSlack; - - @Autowired private CamelContext camelContext; - - @Autowired TestRestTemplate restTemplate; - - public ObjectMapper createObjectMapper() { - return JsonMapper.builder().addModule(new JavaTimeModule()).build(); - } - - private final ObjectMapper mapper = createObjectMapper(); - - private HttpEntity getAuthorizationHeader() { - HttpHeaders headers = new HttpHeaders(); - headers.add("X-API-Key", "test-key-01"); - return new HttpEntity<>(headers); - } - - private ResponseEntity callPostRestWithAuthorization(String uri) { - HttpEntity requestEntity = getAuthorizationHeader(); - - return restTemplate.exchange(uri, HttpMethod.POST, requestEntity, String.class); - } - - @Test - void testExamOrderSlackResponse() throws Exception { - examOrderRepository.deleteAll(); - - var slackCalled = new AtomicBoolean(false); - adviceWith( - camelContext, - "exam-order-slack", - route -> - route - .interceptSendToEndpoint(MasIntegrationRoutes.ENDPOINT_EXAM_ORDER_SLACK) - .skipSendToOriginalEndpoint() - .to(mockExamSlack)) - .end(); - // The mock endpoint returns a valid response - mockExamSlack.whenAnyExchangeReceived( - exchange -> { - slackCalled.set(true); - }); - - ExamOrderInfoQueryParams params = new ExamOrderInfoQueryParams(0, 10, Boolean.TRUE); - - String collectionIDFound = "1234"; - LocalDateTime timeFound = LocalDateTime.now().minus(24, ChronoUnit.HOURS); - - Field createdAtField = ExamOrderEntity.class.getSuperclass().getDeclaredField("createdAt"); - createdAtField.setAccessible(true); - - ExamOrderEntity entity1 = new ExamOrderEntity(); - entity1.setOrderedAt(null); - entity1.setCollectionId(collectionIDFound); - - ExamOrderEntity entity2 = new ExamOrderEntity(); - entity2.setOrderedAt(null); - entity2.setCollectionId("1235"); - - examOrderRepository.save(entity1); - examOrderRepository.save(entity2); - - // Override the created at date for one entity. - createdAtField.set(entity1, timeFound); - examOrderRepository.save(entity1); - - ExamOrderInfoResponse response = new ExamOrderInfoResponse(); - response.setOrderedAt(null); - response.setCreatedAt(timeFound); - response.setCollectionId(collectionIDFound); - // Call exam-order-slack - ResponseEntity responseEntity = - callPostRestWithAuthorization("/v2/exam-order-slack?page=0&size=10¬Ordered=true"); - // Expect a 200 and a list of size one - assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); - String body = responseEntity.getBody(); - assertNotNull(body); - ExamOrderInfoResponse[] actual = mapper.readValue(body, ExamOrderInfoResponse[].class); - assertEquals(1, actual.length); - ExamOrderInfoResponse response1 = actual[0]; - assertNotNull(response1); - assertNull(response1.getOrderedAt()); - assertEquals(response1.getCollectionId(), collectionIDFound); - assertTrue(slackCalled.get()); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/MasControllerTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/MasControllerTest.java deleted file mode 100644 index 96ecd88034..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/MasControllerTest.java +++ /dev/null @@ -1,194 +0,0 @@ -package gov.va.vro.controller; - -import static org.apache.camel.builder.AdviceWith.adviceWith; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.BipServiceTestConfiguration; -import gov.va.vro.MasTestData; -import gov.va.vro.api.rrd.responses.MasResponse; -import gov.va.vro.model.rrd.event.AuditEvent; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.MasExamOrderStatusPayload; -import gov.va.vro.model.rrd.mas.request.MasAutomatedClaimRequest; -import gov.va.vro.persistence.model.ClaimSubmissionEntity; -import gov.va.vro.persistence.repository.AuditEventRepository; -import gov.va.vro.persistence.repository.ClaimRepository; -import gov.va.vro.persistence.repository.ClaimSubmissionRepository; -import gov.va.vro.service.provider.camel.MasIntegrationRoutes; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import lombok.SneakyThrows; -import org.apache.camel.CamelContext; -import org.apache.camel.EndpointInject; -import org.apache.camel.component.mock.MockEndpoint; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Import; -import org.springframework.core.io.ClassPathResource; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ActiveProfiles; - -import java.util.concurrent.atomic.AtomicBoolean; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@ActiveProfiles("test") -@Import(BipServiceTestConfiguration.class) -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) -public class MasControllerTest extends BaseControllerTest { - - @EndpointInject("mock:vro-notify") - private MockEndpoint mockMasOfframpEndpoint; - - @EndpointInject("mock:mas-complete") - private MockEndpoint mockMasCompleteEndpoint; - - @Autowired private CamelContext camelContext; - - @Autowired private ClaimRepository claimRepository; - - @Autowired private ClaimSubmissionRepository claimSubmissionRepository; - - @Autowired private AuditEventRepository auditEventRepository; - - public static final String DEFAULT_ID_TYPE = "va.gov-Form526Submission"; - private ObjectMapper objectMapper = new ObjectMapper(); - - @Test - @SneakyThrows - void testJsonConversion() { - ObjectMapper objectMapper = new ObjectMapper(); - var request = - objectMapper.readValue( - new ClassPathResource("mas-request.json").getFile(), MasAutomatedClaimRequest.class); - assertEquals("Rick", request.getFirstName()); - assertEquals("Smith", request.getLastName()); - assertEquals(123, request.getCollectionId()); - assertEquals("2002-12-12", request.getDateOfBirth()); - assertEquals("X", request.getVeteranIdentifiers().getEdipn()); - assertEquals("X", request.getVeteranIdentifiers().getVeteranFileId()); - assertEquals("X", request.getVeteranIdentifiers().getParticipantId()); - assertEquals("X", request.getVeteranIdentifiers().getIcn()); - assertEquals("X", request.getVeteranIdentifiers().getSsn()); - assertEquals("1233", request.getClaimDetail().getConditions().getDiagnosticCode()); - assertEquals("VA.GOV", request.getClaimDetail().getClaimSubmissionSource()); - } - - @Test - void automatedClaimInvalidRequest() { - MasAutomatedClaimPayload request = - MasAutomatedClaimPayload.builder().dateOfBirth("2002-12-12").collectionId(123).build(); - var responseEntity = post("/v2/automatedClaim", request, MasResponse.class); - assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); - } - - @Test - void automatedClaimOutOfScope() throws Exception { - var offrampCalled = new AtomicBoolean(false); - adviceWith( - camelContext, - "vro-notify", - route -> - route - .interceptSendToEndpoint(MasIntegrationRoutes.ENDPOINT_NOTIFY_AUDIT) - .skipSendToOriginalEndpoint() - .to(mockMasOfframpEndpoint)) - .end(); - // The mock endpoint returns a valid response - mockMasOfframpEndpoint.whenAnyExchangeReceived( - exchange -> { - AuditEvent auditEvent = exchange.getMessage().getBody(AuditEvent.class); - assertEquals( - "Claim with collection id: 123, diagnostic code: 1233, and" - + " disability action type: INCREASE is not in scope.", - String.join(", ", auditEvent.getMessages())); - offrampCalled.set(true); - }); - var completeCalled = new AtomicBoolean(false); - adviceWith( - camelContext, - "mas-complete-claim", - route -> - route - .interceptSendToEndpoint(MasIntegrationRoutes.ENDPOINT_MAS_COMPLETE) - .skipSendToOriginalEndpoint() - .to(mockMasCompleteEndpoint)) - .end(); - mockMasCompleteEndpoint.whenAnyExchangeReceived( - exchange -> { - MasProcessingObject mpo = exchange.getMessage().getBody(MasProcessingObject.class); - assertNotNull(mpo.getClaimPayload()); - completeCalled.set(true); - }); - - var request = MasTestData.getMasAutomatedClaimRequest(); - var responseEntity = post("/v2/automatedClaim", request, MasResponse.class); - assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, responseEntity.getStatusCode()); - assertFalse(offrampCalled.get()); - assertFalse(completeCalled.get()); - verifyClaimPersisted(request); - } - - @Test - void automatedClaimInScope() throws Exception { - - adviceWith( - camelContext, - "mas-claim-notification", - route -> - route - .interceptSendToEndpoint(MasIntegrationRoutes.ENDPOINT_AUTOMATED_CLAIM) - .skipSendToOriginalEndpoint() - .to("mock:mas-notification")) - .end(); - // The mock endpoint returns a valid response - mockMasOfframpEndpoint.whenAnyExchangeReceived(exchange -> {}); - - var request = MasTestData.getMasAutomatedClaimRequest(567, "7101", "999"); - var responseEntity = post("/v2/automatedClaim", request, MasResponse.class); - assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, responseEntity.getStatusCode()); - mockMasOfframpEndpoint.expectedMessageCount(1); - - verifyClaimPersisted(request); - } - - @Test - void orderExamStatus() { - var payload = - MasExamOrderStatusPayload.builder().collectionId(123).collectionStatus("UNKNOWN").build(); - ResponseEntity response = - post("/v2/examOrderingStatus", payload, MasResponse.class); - assertEquals( - "Received Exam Order Status for collection Id 123.", response.getBody().getMessage()); - } - - @Test - void orderExamStatusMissingCollectionId() { - var payload = MasExamOrderStatusPayload.builder().collectionStatus("UNKNOWN").build(); - ResponseEntity response = - post("/v2/examOrderingStatus", payload, MasResponse.class); - assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); - } - - private void verifyClaimPersisted(MasAutomatedClaimRequest request) { - var claim = claimRepository.findByVbmsId(request.getClaimDetail().getBenefitClaimId()).get(); - var claimSubmissionList = - claimSubmissionRepository.findByReferenceIdAndIdType( - String.valueOf(request.getCollectionId()), DEFAULT_ID_TYPE); - for (ClaimSubmissionEntity submission : claimSubmissionList) { - assertEquals(request.getCollectionId().toString(), submission.getReferenceId()); - } - assertEquals(request.getVeteranIdentifiers().getIcn(), claim.getVeteran().getIcn()); - var contentions = claim.getContentions(); - assertEquals(1, contentions.size()); - var contention = contentions.get(0); - assertEquals( - request.getClaimDetail().getConditions().getDiagnosticCode(), - contention.getDiagnosticCode()); - claimRepository.delete(claim); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/VroControllerTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/VroControllerTest.java deleted file mode 100644 index 520ce29ebe..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/controller/VroControllerTest.java +++ /dev/null @@ -1,327 +0,0 @@ -package gov.va.vro.controller; - -import static org.apache.camel.builder.AdviceWith.adviceWith; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.api.rrd.requests.GeneratePdfRequest; -import gov.va.vro.api.rrd.requests.HealthDataAssessmentRequest; -import gov.va.vro.api.rrd.responses.FullHealthDataAssessmentResponse; -import gov.va.vro.api.rrd.responses.GeneratePdfResponse; -import gov.va.vro.camel.FunctionProcessor; -import gov.va.vro.config.AppTestConfig; -import gov.va.vro.config.AppTestUtil; -import gov.va.vro.controller.rrd.exception.ClaimProcessingError; -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.VeteranInfo; -import gov.va.vro.model.rrd.mas.response.FetchPdfResponse; -import gov.va.vro.service.provider.camel.PrimaryRoutes; -import gov.va.vro.service.spi.model.Claim; -import org.apache.camel.CamelContext; -import org.apache.camel.EndpointInject; -import org.apache.camel.builder.Builder; -import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.test.spring.junit5.CamelSpringBootTest; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Import; -import org.springframework.core.io.Resource; -import org.springframework.http.HttpStatus; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ActiveProfiles; - -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@ActiveProfiles("test") -@Import(AppTestConfig.class) -@CamelSpringBootTest -class VroControllerTest extends BaseControllerTest { - - private static final int TIME_OUT = 120000; - - @Autowired private AppTestUtil util; - - @Autowired protected CamelContext camelContext; - - @EndpointInject("mock:rabbit-claim-submit") - private MockEndpoint mockRabbitClaimSubmitEndpoint; - - @EndpointInject("mock:rabbit-health-assess") - private MockEndpoint mockHealthAssessEndpoint; - - @EndpointInject("mock:generate-pdf") - private MockEndpoint mockGeneratePdfEndpoint; - - @EndpointInject("mock:fetch-pdf") - private MockEndpoint mockFetchPdfEndpoint; - - @Value("classpath:test-data/pdf-generator-input-01.json") - private Resource pdfGeneratorInput01; - - @Test - @DirtiesContext - void postFullHealthAssessment() throws Exception { - // Mock the first rabbit mq endpoint - adviceWith( - camelContext, - "claim-submit-full", - route -> - route - .interceptSendToEndpoint("rabbitmq:claim-submit-exchange*") - .skipSendToOriginalEndpoint() - .to("mock:rabbit-claim-submit")); - - // Mock the second rabbit mq endpoint - adviceWith( - camelContext, - "claim-submit-full", - route -> - route - .interceptSendToEndpoint("rabbitmq:health-assess-exchange*") - .skipSendToOriginalEndpoint() - .to("mock:rabbit-health-assess")); - - mockHealthAssessEndpoint.whenAnyExchangeReceived( - FunctionProcessor.fromFunction( - claim -> util.claimToResponse(claim, true, null))); - - HealthDataAssessmentRequest request = new HealthDataAssessmentRequest(); - request.setClaimSubmissionId("1234"); - request.setVeteranIcn("icn"); - request.setDiagnosticCode("7101"); - - var responseEntity1 = - post("/v1/full-health-data-assessment", request, FullHealthDataAssessmentResponse.class); - assertEquals(HttpStatus.CREATED, responseEntity1.getStatusCode()); - FullHealthDataAssessmentResponse response1 = responseEntity1.getBody(); - assertNotNull(response1); - assertEquals(request.getDiagnosticCode(), response1.getDiagnosticCode()); - assertEquals(request.getVeteranIcn(), response1.getVeteranIcn()); - - // Now submit an existing claim: - var responseEntity2 = - post("/v1/full-health-data-assessment", request, FullHealthDataAssessmentResponse.class); - assertEquals(HttpStatus.CREATED, responseEntity2.getStatusCode()); - FullHealthDataAssessmentResponse response2 = responseEntity2.getBody(); - assertNotNull(response2); - assertEquals(request.getDiagnosticCode(), response2.getDiagnosticCode()); - assertEquals(request.getVeteranIcn(), response2.getVeteranIcn()); - - var claimSubmission = - claimSubmissionRepository.findFirstByReferenceIdAndIdTypeOrderByCreatedAtDesc( - request.getClaimSubmissionId(), Claim.V1_ID_TYPE); - assertTrue(claimSubmission.isPresent()); - var claim = claimSubmission.get().getClaim(); - assertNull(claim.getVbmsId()); - assertEquals(2, claim.getClaimSubmissions().size()); - } - - // @Test - // @DirtiesContext - // void fullHealthAssessmentMissingEvidence() throws Exception { - // // Mock the first rabbit endpoint - // adviceWith( - // camelContext, - // "claim-submit-full", - // route -> - // route - // .interceptSendToEndpoint( - // "rabbitmq:claim-submit-exchange" - // + "?queue=claim-submit" - // + "&routingKey=code.hypertension&requestTimeout=" - // + TIME_OUT) - // .skipSendToOriginalEndpoint() - // .to("mock:rabbit-claim-submit")); - // // Mock the second rabbit endpoint - // adviceWith( - // camelContext, - // "claim-submit-full", - // route -> - // route - // .interceptSendToEndpoint( - // "rabbitmq:health-assess-exchange" - // + "?routingKey=health-assess.hypertension&requestTimeout=" - // + TIME_OUT) - // .skipSendToOriginalEndpoint() - // .to("mock:rabbit-health-assess")); - // - // mockHealthAssessEndpoint.whenAnyExchangeReceived( - // FunctionProcessor.fromFunction( - // claim -> - // util.claimToResponse(claim, false, "Internal error while processing claim - // data."))); - // HealthDataAssessmentRequest request = new HealthDataAssessmentRequest(); - // request.setClaimSubmissionId("1234"); - // request.setVeteranIcn("icn"); - // request.setDiagnosticCode("7101"); - // - // var responseEntity = post("/v2/health-data-assessment", request, - // ClaimProcessingError.class); - // assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); - // var claimProcessingError = responseEntity.getBody(); - // assertNotNull(claimProcessingError); - // assertEquals("Internal error while processing claim data.", - // claimProcessingError.getMessage()); - // assertEquals("1234", claimProcessingError.getClaimSubmissionId()); - // } - // - // @Test - // void fullHealthAssessmentInvalidInput() { - // HealthDataAssessmentRequest request = new HealthDataAssessmentRequest(); - // request.setVeteranIcn("icn"); - // - // var responseEntity = post("/v2/health-data-assessment", request, - // ClaimProcessingError.class); - // assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); - // var claimProcessingError = responseEntity.getBody(); - // assertNotNull(claimProcessingError); - // String[] actual = claimProcessingError.getMessage().split("\n"); - // Arrays.sort(actual); - // String[] expected = { - // "claimSubmissionId: Claim submission id cannot be empty", - // "diagnosticCode: Diagnostic code cannot be empty" - // }; - // assertArrayEquals(expected, actual); - // } - - // @Test - // void fullHealthAssessmentMalformedJson() { - // Map headers = new HashMap<>(); - // headers.put("accept", "application/json"); - // headers.put("content-type", "application/json"); - // var responseEntity = - // post( - // "/v2/health-data-assessment", - // "{ \"one\":\"one\", \"two\":\"two\",}", - // headers, - // ClaimProcessingError.class); - // assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); - // } - - @Test - void serverResponseUnsupportedHttpMethod() { - Map headers = new HashMap<>(); - headers.put("accept", "application/json"); - headers.put("content-type", "application/json"); - String url = "/v2/claim-metrics"; - String sampleRequestBody = "{ \"one\":\"one\", \"two\":\"two\",}"; - var getResponseEntity = get(url, headers, ClaimProcessingError.class); - var postResponseEntity = post(url, sampleRequestBody, headers, ClaimProcessingError.class); - var putResponseEntity = put(url, sampleRequestBody, headers, ClaimProcessingError.class); - assertEquals(HttpStatus.OK, getResponseEntity.getStatusCode()); - assertEquals(HttpStatus.METHOD_NOT_ALLOWED, postResponseEntity.getStatusCode()); - assertEquals(HttpStatus.METHOD_NOT_ALLOWED, putResponseEntity.getStatusCode()); - } - - @Test - @DirtiesContext - void generatePdf() throws Exception { - var mapper = new ObjectMapper(); - var mockResponseObj = new GeneratePdfResponse("1234", "7701", "COMPLETE"); - String mockResponse = mapper.writeValueAsString(mockResponseObj); - adviceWith( - camelContext, - "generate-pdf", - route -> - route - .interceptSendToEndpoint(PrimaryRoutes.ENDPOINT_GENERATE_PDF) - .skipSendToOriginalEndpoint() - .setBody(Builder.simple(mockResponse)) - .to("mock:generate-pdf")); - mockGeneratePdfEndpoint.expectedMessageCount(1); - - InputStream stream = pdfGeneratorInput01.getInputStream(); - String inputAsString = new String(stream.readAllBytes(), StandardCharsets.UTF_8); - GeneratePdfRequest input = mapper.readValue(inputAsString, GeneratePdfRequest.class); - var response = post("/v1/evidence-pdf", input, GeneratePdfResponse.class); - assertEquals(HttpStatus.OK, response.getStatusCode()); - } - - @Test - void generatePdfInvalidInput() { - var generatePdf = new GeneratePdfRequest(); - generatePdf.setClaimSubmissionId("1234"); - generatePdf.setVeteranInfo(new VeteranInfo()); - generatePdf.setEvidence(new AbdEvidence()); - var response = post("/v1/evidence-pdf", generatePdf, ClaimProcessingError.class); - assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); - assertEquals(response.getBody().getMessage(), "diagnosticCode: must not be blank"); - } - - @Test - @DirtiesContext - void fetchPdf() throws Exception { - adviceWith( - camelContext, - "fetch-pdf", - route -> - route - .interceptSendToEndpoint(PrimaryRoutes.ENDPOINT_FETCH_PDF) - .skipSendToOriginalEndpoint() - .to("mock:fetch-pdf")); - mockFetchPdfEndpoint.expectedMessageCount(1); - - var fetchPdfResponse = new FetchPdfResponse("1234", "ERROR", "diagnosis", null, ""); - - mockFetchPdfEndpoint.whenAnyExchangeReceived( - FunctionProcessor.fromFunction( - (Function) o -> util.toJsonString(fetchPdfResponse))); - - var response = get("/v1/evidence-pdf/1234", null, String.class); - assertNotNull(response); - } - - @Test - @DirtiesContext - void fetchPdfAcceptJson() throws Exception { - Map headers = new HashMap<>(); - headers.put("accept", "application/json"); - fetchPdfCommon(headers); - } - - @Test - @DirtiesContext - void fetchPdfAcceptPdf() throws Exception { - Map headers = new HashMap<>(); - headers.put("accept", "application/pdf"); - fetchPdfCommon(headers); - } - - void fetchPdfCommon(Map headers) throws Exception { - adviceWith( - camelContext, - "fetch-pdf", - route -> - route - .interceptSendToEndpoint(PrimaryRoutes.ENDPOINT_FETCH_PDF) - .skipSendToOriginalEndpoint() - .to("mock:fetch-pdf")); - mockFetchPdfEndpoint.expectedMessageCount(1); - - var fetchPdfResponse = new FetchPdfResponse(); - fetchPdfResponse.setPdfData(Base64.getEncoder().encodeToString("Example PDF".getBytes())); - fetchPdfResponse.setClaimSubmissionId("1239"); - fetchPdfResponse.setStatus("SUCCESS"); - - mockFetchPdfEndpoint.whenAnyExchangeReceived( - FunctionProcessor.fromFunction( - (Function) o -> util.toJsonString(fetchPdfResponse))); - - var response = get("/v1/evidence-pdf/1239", null, headers, byte[].class); - assertNotNull(response); - assertEquals(HttpStatus.OK, response.getStatusCode()); - String value = new String(response.getBody()); - assertEquals("Example PDF", value); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/routes/MasIntegrationNegativeTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/routes/MasIntegrationNegativeTest.java deleted file mode 100644 index 57ce2464a2..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/routes/MasIntegrationNegativeTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package gov.va.vro.routes; - -import static org.junit.jupiter.api.Assertions.fail; - -import gov.va.vro.BaseIntegrationTest; -import gov.va.vro.MasTestData; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import gov.va.vro.model.rrd.mas.MasDocument; -import gov.va.vro.service.provider.CamelEntrance; -import gov.va.vro.service.provider.mas.service.IMasApiService; -import gov.va.vro.service.provider.mas.service.MasCollectionService; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.CamelExecutionException; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; - -import java.util.Collections; - -@Slf4j -public class MasIntegrationNegativeTest extends BaseIntegrationTest { - - @Autowired CamelEntrance camelEntrance; - - @MockBean IMasApiService masApiService; - - @Autowired @InjectMocks MasCollectionService masCollectionService; - - @Test - void processClaimInvalidInput() { - var payload = MasAutomatedClaimPayload.builder().collectionId(123).build(); - try { - camelEntrance.processClaim(payload); - fail(); - } catch (CamelExecutionException cee) { - log.info("error in masIntegrationNegativeTest."); - } - } - - @Test - void processClaimLighthouseConnectFailed() { - int collectionId = 123; - var collectionAnnotation = new MasCollectionAnnotation(); - MasDocument document = MasTestData.createHypertensionDocument(); - collectionAnnotation.setCollectionsId(123); - collectionAnnotation.setDocuments(Collections.singletonList(document)); - Mockito.when(masApiService.getCollectionAnnotations(collectionId)) - .thenReturn(Collections.singletonList(collectionAnnotation)); - var payload = MasTestData.getMasAutomatedClaimPayload(); - payload.getClaimDetail().getConditions().setDiagnosticCode("1233"); - try { - camelEntrance.processClaim(payload); - fail(); - } catch (CamelExecutionException me) { - log.info("error in masIntegrationNegativeTest."); - } - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/routes/MasIntegrationRoutesTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/routes/MasIntegrationRoutesTest.java deleted file mode 100644 index 4d86f56234..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/routes/MasIntegrationRoutesTest.java +++ /dev/null @@ -1,193 +0,0 @@ -package gov.va.vro.routes; - -import static gov.va.vro.service.provider.camel.PrimaryRoutes.INCOMING_CLAIM_WIRETAP; -import static org.apache.camel.builder.AdviceWith.adviceWith; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.BaseIntegrationTest; -import gov.va.vro.MasTestData; -import gov.va.vro.camel.RabbitMqCamelUtils; -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.model.rrd.HealthDataAssessment; -import gov.va.vro.model.rrd.event.EventReason; -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import gov.va.vro.model.rrd.mas.MasDocument; -import gov.va.vro.model.rrd.mas.request.MasOrderExamRequest; -import gov.va.vro.persistence.repository.AuditEventRepository; -import gov.va.vro.service.provider.CamelEntrance; -import gov.va.vro.service.provider.camel.BgsApiClientRoutes; -import gov.va.vro.service.provider.camel.MasIntegrationRoutes; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import gov.va.vro.service.provider.mas.service.IMasApiService; -import gov.va.vro.service.provider.mas.service.MasCollectionService; -import org.apache.camel.CamelContext; -import org.apache.camel.EndpointInject; -import org.apache.camel.component.mock.MockEndpoint; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; - -import java.util.Collections; - -public class MasIntegrationRoutesTest extends BaseIntegrationTest { - - private static final long DEFAULT_REQUEST_TIMEOUT = 120000; - - @Autowired CamelEntrance camelEntrance; - - @MockBean IMasApiService masApiService; - - @Autowired @InjectMocks MasCollectionService masCollectionService; - - @Autowired CamelContext camelContext; - - @Autowired AuditEventRepository auditEventRepository; - - @EndpointInject("mock:sufficiency-assess") - private MockEndpoint mockSufficiencyAssess; - - @EndpointInject("mock:claim-submit-full") - private MockEndpoint mockClaimSubmit; - - @EndpointInject("mock:empty-endpoint") - private MockEndpoint mockEmptyEndpoint; - - @Test - void processClaimSufficientEvidence() throws Exception { - var mpo = processClaim(true); - Thread.sleep(200); - var audits = auditEventRepository.findByEventIdOrderByEventTimeAsc(mpo.getEventId()); - assertTrue( - audits.stream() - .filter(audit -> audit.getMessage().startsWith("Sufficient evidence")) - .findFirst() - .isPresent()); - } - - @Test - void processClaimInsufficientEvidence() throws Exception { - var mpo = processClaim(false); - Thread.sleep(200); - var audits = auditEventRepository.findByEventIdOrderByEventTimeAsc(mpo.getEventId()); - assertTrue( - audits.stream() - .filter(audit -> audit.getMessage().startsWith("There is insufficient evidence")) - .findFirst() - .isPresent()); - } - - @Test - void processClaimInsufficientEvidenceAccessError() throws Exception { - var mpo = processClaim(null); - Thread.sleep(200); - String expectedMessageStart = - String.format("reason code: %s", EventReason.SUFFICIENCY_UNDETERMINED.getCode()); - var audits = auditEventRepository.findByEventIdOrderByEventTimeAsc(mpo.getEventId()); - assertTrue( - audits.stream() - .filter(audit -> audit.getMessage().startsWith(expectedMessageStart)) - .findFirst() - .isPresent()); - } - - private MasProcessingObject processClaim(Boolean sufficientEvidence) throws Exception { - - // Mock a return value when claim-submit-full (lighthouse) is invoked - replaceEndpoint( - "claim-submit-full", - "rabbitmq://claim-submit-exchange?queue=claim-submit&" - + "requestTimeout=" - + DEFAULT_REQUEST_TIMEOUT - + "&routingKey=code.hypertension", - "mock:claim-submit-full"); - - mockClaimSubmit.whenAnyExchangeReceived( - exchange -> { - var assessment = new HealthDataAssessment(); - exchange.getMessage().setBody(new ObjectMapper().writeValueAsBytes(assessment)); - }); - - // Mock a return value when health assess is invoked - - replaceEndpoint( - "mas-processing", - "rabbitmq:health-assess-exchange?routingKey=health-sufficiency-assess.hypertension&" - + "requestTimeout=" - + DEFAULT_REQUEST_TIMEOUT, - "mock:sufficiency-assess"); - - mockSufficiencyAssess.whenAnyExchangeReceived( - exchange -> { - var evidence = new AbdEvidenceWithSummary(); - evidence.setEvidence(new AbdEvidence()); - evidence.setSufficientForFastTracking(sufficientEvidence); - exchange.getMessage().setBody(new ObjectMapper().writeValueAsBytes(evidence)); - }); - - // Mock NOOP when generate PDF endpoints are called - - replaceEndpoint( - "generate-pdf", - RabbitMqCamelUtils.getTapProducerDirectEndpoint(INCOMING_CLAIM_WIRETAP), - "mock:empty-endpoint"); - - replaceEndpoint( - "generate-pdf", - "rabbitmq://pdf-generator?queue=generate-pdf&routingKey=generate-pdf", - "mock:empty-endpoint"); - - replaceEndpoint( - "mas-processing", MasIntegrationRoutes.ENDPOINT_UPLOAD_PDF, "mock:empty-endpoint"); - - replaceEndpoint("mas-rfd", MasIntegrationRoutes.ENDPOINT_UPLOAD_PDF, "mock:empty-endpoint"); - - replaceEndpoint( - "mas-order-exam", MasIntegrationRoutes.ENDPOINT_UPLOAD_PDF, "mock:empty-endpoint"); - - // This route is tested in its own unit test and isn't required for the MAS workflow - replaceEndpoint("add-bgs-notes-route", BgsApiClientRoutes.ADD_BGS_NOTES, "mock:empty-endpoint"); - - mockEmptyEndpoint.whenAnyExchangeReceived(exchange -> {}); - - // set up a Mas Request and invoke processClaim - int collectionId = 123; - var collectionAnnotation = new MasCollectionAnnotation(); - MasDocument document = MasTestData.createHypertensionDocument(); - collectionAnnotation.setCollectionsId(collectionId); - collectionAnnotation.setDocuments(Collections.singletonList(document)); - Mockito.when(masApiService.getCollectionAnnotations(collectionId)) - .thenReturn(Collections.singletonList(collectionAnnotation)); - var payload = MasTestData.getMasAutomatedClaimPayload(); - var response = camelEntrance.processClaim(payload); - - // verify if order exam was called based on the sufficient evidence flag - if (sufficientEvidence == null) { - Mockito.verify(masApiService, Mockito.never()).orderExam(Mockito.any()); - } else if (sufficientEvidence != null && sufficientEvidence == true) { - Mockito.verify(masApiService, Mockito.never()).orderExam(Mockito.any()); - } else if (sufficientEvidence != null && sufficientEvidence == false) { - var argumentCaptor = ArgumentCaptor.forClass(MasOrderExamRequest.class); - Mockito.verify(masApiService, Mockito.times(1)).orderExam(argumentCaptor.capture()); - MasOrderExamRequest orderExamRequest = argumentCaptor.getValue(); - assertEquals(collectionId, orderExamRequest.getCollectionsId()); - } - return response; - } - - private void replaceEndpoint(String routeId, String fromUri, String toUri) throws Exception { - adviceWith( - camelContext, - routeId, - // TODO: Consider using `weaveById().replace()` for rabbitmq endpoints to avoid "Failed to - // create connection." - // https://tomd.xyz/mock-endpoints-are-real: "Original endpoints are still initialised, even - // if they have been mocked." - route -> route.interceptSendToEndpoint(fromUri).skipSendToOriginalEndpoint().to(toUri)); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/BipClaimServiceTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/BipClaimServiceTest.java deleted file mode 100644 index f839fc0701..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/BipClaimServiceTest.java +++ /dev/null @@ -1,391 +0,0 @@ -package gov.va.vro.service; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyString; - -import gov.va.vro.MasTestData; -import gov.va.vro.model.rrd.bip.BipClaim; -import gov.va.vro.model.rrd.bip.BipUpdateClaimResp; -import gov.va.vro.model.rrd.bip.ClaimContention; -import gov.va.vro.model.rrd.bip.ClaimStatus; -import gov.va.vro.model.rrd.bip.UpdateContention; -import gov.va.vro.model.rrd.bip.UpdateContentionReq; -import gov.va.vro.model.rrd.mas.ClaimDetail; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.response.FetchPdfResponse; -import gov.va.vro.service.provider.ClaimProps; -import gov.va.vro.service.provider.bip.BipException; -import gov.va.vro.service.provider.bip.service.BipClaimService; -import gov.va.vro.service.provider.bip.service.BipUpdateClaimResult; -import gov.va.vro.service.provider.bip.service.IBipApiService; -import gov.va.vro.service.provider.bip.service.IBipCeApiService; -import gov.va.vro.service.provider.mas.MasCamelStage; -import gov.va.vro.service.provider.mas.MasCompletionStatus; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import gov.va.vro.service.spi.db.SaveToDbService; -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.http.HttpStatus; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Base64; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -class BipClaimServiceTest { - - private static final Integer collectionId = 123; - private static final String CLAIM_ID1 = "345"; - private static final String CLAIM_ID2 = "39208503"; - - private static final long CONTENTION_ID = 1000L; - private static final long CONTENTION_ID2 = 1001L; - private static final List SPECIAL_ISSUES_1 = Arrays.asList("RRD", "RRD1"); - private static final List SPECIAL_ISSUES_2 = new ArrayList<>(); - private static final ClaimStatus LIFE_CYCLE_STATUS_1 = ClaimStatus.OPEN; - private static final ClaimStatus LIFE_CYCLE_STATUS_2 = ClaimStatus.RFD; - private static final boolean AUTOMATION_IND_1 = false; - private static final boolean AUTOMATION_IND_2 = false; - - private ClaimProps claimProps; - - private final Map bipClaims = new ConcurrentHashMap<>(); - private final Map> bipContentions = new ConcurrentHashMap<>(); - - class BipApiTestService implements IBipApiService { - - @Override - public BipClaim getClaimDetails(long claimId) throws BipException { - return bipClaims.get(claimId); - } - - @Override - public BipUpdateClaimResp setClaimToRfdStatus(long claimId) throws BipException { - return updateClaimStatus(claimId, ClaimStatus.RFD); - } - - @Override - public BipUpdateClaimResp updateClaimStatus(long claimId, ClaimStatus status) - throws BipException { - BipClaim claim = getBipClaim(claimId); - try { - claim.setClaimLifecycleStatus(status.getDescription()); - return new BipUpdateClaimResp(HttpStatus.OK, "successful"); - } catch (Exception e) { - throw new BipException("failed to update claim status"); - } - } - - @Override - public List getClaimContentions(long claimId) throws BipException { - List contentions = bipContentions.get(claimId); - if (contentions == null) { - return new ArrayList<>(); - } - return contentions; - } - - @NotNull - private BipClaim getBipClaim(long claimId) { - BipClaim claim = bipClaims.get(claimId); - if (claim == null) { - throw new BipException("claim not found."); - } - return claim; - } - - @Override - public BipUpdateClaimResp updateClaimContention(long claimId, UpdateContentionReq contention) - throws BipException { - List contentions = bipContentions.get(claimId); - if (contentions == null) { - throw new BipException("Contention to update is not found."); - } - Map updtContentions = - contention.getUpdateContentions().stream() - .collect(Collectors.toMap(UpdateContention::getContentionId, c -> c)); - contentions.forEach( - c -> { - UpdateContention updt = updtContentions.get(c.getContentionId()); - if (updt != null) { - c.setLifecycleStatus(updt.getLifecycleStatus()); - c.setAutomationIndicator(updt.isAutomationIndicator()); - c.setSpecialIssueCodes(updt.getSpecialIssueCodes()); - } - }); - return new BipUpdateClaimResp(HttpStatus.OK, "updated"); - } - - @Override - public boolean verifySpecialIssueTypes() { - return true; - } - } - - private void initializeBipClaims() { - BipClaim claim = new BipClaim(); - claim.setClaimId(CLAIM_ID1); - claim.setClaimLifecycleStatus(LIFE_CYCLE_STATUS_1.getDescription()); - bipClaims.put(Long.parseLong(CLAIM_ID1), claim); - - claim = new BipClaim(); - claim.setClaimId(CLAIM_ID2); - claim.setClaimLifecycleStatus(LIFE_CYCLE_STATUS_2.getDescription()); - bipClaims.put(Long.parseLong(CLAIM_ID2), claim); - - ClaimContention contention = new ClaimContention(); - contention.setContentionId(CONTENTION_ID); - contention.setSpecialIssueCodes(SPECIAL_ISSUES_1); - contention.setLifecycleStatus(LIFE_CYCLE_STATUS_1.getDescription()); - contention.setAutomationIndicator(AUTOMATION_IND_1); - bipContentions.put(Long.parseLong(CLAIM_ID1), Collections.singletonList(contention)); - - contention = new ClaimContention(); - contention.setContentionId(CONTENTION_ID2); - contention.setSpecialIssueCodes(SPECIAL_ISSUES_2); - contention.setLifecycleStatus(LIFE_CYCLE_STATUS_2.getDescription()); - contention.setAutomationIndicator(AUTOMATION_IND_2); - bipContentions.put(Long.parseLong(CLAIM_ID2), Collections.singletonList(contention)); - } - - @BeforeEach - public void setup() { - claimProps = new ClaimProps(); - claimProps.setSpecialIssue1("RRD1"); - claimProps.setSpecialIssue2("RRD"); - } - - @Test - void hasAnchorsWrongJurisdiction() throws BipException { - long bipClaimId = Long.parseLong(CLAIM_ID1); - IBipApiService bipApiService = Mockito.mock(IBipApiService.class); - Mockito.when(bipApiService.getClaimDetails(bipClaimId)) - .thenReturn(createClaim("123", "King Cross")); - - BipClaimService claimService = new BipClaimService(claimProps, bipApiService, null, null); - assertFalse(claimService.hasAnchors(bipClaimId)); - } - - @Test - void hasAnchorsMissingSpecialIssue() throws BipException { - long bipClaimId = Long.parseLong(CLAIM_ID1); - IBipApiService bipApiService = Mockito.mock(IBipApiService.class); - Mockito.when(bipApiService.getClaimDetails(bipClaimId)) - .thenReturn(createClaim(CLAIM_ID1, "398")); - Mockito.when(bipApiService.getClaimContentions(bipClaimId)) - .thenReturn( - List.of( - createContention(List.of("TEST", "RRD")), - createContention(List.of("RRD", "OTHER")))); - - BipClaimService claimService = new BipClaimService(claimProps, bipApiService, null, null); - assertFalse(claimService.hasAnchors(bipClaimId)); - } - - @Test - void hasAnchors() throws BipException { - - long bipClaimId = Long.parseLong(CLAIM_ID1); - IBipApiService bipApiService = Mockito.mock(IBipApiService.class); - Mockito.when(bipApiService.getClaimDetails(bipClaimId)) - .thenReturn(createClaim(CLAIM_ID1, "398")); - Mockito.when(bipApiService.getClaimContentions(bipClaimId)) - .thenReturn( - List.of( - createContention(List.of("TEST", "RRD")), - createContention(List.of(claimProps.getSpecialIssue1(), "OTHER")))); - - BipClaimService claimService = new BipClaimService(claimProps, bipApiService, null, null); - assertFalse(claimService.hasAnchors(bipClaimId)); - } - - @Test - void removeSpecialIssueMissing() throws BipException { - long bipClaimId = Long.parseLong(CLAIM_ID1); - IBipApiService bipApiService = Mockito.mock(IBipApiService.class); - - Mockito.when(bipApiService.getClaimDetails(bipClaimId)) - .thenReturn(createClaim(CLAIM_ID1, "Short Line")); - - Mockito.when(bipApiService.getClaimContentions(bipClaimId)) - .thenReturn( - List.of( - createContention(List.of("TEST", "RRD")), - createContention(List.of("RRD", "OTHER")))); - - SaveToDbService saveToDbService = Mockito.mock(SaveToDbService.class); - Mockito.doNothing().when(saveToDbService).updateRfdFlag(CLAIM_ID1, true); - - BipClaimService claimService = - new BipClaimService(claimProps, bipApiService, null, saveToDbService); - var payload = MasTestData.getMasAutomatedClaimPayload(collectionId, "1701", CLAIM_ID1); - var mpo = new MasProcessingObject(payload, MasCamelStage.DURING_PROCESSING); - claimService.updateClaim(mpo, MasCompletionStatus.READY_FOR_DECISION); - } - - @Test - void removeSpecialIssue() throws BipException { - long bipClaimId = Long.parseLong(CLAIM_ID1); - IBipApiService bipApiService = Mockito.mock(IBipApiService.class); - - Mockito.when(bipApiService.getClaimDetails(bipClaimId)) - .thenReturn(createClaim(CLAIM_ID1, "Short Line")); - - Mockito.when(bipApiService.getClaimContentions(bipClaimId)) - .thenReturn( - List.of( - createContention(List.of("TEST", "RRD")), - createContention(List.of(claimProps.getSpecialIssue1().toLowerCase(), "OTHER")))); - - SaveToDbService saveToDbService = Mockito.mock(SaveToDbService.class); - Mockito.doNothing().when(saveToDbService).updateRfdFlag(CLAIM_ID1, true); - - BipClaimService claimService = - new BipClaimService(claimProps, bipApiService, null, saveToDbService); - var payload = MasTestData.getMasAutomatedClaimPayload(collectionId, "1701", CLAIM_ID1); - var mpo = new MasProcessingObject(payload, MasCamelStage.DURING_PROCESSING); - claimService.updateClaim(mpo, MasCompletionStatus.READY_FOR_DECISION); - } - - // TODO -> Fix this test <--- - /* - @Test - void completeProcessing() throws BipException { - long bipClaimId = Long.parseLong(claimId); - IBipApiService bipApiService = Mockito.mock(IBipApiService.class); - Mockito.when(bipApiService.getClaimDetails(bipClaimId)).thenReturn(createClaim(claimId, "398")); - - SaveToDbService saveToDbService = Mockito.mock(SaveToDbService.class); - Mockito.doNothing().when(saveToDbService).updateRfdFlag(String.valueOf(claimId), true); - - BipClaimService claimService = new BipClaimService(null, bipApiService, null, null); - var payload = MasTestData.getMasAutomatedClaimPayload(collectionId, "1701", claimId); - assertTrue(claimService.markAsRfd(getMpo(payload)).isTSOJ()); - Mockito.verify(bipApiService).setClaimToRfdStatus(bipClaimId); - } - */ - // TODO -> Fix this test <--- - - @Test - void uploadPdf_missingData() { - IBipCeApiService bipCeApiService = Mockito.mock(IBipCeApiService.class); - BipClaimService claimService = new BipClaimService(null, null, bipCeApiService, null); - var payload = MasTestData.getMasAutomatedClaimPayload(); - FetchPdfResponse fetchPdfResponse = new FetchPdfResponse(); - try { - claimService.uploadPdf(payload, fetchPdfResponse); - fail(); - } catch (BipException e) { - assertEquals("PDF Response does not contain any data", e.getMessage()); - } - } - - @Test - void uploadPdf() { - IBipCeApiService bipCeApiService = Mockito.mock(IBipCeApiService.class); - BipClaimService claimService = new BipClaimService(null, null, bipCeApiService, null); - FetchPdfResponse fetchPdfResponse = new FetchPdfResponse(); - var data = Base64.getEncoder().encode("Hello!".getBytes(StandardCharsets.UTF_8)); - fetchPdfResponse.setPdfData(new String(data)); - var payload = MasTestData.getMasAutomatedClaimPayload(); - claimService.uploadPdf(payload, fetchPdfResponse); - } - - @Test - void testUpdateClaim() { - initializeBipClaims(); - BipApiTestService bipApiService = new BipApiTestService(); - - ClaimProps claimProp = new ClaimProps(); - claimProp.setSpecialIssue1(SPECIAL_ISSUES_1.get(0)); - claimProp.setSpecialIssue2(SPECIAL_ISSUES_1.get(1)); - - SaveToDbService saveToDbService = Mockito.mock(SaveToDbService.class); - Mockito.doNothing().when(saveToDbService).updateRfdFlag(anyString(), anyBoolean()); - - BipClaimService claimService = - new BipClaimService(claimProp, bipApiService, null, saveToDbService); - - for (long claimId : bipClaims.keySet()) { - for (MasCamelStage stage : MasCamelStage.values()) { - MasProcessingObject payload = getMasPayload(claimId, stage); - for (MasCompletionStatus status : MasCompletionStatus.values()) { - BipUpdateClaimResult result = claimService.updateClaim(payload, status); - Set specialIssueCodes = status.getSpecialIssuesToRemove(claimProps); - verifyUpdateClaimResult(result, payload, status, stage, specialIssueCodes); - } - } - } - } - - private void verifyUpdateClaimResult( - BipUpdateClaimResult result, - MasProcessingObject payload, - MasCompletionStatus status, - MasCamelStage stage, - Set specialIssueCodes) { - assertTrue(result.isSuccess()); - long claimId = Long.parseLong(payload.getBenefitClaimId()); - BipClaim claim = bipClaims.get(claimId); - ClaimStatus expectedStatus = status.getClaimStatus(); - - // Check claim status - assertEquals(expectedStatus.getDescription(), claim.getClaimLifecycleStatus()); - - // Check contention. It is assumed the claim should have only one contention. - List contentions = bipContentions.get(claimId); - for (ClaimContention contention : contentions) { - // Check automation indicator. - if (status.isAutomationIndicator()) { - assertTrue(contention.isAutomationIndicator()); - } - - // Check special issue codes - if (!specialIssueCodes.isEmpty()) { - assertFalse( - contention.getSpecialIssueCodes().stream() - .anyMatch(c -> specialIssueCodes.contains(c))); - } - - // Check contention life cycle status - assertEquals(status.getClaimStatus().getDescription(), contention.getLifecycleStatus()); - } - } - - private static MasProcessingObject getMasPayload(long claimId, MasCamelStage stage) { - ClaimDetail claimDetail = new ClaimDetail(); - claimDetail.setBenefitClaimId(claimId + ""); - MasAutomatedClaimPayload claimPayload = - MasAutomatedClaimPayload.builder().claimDetail(claimDetail).build(); - return new MasProcessingObject(claimPayload, stage); - } - - private ClaimContention createContention(List codes) { - var contention = new ClaimContention(); - contention.setSpecialIssueCodes(codes); - return contention; - } - - private BipClaim createClaim(String claimId, String station) { - var claim = new BipClaim(); - claim.setClaimId(claimId); - claim.setTempStationOfJurisdiction(station); - return claim; - } - - private MasProcessingObject getMpo(MasAutomatedClaimPayload payload) { - return new MasProcessingObject(payload, MasCamelStage.DURING_PROCESSING); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasAssessmentResultProcessorTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasAssessmentResultProcessorTest.java deleted file mode 100644 index 77fa7b5426..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasAssessmentResultProcessorTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package gov.va.vro.service; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import gov.va.vro.BaseIntegrationTest; -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.persistence.repository.AssessmentResultRepository; -import gov.va.vro.service.provider.camel.processor.MasAssessmentResultProcessor; -import gov.va.vro.service.spi.db.SaveToDbService; -import gov.va.vro.service.spi.model.Claim; -import org.apache.camel.Exchange; -import org.apache.camel.Message; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; - -import java.util.Map; - -public class MasAssessmentResultProcessorTest extends BaseIntegrationTest { - - @Autowired MasAssessmentResultProcessor processor; - - @Autowired SaveToDbService saveToDbService; - - @Autowired AssessmentResultRepository assessmentResultRepository; - - @Test - void testPersist() throws Exception { - String benefitClaimId = "111"; - String collectionId = "666"; - String diagnosticCode = "999"; - String idType = MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE; - - Claim claim = new Claim(); - - claim.setBenefitClaimId(benefitClaimId); - claim.setIdType(idType); - claim.setVeteranIcn("v1"); - claim.setDiagnosticCode(diagnosticCode); - claim.setCollectionId(collectionId); - saveToDbService.insertClaim(claim); - - // IdType on evidence is set by the processor since it doesn't come in otherwise. - // This is why the below line of exchange getProperty is important to mock. - var evidence = new AbdEvidenceWithSummary(); - evidence.setClaimSubmissionId(collectionId); - evidence.setEvidenceSummary(Map.of("Hello", 10)); - - var message = Mockito.mock(Message.class); - var exchange = Mockito.mock(Exchange.class); - Mockito.when(exchange.getMessage()).thenReturn(message); - Mockito.when(exchange.getProperty("diagnosticCode", String.class)).thenReturn(diagnosticCode); - Mockito.when(exchange.getProperty("idType", String.class)).thenReturn(idType); - - Mockito.when(message.getBody(AbdEvidenceWithSummary.class)).thenReturn(evidence); - processor.process(exchange); - - claimSubmissionRepository - .findFirstByReferenceIdAndIdTypeOrderByCreatedAtDesc(collectionId, idType) - .orElseThrow(); - var results = - assessmentResultRepository.findAll().stream() - .filter(result -> diagnosticCode.equals(result.getContention().getDiagnosticCode())) - .toList(); - assertEquals(1, results.size()); - var result = results.get(0); - var summary = result.getEvidenceCountSummary(); - assertEquals("10", summary.get("Hello")); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasCollectionAnnotsResultsTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasCollectionAnnotsResultsTest.java deleted file mode 100644 index 4c840ffbb5..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasCollectionAnnotsResultsTest.java +++ /dev/null @@ -1,80 +0,0 @@ -package gov.va.vro.service; - -import static gov.va.vro.model.rrd.mas.MasAnnotType.BLOOD_PRESSURE; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.mas.MasAnnotation; -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import gov.va.vro.model.rrd.mas.MasDocument; -import gov.va.vro.service.provider.mas.service.mapper.MasCollectionAnnotsResults; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** @author warren @Date 3/20/23 */ -@Slf4j -class MasCollectionAnnotsResultsTest { - - private static final int COLLECTION_ID = 350; - - private static final String[] BP_ANNOTATIONS = {"120/80", "150/ 82", "125/-", "32 ", "-/80"}; - private static final String[] BAD_BP_ANNOTATIONS = {"-/-", "120325 mg/dL", "-/3245 mg/dL"}; - - private static final String BP_CONDITION = "Hypertension"; - - @BeforeEach - void setUp() {} - - @Test - public void mapAnnotationsToEvidenceTest() { - MasCollectionAnnotation masCollectionAnnotation = new MasCollectionAnnotation(); - masCollectionAnnotation.setCollectionsId(COLLECTION_ID); - List annotationList = new ArrayList<>(); - String annotType = BLOOD_PRESSURE.getMasAnnotTypeText(); - for (String annotation : BP_ANNOTATIONS) { - MasAnnotation annot = new MasAnnotation(); - annot.setAnnotType(annotType); - annot.setAnnotVal(annotation); - annotationList.add(annot); - } - - MasDocument doc = new MasDocument(); - doc.setCondition(BP_CONDITION); - doc.setAnnotations(annotationList); - masCollectionAnnotation.setDocuments(Collections.singletonList(doc)); - - MasCollectionAnnotsResults results = new MasCollectionAnnotsResults(); - AbdEvidence evidence = results.mapAnnotationsToEvidence(masCollectionAnnotation); - assertNotNull(evidence); - assertEquals(doc.getAnnotations().size(), evidence.getBloodPressures().size()); - - // Negative tests - - for (String annotation : BAD_BP_ANNOTATIONS) { - annotationList.clear(); - MasAnnotation annot = new MasAnnotation(); - annot.setAnnotType(annotType); - annot.setAnnotVal(annotation); - annotationList.add(annot); - - doc = new MasDocument(); - doc.setCondition(BP_CONDITION); - doc.setAnnotations(annotationList); - masCollectionAnnotation.setDocuments(Collections.singletonList(doc)); - try { - evidence = results.mapAnnotationsToEvidence(masCollectionAnnotation); - assertTrue(evidence.getBloodPressures().isEmpty()); - } catch (Exception e) { - fail("Failed to catch bad blood pressure annotation. " + annotation); - } - } - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasCollectionServiceTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasCollectionServiceTest.java deleted file mode 100644 index ffe87c8d48..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasCollectionServiceTest.java +++ /dev/null @@ -1,78 +0,0 @@ -package gov.va.vro.service; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import gov.va.vro.model.rrd.AbdCondition; -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.AbdMedication; -import gov.va.vro.model.rrd.HealthAssessmentSource; -import gov.va.vro.model.rrd.HealthDataAssessment; -import gov.va.vro.service.provider.mas.service.MasCollectionService; -import org.junit.jupiter.api.Test; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public class MasCollectionServiceTest { - - @Test - void combineEvidence() { - var lighthouseAssessment = createAssessment("123"); - lighthouseAssessment.setSource(HealthAssessmentSource.LIGHTHOUSE); - lighthouseAssessment.setEvidence( - createEvidence( - Arrays.asList(createMedication("med1", "LH"), createMedication("med2", "LH")), - Collections.singletonList(createCondition("cond2", "LH")))); - var masAssessment = createAssessment(null); - masAssessment.setSource(HealthAssessmentSource.MAS); - masAssessment.setDisabilityActionType("INCREASE"); - masAssessment.setEvidence( - createEvidence( - Collections.singletonList(createMedication("med1", "MAS")), - Arrays.asList(createCondition("cond1", "MAS"), createCondition("cond2", "MAS")))); - var result = MasCollectionService.combineEvidence(lighthouseAssessment, masAssessment); - assertEquals("INCREASE", result.getDisabilityActionType()); - assertEquals("12345", result.getDiagnosticCode()); - assertEquals("icn", result.getVeteranIcn()); - assertEquals("123", result.getClaimSubmissionId()); - var evidence = result.getEvidence(); - assertTrue(evidence.getBloodPressures().isEmpty()); - assertTrue(evidence.getProcedures().isEmpty()); - assertEquals(3, evidence.getMedications().size()); - assertEquals(3, evidence.getConditions().size()); - } - - private AbdCondition createCondition(String code, String source) { - var condition = new AbdCondition(); - condition.setCode(code); - condition.setText("text"); - condition.setDataSource(source); - return condition; - } - - private AbdMedication createMedication(String route, String source) { - var medication = new AbdMedication(); - medication.setRoute(route); - medication.setDescription("medication"); - medication.setDataSource(source); - return medication; - } - - private AbdEvidence createEvidence( - List medications, List conditions) { - var evidence = new AbdEvidence(); - evidence.setMedications(medications); - evidence.setConditions(conditions); - return evidence; - } - - private HealthDataAssessment createAssessment(String claimId) { - var assessment = new HealthDataAssessment(); - assessment.setClaimSubmissionId(claimId); - assessment.setDiagnosticCode("12345"); - assessment.setVeteranIcn("icn"); - return assessment; - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasProcessingServiceTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasProcessingServiceTest.java deleted file mode 100644 index b4b7880a88..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasProcessingServiceTest.java +++ /dev/null @@ -1,121 +0,0 @@ -package gov.va.vro.service; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import gov.va.vro.BaseIntegrationTest; -import gov.va.vro.MasTestData; -import gov.va.vro.model.rrd.event.EventReason; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.persistence.model.ClaimEntity; -import gov.va.vro.persistence.model.ClaimSubmissionEntity; -import gov.va.vro.persistence.repository.ClaimSubmissionRepository; -import gov.va.vro.service.provider.mas.service.MasProcessingService; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; - -import java.util.List; - -public class MasProcessingServiceTest extends BaseIntegrationTest { - - @Autowired MasProcessingService masProcessingService; - - @Autowired ClaimSubmissionRepository claimSubmissionRepository; - - @Test - void testClaimPersistence() { - var collectionId1 = 123; - var claimId1 = "123"; - var diagnosticCode1 = "71"; - var request1 = - MasTestData.getMasAutomatedClaimPayload(collectionId1, diagnosticCode1, claimId1); - masProcessingService.processIncomingClaimSaveToDB(request1); - - var claimEntity1 = verifyClaimPersisted(request1); - var contentions = claimEntity1.getContentions(); - assertEquals(1, contentions.size()); - var contention = contentions.get(0); - assertEquals(request1.getDiagnosticCode(), contention.getDiagnosticCode()); - // same claim, different diagnostic code - var diagnosticCode2 = "17"; - var request2 = - MasTestData.getMasAutomatedClaimPayload(collectionId1, diagnosticCode2, claimId1); - masProcessingService.processIncomingClaimSaveToDB(request2); - var claimEntity2 = verifyClaimPersisted(request2); - contentions = claimEntity2.getContentions(); - ClaimEntity claim = claimRepository.findByVbmsId(claimId1).orElseThrow(); - assertEquals(2, contentions.size()); - - // new claim - var claimId2 = "321"; - var request3 = - MasTestData.getMasAutomatedClaimPayload(collectionId1, diagnosticCode1, claimId2); - masProcessingService.processIncomingClaimSaveToDB(request3); - verifyClaimPersisted(request3); - } - - @Test - public void testNotInScope() { - var collectionId1 = 123; - var claimId1 = "123"; - var diagnosticCode1 = "71"; - var request1 = - MasTestData.getMasAutomatedClaimPayload(collectionId1, diagnosticCode1, claimId1); - var response1 = masProcessingService.processIncomingClaimGetUnprocessableReason(request1); - // wrong diagnostic code - assertEquals( - "Claim with collection id: 123, diagnostic code: 71, and" - + " disability action type: INCREASE is not in scope.", - response1); - - var request2 = MasTestData.getMasAutomatedClaimPayload(collectionId1, "7101", claimId1); - request2.getClaimDetail().getConditions().setDisabilityActionType("OTHER"); - var response2 = masProcessingService.processIncomingClaimGetUnprocessableReason(request2); - // wrong disability action - assertEquals( - "Claim with collection id: 123, diagnostic code: 7101, and" - + " disability action type: OTHER is not in scope.", - response2); - } - - @Test - public void testInScopeButNotPresumptive() { - var collectionId1 = 123; - var claimId1 = "123"; - var diagnosticCode1 = "7101"; - var request1 = - MasTestData.getMasAutomatedClaimPayload(collectionId1, diagnosticCode1, claimId1); - request1.getClaimDetail().getConditions().setDisabilityActionType("NEW"); - var response = masProcessingService.getOffRampReasonPresumptiveCheck(request1); - assertEquals(EventReason.NEW_NOT_PRESUMPTIVE.getReasonMessage(), response.get()); - } - - @Test - public void testInScopeAndPresumptiveButMissingAnchors() { - var collectionId = 123; - var claimId = "123"; - var diagnosticCode = "7101"; - var request = MasTestData.getMasAutomatedClaimPayload(collectionId, diagnosticCode, claimId); - request.getClaimDetail().getConditions().setDisabilityActionType("NEW"); - request = request.toBuilder().veteranFlashIds(List.of("123", "266")).build(); - var response = masProcessingService.processIncomingClaimGetUnprocessableReason(request); - assertEquals( - "Claim with collection id: 123 does not qualify for " - + "automated processing because it is missing anchors.", - response); - } - - private ClaimEntity verifyClaimPersisted(MasAutomatedClaimPayload request) { - var claim = claimRepository.findByVbmsId(request.getBenefitClaimId()).orElseThrow(); - var claimSubmissionList = - claimSubmissionRepository.findByReferenceIdAndIdType( - String.valueOf(request.getCollectionId()), MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - assertTrue(claimSubmissionList.size() > 0); - for (ClaimSubmissionEntity submission : claimSubmissionList) { - assertEquals(request.getCollectionId().toString(), submission.getReferenceId()); - } - - assertEquals(request.getVeteranIcn(), claim.getVeteran().getIcn()); - return claim; - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasServiceTest.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasServiceTest.java deleted file mode 100644 index 4fc9c96d10..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MasServiceTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package gov.va.vro.service; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import gov.va.vro.controller.BaseControllerTest; -import gov.va.vro.service.provider.mas.service.MasAuthToken; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@ActiveProfiles("test") -public class MasServiceTest extends BaseControllerTest { - - @Autowired MasAuthToken masAuthToken; - - @Test - void testService() { - assertNotNull(masAuthToken.getAuthorizedClientServiceAndManager()); - } -} diff --git a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MockBipApiService.java b/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MockBipApiService.java deleted file mode 100644 index 800949b8a0..0000000000 --- a/domain-rrd/rrd-app-test/src/test/java/gov/va/vro/service/MockBipApiService.java +++ /dev/null @@ -1,208 +0,0 @@ -package gov.va.vro.service; - -import gov.va.vro.model.rrd.bip.BipClaim; -import gov.va.vro.model.rrd.bip.BipUpdateClaimResp; -import gov.va.vro.model.rrd.bip.ClaimContention; -import gov.va.vro.model.rrd.bip.ClaimStatus; -import gov.va.vro.model.rrd.bip.UpdateContentionReq; -import gov.va.vro.service.provider.bip.BipException; -import gov.va.vro.service.provider.bip.service.BipClaimService; -import gov.va.vro.service.provider.bip.service.IBipApiService; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.List; - -/** Mock some claim data returned by the BIP API. */ -@Service -public class MockBipApiService implements IBipApiService { - private static final long CLAIM_ID_204 = 204L; - private static final long CLAIM_ID_400 = 400L; - private static final long CLAIM_ID_401 = 401L; - private static final long CLAIM_ID_404 = 404L; - private static final long CLAIM_ID_500 = 500L; - private static final long CLAIM_ID_501 = 501L; - - private static final String ERR_MSG_400 = - """ - { - "messages": [ - { - "timestamp": "2023-01-24T16:36:59.578", - "key": "Bad reqeust", - "severity": "ERROR", - "status": "400", - "text": "Invalid parameters.", - "httpStatus": "BAD_REQUEST" - } - ] - }"""; - - private static final String ERR_MSG_404 = - """ - { - "messages": [ - { - "timestamp": "2023-01-24T16:36:59.578", - "key": "bip.vetservices.claims.request.claimId.NotValid", - "severity": "ERROR", - "status": "404", - "text": "Claim not found.", - "httpStatus": "NOT_FOUND" - } - ] - }"""; - - private static final String ERR_MSG_401 = - """ - { - "messages": [ - { - "timestamp": "2023-01-24T16:36:59.578", - "key": "UNAUTHORIZED", - "severity": "ERROR", - "status": "401", - "text": "No JWT Token in Header.", - "httpStatus": "UNAUTHORIZED" - } - ] - }"""; - - private static final String ERR_MSG_500 = - """ - { - "messages": [ - { - "timestamp": "2023-01-24T16:36:59.578", - "key": "bip.framework.global.general.exception", - "severity": "ERROR", - "status": "500", - "text": "Unexpected exception.", - "httpStatus": "INTERNAL_SERVER_ERROR" - } - ] - }"""; - - private static final String ERR_MSG_501 = - """ - { - "messages": [ - { - "timestamp": "2023-01-24T16:36:59.578", - "key": "system error", - "severity": "ERROR", - "status": "501", - "text": "Not implemented.", - "httpStatus": "INTERNAL_SERVER_ERROR" - } - ] - }"""; - - @Override - public BipClaim getClaimDetails(long collectionId) { - if (collectionId == 350 || collectionId == 353) { - // valid - return buildClaim(1234, BipClaimService.TSOJ); - } else if (collectionId == 885491) { - // wrong station - return buildClaim(885491, "OTHER"); - } else if (collectionId == CLAIM_ID_404) { // invalid claim ID, throw BipException. - throw new BipException(HttpStatus.NOT_FOUND, ERR_MSG_404); - } else if (collectionId == CLAIM_ID_401) { // not authorized, throw BipException - throw new BipException(HttpStatus.UNAUTHORIZED, ERR_MSG_401); - } else if (collectionId == CLAIM_ID_500) { // internal error, throw BipException - throw new BipException(HttpStatus.INTERNAL_SERVER_ERROR, ERR_MSG_500); - } else { - return buildClaim(555, BipClaimService.TSOJ); - } - } - - @Override - public BipUpdateClaimResp setClaimToRfdStatus(long collectionId) throws BipException { - if (collectionId == CLAIM_ID_404) { // invalid claim ID, throw BipException - throw new BipException(HttpStatus.NOT_FOUND, ERR_MSG_404); - } else if (collectionId == CLAIM_ID_401) { // not authorized, throw BipException - throw new BipException(HttpStatus.UNAUTHORIZED, ERR_MSG_401); - } else if (collectionId == CLAIM_ID_400) { // not authorized, throw BipException - throw new BipException(HttpStatus.BAD_REQUEST, ERR_MSG_400); - } else if (collectionId == CLAIM_ID_500) { // internal error, throw BipException - throw new BipException(HttpStatus.UNAUTHORIZED, ERR_MSG_500); - } else if (collectionId == CLAIM_ID_501) { // 501 error, throw BipException - throw new BipException(HttpStatus.UNAUTHORIZED, ERR_MSG_501); - } else { - return new BipUpdateClaimResp(HttpStatus.OK, "OK from mock service."); - } - } - - @Override - public List getClaimContentions(long claimId) throws BipException { - if (claimId == 1234) { - return List.of(buildContention("RDR1", "RRD")); - } else if (claimId == CLAIM_ID_204) { // No data. Returns an empty list. - return new ArrayList<>(); - } else if (claimId == CLAIM_ID_404) { // invalid claim ID, throw BipException - throw new BipException(HttpStatus.NOT_FOUND, ERR_MSG_404); - } else if (claimId == CLAIM_ID_401) { // not authorized, throw BipException - throw new BipException(HttpStatus.UNAUTHORIZED, ERR_MSG_401); - } else if (claimId == CLAIM_ID_500) { // internal error, throw BipException - throw new BipException(HttpStatus.INTERNAL_SERVER_ERROR, ERR_MSG_500); - } else { - return List.of(buildContention("A", "B", "C")); - } - } - - @Override - public BipUpdateClaimResp updateClaimStatus(long claimId, ClaimStatus status) - throws BipException { - if (claimId == CLAIM_ID_404) { // invalid claim ID, throw BipException - throw new BipException(HttpStatus.NOT_FOUND, ERR_MSG_404); - } else if (claimId == CLAIM_ID_400) { // bad call, throw BipException - throw new BipException(HttpStatus.BAD_REQUEST, ERR_MSG_400); - } else if (claimId == CLAIM_ID_401) { // not authorized, throw BipException - throw new BipException(HttpStatus.UNAUTHORIZED, ERR_MSG_401); - } else if (claimId == CLAIM_ID_500) { // internal error, throw BipException - throw new BipException(HttpStatus.UNAUTHORIZED, ERR_MSG_500); - } else if (claimId == CLAIM_ID_501) { // 501 error, throw BipException - throw new BipException(HttpStatus.UNAUTHORIZED, ERR_MSG_501); - } else { - return new BipUpdateClaimResp(HttpStatus.OK, "OK from mock service."); - } - } - - @Override - public BipUpdateClaimResp updateClaimContention(long claimId, UpdateContentionReq contention) - throws BipException { - if (claimId == CLAIM_ID_404) { // invalid claim ID, throw BipException - throw new BipException(HttpStatus.NOT_FOUND, ERR_MSG_404); - } else if (claimId == CLAIM_ID_400) { // bad call, throw BipException - throw new BipException(HttpStatus.BAD_REQUEST, ERR_MSG_400); - } else if (claimId == CLAIM_ID_401) { // not authorized, throw BipException - throw new BipException(HttpStatus.UNAUTHORIZED, ERR_MSG_401); - } else if (claimId == CLAIM_ID_500) { // internal error, throw BipException - throw new BipException(HttpStatus.UNAUTHORIZED, ERR_MSG_500); - } else if (claimId == CLAIM_ID_501) { // 501 error, throw BipException - throw new BipException(HttpStatus.UNAUTHORIZED, ERR_MSG_501); - } else { - return new BipUpdateClaimResp(HttpStatus.CREATED, "OK from mock service."); - } - } - - @Override - public boolean verifySpecialIssueTypes() { - return true; - } - - private BipClaim buildClaim(int claimId, String station) { - var claim = new BipClaim(); - claim.setClaimId(Integer.toString(claimId)); - claim.setTempStationOfJurisdiction(station); - return claim; - } - - private ClaimContention buildContention(String... specialIssueCodes) { - var contention = new ClaimContention(); - contention.setSpecialIssueCodes(List.of(specialIssueCodes)); - return contention; - } -} diff --git a/domain-rrd/rrd-app-test/src/test/resources/application-test.yml b/domain-rrd/rrd-app-test/src/test/resources/application-test.yml deleted file mode 100644 index b61d675485..0000000000 --- a/domain-rrd/rrd-app-test/src/test/resources/application-test.yml +++ /dev/null @@ -1,39 +0,0 @@ -# This file is loaded when a test is annotated with @ActiveProfiles("test") -# Spring will load main/resources/application.yml, followed by this file. -# Since we want tests to be as close as possible to the deployed app, don't create test/resources/application.yml. -# If test/resources/application.yml exists, it will override main/resources/application.yml. - -# Load main/resources/application-nonprod.yml and main/resources/application-local.yml -spring.config.import: > - application-nonprod.yml, - application-local.yml - -# Since this is for tests, override some main/resources/application.yml Spring settings -spring: - datasource: - url: jdbc:h2:mem:example;DB_CLOSE_DELAY=-1;MODE=PostgreSQL; - username: skuser - password: localT3st! - # Disable hikari for tests -- https://stackoverflow.com/a/71408822 - type: org.springframework.jdbc.datasource.SimpleDriverDataSource - jpa: - hibernate: - ddl-auto: create - show-sql: true - properties: - hibernate: - dialect: org.hibernate.dialect.PostgreSQLDialect - flyway: - enabled: false - security: - oauth2: - client: - registration: - mas: - client-id: "${MAS_API_AUTH_CLIENTID:placeholderId}" - client-secret: "${MAS_API_AUTH_CLIENT_SECRET:placeholderClientSecret}" -lhAPIProvider: - tokenValidatorURL: "${LH_API_AUTH_URL:placeholderUrl}" - vroAudURL: "${VRO_AUD_URL:placeholderUrl}" - apiKey: "${LH_VRO_API_KEY:placeholderKey}" - validateToken: "NO" diff --git a/domain-rrd/rrd-app-test/src/test/resources/mas-request.json b/domain-rrd/rrd-app-test/src/test/resources/mas-request.json deleted file mode 100644 index db852643d0..0000000000 --- a/domain-rrd/rrd-app-test/src/test/resources/mas-request.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "dob": "2002-12-12", - "firstName": "Rick", - "lastName": "Smith", - "gender": null, - "collectionId": "123", - "veteranIdentifiers": { - "icn": "X", - "ssn": "X", - "veteranFileId": "X", - "edipn": "X", - "participantId": "X" - }, - "claimDetail": { - "claimSubmissionSource": "VA.GOV", - "conditions": { - "diagnosticCode": "1233" - } - } -} diff --git a/domain-rrd/rrd-app-test/src/test/resources/test-data/pdf-generator-input-01.json b/domain-rrd/rrd-app-test/src/test/resources/test-data/pdf-generator-input-01.json deleted file mode 100644 index c61a87a2ba..0000000000 --- a/domain-rrd/rrd-app-test/src/test/resources/test-data/pdf-generator-input-01.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "claimSubmissionId": "1234", - "diagnosticCode": "7101", - "veteranInfo": { - "first": "Joe", - "middle": "M", - "last": "Doe", - "suffix": "Jr", - "birthdate": "01/04/1971" - }, - "veteranFileId": "12345", - "pdfTemplate": "v1", - "evidence": { - "medications": [ - { - "status": "Active", - "description": "Hydrochlorothiazide 6.25 MG", - "refills": 0, - "authoredOn": "1950-04-05T23:00:00Z", - "dosageInstructions": [ - "QD" - ], - "route": "ORAL", - "partialDate":"" - }, - { - "status": "Active", - "notes": [ - "Hydrochlorothiazide 6.25 MG" - ], - "description": "Hydrochlorothiazide 6.25 MG", - "refills": 0, - "authoredOn": "1950-04-06T07:24:55Z", - "dosageInstructions": [ - "Once per day.", - "As directed by physician." - ], - "route": "As directed by physician.", - "partialDate":"" - } - ], - "bp_readings": [ - { - "date": "2009-03-19", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 83.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 131.0 - }, - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "date": "2010-03-25", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 82.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 138.0 - }, - "practitioner": "DR. THOMAS359 REYNOLDS206 PHD", - "organization": "NEW AMSTERDAM CBOC" - }, - { - "date": "2011-03-31", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 71.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 101.0 - }, - "practitioner": "DR. JOHN248 SMITH811 MD", - "organization": "LYONS VA MEDICAL CENTER" - } - ] - } -} diff --git a/domain-rrd/rrd-app-test/src/test/resources/test-data/pdf-generator-mas.json b/domain-rrd/rrd-app-test/src/test/resources/test-data/pdf-generator-mas.json deleted file mode 100644 index cdb0f1ac03..0000000000 --- a/domain-rrd/rrd-app-test/src/test/resources/test-data/pdf-generator-mas.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - "claimSubmissionId": "1234", - "diagnosticCode": "7101", - "pdfTemplate": "v2", - "conditions": { - "disabilityActionType": "NEW", - "name": "high blood pressure" - }, - "veteranInfo": { - "first": "Joe", - "middle": "M", - "last": "Doe", - "suffix": "Jr", - "birthdate": "01/04/1971" - }, - "evidence": { - "serviceLocations": [ - {"location": "Vietnam", - "document": "VA 21-3101 Request for Information", - "receiptDate" : "1/28/2016", - "page": "2", - "documentId": "{BFA4943C-4F56-4AC5-B48F-5FDE469B1226}"}], - "conditions": [{"code": "I10", - "text": "Essential (primary) hypertension", - "recordedDate": "04-06-1950", - "dateFormatted": "4/6/1950", - "relevant": true, - "dataSource": "LH", - "partialDate": "" - }, - {"code": "38341003", - "relevant": false, - "text": "Hypertensive disorder", - "dateFormatted": "4/6/1950", - "dataSource": "MAS", - "partialDate": ""} - ], - "medications": [ - { - "status": "Active", - "description": "Hydrochlorothiazide 6.25 MG", - "refills": 0, - "authoredOn": "1950-04-05T23:00:00Z", - "dateFormatted": "4/6/1950", - "docTypeDescription": "C and P Exam", - "dosageInstructions": [ - "QD" - ], - "route": "ORAL", - "dataSource": "MAS", - "partialDate": "" - }, - { - "status": "Active", - "notes": [ - "Hydrochlorothiazide 6.25 MG" - ], - "description": "Hydrochlorothiazide 6.25 MG", - "refills": 0, - "authoredOn": "", - "dateFormatted": "", - "dosageInstructions": [ - "Once per day.", - "As directed by physician." - ], - "route": "As directed by physician.", - "dataSource": "MAS", - "partialDate": "*/6/1950" - } - ], - "bp_readings": [ - { - "date": "2009-03-19", - "dateFormatted": "3/19/2009", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 83.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 131.0 - }, - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "date": "2010-03-25", - "dateFormatted": "3/25/2010", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 82.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 138.0 - }, - "practitioner": "DR. THOMAS359 REYNOLDS206 PHD", - "organization": "NEW AMSTERDAM CBOC" - }, - { - "date": "2011-03-31", - "dateFormatted": "3/25/2010", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 71.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 101.0 - }, - "practitioner": "DR. JOHN248 SMITH811 MD", - "organization": "LYONS VA MEDICAL CENTER" - } - ], - "documentsWithoutAnnotationsChecked": [ - "{guid1}" - ] - } -} diff --git a/domain-rrd/rrd-shared/build.gradle.bak b/domain-rrd/rrd-shared/build.gradle.bak deleted file mode 100644 index 8d8a5b319c..0000000000 --- a/domain-rrd/rrd-shared/build.gradle.bak +++ /dev/null @@ -1,7 +0,0 @@ -plugins { - id 'local.std.java.library-conventions' -} - -dependencies { - implementation "org.springdoc:springdoc-openapi-webmvc-core:${spring_doc_version}" -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/bgs/BgsApiClientRequest.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/bgs/BgsApiClientRequest.java deleted file mode 100644 index c964b7d16e..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/bgs/BgsApiClientRequest.java +++ /dev/null @@ -1,30 +0,0 @@ -package gov.va.vro.model.rrd.bgs; - -import lombok.Data; -import lombok.RequiredArgsConstructor; - -import java.util.ArrayList; -import java.util.List; - -@Data -@RequiredArgsConstructor -public class BgsApiClientRequest { - - // aka benefitClaimId - final String vbmsClaimId; - final String veteranParticipantId; - - /** - * Veteran-level notes must be submitted separately from claim-level notes and submitted - * individually (one at a time). - */ - public String veteranNote; - - /** Multiple claim notes can be submitted */ - public List claimNotes = new ArrayList<>(); - - public boolean isConstraintSatisfied() { - if (veteranNote == null) return vbmsClaimId != null && !claimNotes.isEmpty(); - else return veteranParticipantId != null && claimNotes.isEmpty(); - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/bgs/BgsApiClientResponse.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/bgs/BgsApiClientResponse.java deleted file mode 100644 index c59a830ccb..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/bgs/BgsApiClientResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package gov.va.vro.model.rrd.bgs; - -import lombok.Data; -import lombok.RequiredArgsConstructor; - -@Data -@RequiredArgsConstructor -public class BgsApiClientResponse { - public int statusCode; - public String statusMessage; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/AssessmentInfo.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/AssessmentInfo.java deleted file mode 100644 index 57074e9e9d..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/AssessmentInfo.java +++ /dev/null @@ -1,21 +0,0 @@ -package gov.va.vro.model.rrd.claimmetrics; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.Map; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -@Builder -@EqualsAndHashCode -public class AssessmentInfo { - private Map evidenceInfo; - private Boolean sufficientEvidenceFlag; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ClaimInfoQueryParams.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ClaimInfoQueryParams.java deleted file mode 100644 index 9ef9870553..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ClaimInfoQueryParams.java +++ /dev/null @@ -1,20 +0,0 @@ -package gov.va.vro.model.rrd.claimmetrics; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -@EqualsAndHashCode -public class ClaimInfoQueryParams { - @Builder.Default private int page = 0; - @Builder.Default private int size = 10; - private String icn; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ClaimsInfo.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ClaimsInfo.java deleted file mode 100644 index 3a2e201be0..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ClaimsInfo.java +++ /dev/null @@ -1,18 +0,0 @@ -package gov.va.vro.model.rrd.claimmetrics; - -import gov.va.vro.model.rrd.claimmetrics.response.ClaimInfoResponse; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.List; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -public class ClaimsInfo { - private List claimInfoList; - private long total; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ContentionInfo.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ContentionInfo.java deleted file mode 100644 index f8405bc6e7..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ContentionInfo.java +++ /dev/null @@ -1,24 +0,0 @@ -package gov.va.vro.model.rrd.claimmetrics; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.List; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -@Builder -@EqualsAndHashCode -public class ContentionInfo { - private String diagnosticCode; - - private List assessments; - - private List documents; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/DocumentInfo.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/DocumentInfo.java deleted file mode 100644 index cc26d5ad6b..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/DocumentInfo.java +++ /dev/null @@ -1,22 +0,0 @@ -package gov.va.vro.model.rrd.claimmetrics; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.Map; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -@Builder -@EqualsAndHashCode -public class DocumentInfo { - private String documentName; - - private Map evidenceInfo; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ExamOrderInfoQueryParams.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ExamOrderInfoQueryParams.java deleted file mode 100644 index ddd54cf761..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ExamOrderInfoQueryParams.java +++ /dev/null @@ -1,20 +0,0 @@ -package gov.va.vro.model.rrd.claimmetrics; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -@EqualsAndHashCode -public class ExamOrderInfoQueryParams { - @Builder.Default private int page = 0; - @Builder.Default private int size = 10; - @Builder.Default private Boolean notOrdered = Boolean.FALSE; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ExamOrdersInfo.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ExamOrdersInfo.java deleted file mode 100644 index 7214a836b9..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/ExamOrdersInfo.java +++ /dev/null @@ -1,47 +0,0 @@ -package gov.va.vro.model.rrd.claimmetrics; - -import gov.va.vro.model.rrd.claimmetrics.response.ExamOrderInfoResponse; -import gov.va.vro.model.rrd.event.Auditable; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -public class ExamOrdersInfo implements Auditable { - private List examOrderInfoList; - private long total; - - @Override - public String getEventId() { - return "ExamOrderSlackEvent"; - } - - @Override - public Map getDetails() { - Map detailsMap = new HashMap<>(); - for (ExamOrderInfoResponse exam : examOrderInfoList) { - String examInfo = - "collectionId: " - + exam.getCollectionId() - + " createdAt: " - + exam.getCreatedAt() - + " status: " - + exam.getStatus(); - detailsMap.put("ExamOrder", examInfo); - } - return detailsMap; - } - - @Override - public String getDisplayName() { - return "ExamOrderSlackEvent"; - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/response/ClaimInfoResponse.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/response/ClaimInfoResponse.java deleted file mode 100644 index 05662367d9..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/response/ClaimInfoResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -package gov.va.vro.model.rrd.claimmetrics.response; - -import gov.va.vro.model.rrd.claimmetrics.ContentionInfo; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.List; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -@Builder -@EqualsAndHashCode -public class ClaimInfoResponse { - private String claimSubmissionId; - private String collectionId; // will be empty for v1 claims. - private String idType; - private String veteranIcn; - private List contentions; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/response/ClaimMetricsResponse.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/response/ClaimMetricsResponse.java deleted file mode 100644 index 4f369a0feb..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/response/ClaimMetricsResponse.java +++ /dev/null @@ -1,22 +0,0 @@ -package gov.va.vro.model.rrd.claimmetrics.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -@Builder -@EqualsAndHashCode -@ToString -public class ClaimMetricsResponse { - private long totalClaims; - private long totalEvidenceGenerations; - private long totalPdfGenerations; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/response/ExamOrderInfoResponse.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/response/ExamOrderInfoResponse.java deleted file mode 100644 index 3491584620..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/claimmetrics/response/ExamOrderInfoResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -package gov.va.vro.model.rrd.claimmetrics.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.time.LocalDateTime; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -@Builder -@EqualsAndHashCode -public class ExamOrderInfoResponse { - private String collectionId; - private String status; - private LocalDateTime orderedAt; - private LocalDateTime createdAt; - private LocalDateTime updatedAt; - private boolean hasAssociatedClaimSubmission; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/AuditEvent.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/AuditEvent.java deleted file mode 100644 index 8deeefdf5c..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/AuditEvent.java +++ /dev/null @@ -1,119 +0,0 @@ -package gov.va.vro.model.rrd.event; - -import lombok.Builder; -import lombok.Getter; - -import java.time.ZonedDateTime; -import java.util.Map; - -@Getter -@Builder(toBuilder = true) -public class AuditEvent { - - private String eventId; - private String routeId; - private String payloadType; - private Throwable throwable; - - // WARNING: DO NOT STORE PII/PHI - private String[] messages; - - // WARNING: DO NOT STORE PII/PHI - private Map details; - - @Builder.Default private ZonedDateTime eventTime = ZonedDateTime.now(); - - public boolean isException() { - return throwable != null; - } - - /** - * From auditable. - * - * @param auditable auditable. - * @param routeId route ID. - * @param message message. - * @return return. - */ - public static AuditEvent fromAuditable(Auditable auditable, String routeId, String message) { - - return AuditEvent.builder() - .eventId(auditable.getEventId()) - .routeId(routeId) - .payloadType(auditable.getDisplayName()) - .messages(new String[] {message}) - .details(auditable.getDetails()) - .build(); - } - - /** - * From auditable. - * - * @param auditable auditable. - * @param routeId route ID. - * @param messages messages. - * @return return. - */ - public static AuditEvent fromAuditable(Auditable auditable, String routeId, String[] messages) { - return AuditEvent.builder() - .eventId(auditable.getEventId()) - .routeId(routeId) - .payloadType(auditable.getDisplayName()) - .messages(messages) - .details(auditable.getDetails()) - .build(); - } - /** - * From exception. - * - * @param auditable auditable. - * @param routeId route ID. - * @param exception exception. - * @return return. - */ - public static AuditEvent fromException(Auditable auditable, String routeId, Throwable exception) { - - return AuditEvent.builder() - .eventId(auditable.getEventId()) - .routeId(routeId) - .payloadType(auditable.getDisplayName()) - .messages(new String[] {exception.getMessage()}) - .throwable(exception) - .build(); - } - - /** - * To string. - * - * @return the string. - */ - @Override - public String toString() { - if (isException()) { - return String.format( - "Exception occurred on route %s for %s(id = %s): %s.\n" - + "Please check the audit store for more information.", - routeId, payloadType, eventId, String.join(", ", messages)); - } else { - return toSimpleString(); - } - } - - /** - * To simple string. - * - * @return return string. - */ - public String toSimpleString() { - return "AuditEvent{" - + "routeId='" - + routeId - + '\'' - + ", payloadType=" - + payloadType - + ", message='" - + String.join(", ", messages) - + '\'' - + '}'; - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/Auditable.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/Auditable.java deleted file mode 100644 index de67133b49..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/Auditable.java +++ /dev/null @@ -1,13 +0,0 @@ -package gov.va.vro.model.rrd.event; - -import java.util.Map; - -/** POJOs implementing this interface participate in audit events. */ -public interface Auditable { - - String getEventId(); - - Map getDetails(); - - String getDisplayName(); -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/EventReason.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/EventReason.java deleted file mode 100644 index ded23c7a0b..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/EventReason.java +++ /dev/null @@ -1,48 +0,0 @@ -package gov.va.vro.model.rrd.event; - -import lombok.Getter; - -/** - * The object lists events that can happen in VRO process. Each event has a code and a narrative - * message. It can be used to handle the event message consistently in the VRO process. - * - * @author warren @Date 4/6/23 - */ -@Getter -public enum EventReason { - SUFFICIENCY_UNDETERMINED("assessorError", "Sufficiency cannot be determined."), - NEW_NOT_PRESUMPTIVE( - "newClaimMissingFlash266", "New claim cannot be determined to be presumptive."), - PDF_UPLOAD_FAILED_AFTER_ORDER_EXAM( - "docUploadFailed", "PDF upload failed after exam order requested."), - PDF_UPLOAD_FAILED_AFTER_RFD("docUploadFailedRfd", "Failed to upload PDF file."), - EXAM_ORDER_FAILED("examOrderFailed", "Failed to order exam."), - ANNOTATIONS_FAILED("annotationDataRequestFailed", "Failed to get annotation data."), - BIP_UPDATE_FAILED("bipUpdateFailed", "BIP update failed."), - HEALTH_PROCESSOR_FAILED("healthProcessFailed", "Processing health data failed."); - - private static int MAX_CODE_LENGTH = 50; - - private String code; - private String narrative; - - EventReason(String code, String narrative) { - this.code = code; - this.narrative = narrative; - } - - public String getReasonMessage() { - return String.format("reason code: %s, narrative:%s", code, narrative); - } - - public static EventReason getEventReason(String reasonCode) { - if (reasonCode.length() < MAX_CODE_LENGTH) { - for (EventReason reason : EventReason.values()) { - if (reasonCode.equals(reason.getCode())) { - return reason; - } - } - } - return null; - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/JsonConverter.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/JsonConverter.java deleted file mode 100644 index fbdb149037..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/event/JsonConverter.java +++ /dev/null @@ -1,18 +0,0 @@ -package gov.va.vro.model.rrd.event; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.SneakyThrows; - -import java.util.function.Function; - -/** Maps an object to a JSON String. */ -public class JsonConverter implements Function { - - private final ObjectMapper objectMapper = new ObjectMapper(); - - @Override - @SneakyThrows - public String apply(Auditable auditable) { - return objectMapper.writeValueAsString(auditable); - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/ClaimCondition.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/ClaimCondition.java deleted file mode 100644 index c9c281878e..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/ClaimCondition.java +++ /dev/null @@ -1,32 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Getter; -import lombok.Setter; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; - -@Getter -@Setter -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonIgnoreProperties(ignoreUnknown = true) -public class ClaimCondition { - - private String name; - - @NotNull - @Schema(description = "Diagnostic code", example = "7101") - @NotBlank(message = "Diagnostic Code is required") - private String diagnosticCode; - - @Schema(description = "Disability action type", example = "NEW") - private String disabilityActionType; - - @Schema(description = "Disability classification code", example = "3460") - private String disabilityClassificationCode; - - private String ratedDisabilityId; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/ClaimDetail.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/ClaimDetail.java deleted file mode 100644 index b929273f93..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/ClaimDetail.java +++ /dev/null @@ -1,31 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Getter; -import lombok.Setter; - -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; - -@Getter -@Setter -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonIgnoreProperties(ignoreUnknown = true) -public class ClaimDetail { - - @Schema(description = "Claim ID", example = "1020") - private String benefitClaimId; - - @Schema(description = "Claim submission timestamp", example = "2023-02-08T18:45:59Z") - @NotBlank - private String claimSubmissionDateTime; - - @Schema(description = "Source of claim", example = "VA.GOV") - @NotBlank - private String claimSubmissionSource = "VA.GOV"; - - @NotNull @Valid private ClaimCondition conditions; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasAnnotType.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasAnnotType.java deleted file mode 100644 index ff5417e63f..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasAnnotType.java +++ /dev/null @@ -1,42 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -/** - * Represents medical data domains used in decision rules in Automated Benefit Delivery health - * assessment. - */ -public enum MasAnnotType { - MEDICATION("medication"), - LABRESULT("lab_result"), - - BLOOD_PRESSURE("blood_pressure"), - - PROCEDURE("procedure"), - SERVICE("service"), - CONDITION("medical_condition"), - UNKNOWN(""); - - private final String masAnnotTypeText; - - MasAnnotType(String masAnnotTypeText) { - this.masAnnotTypeText = masAnnotTypeText; - } - - public String getMasAnnotTypeText() { - return this.masAnnotTypeText; - } - - /** - * Mas Annotation type from string. - * - * @param text text. - * @return type. - */ - public static MasAnnotType fromString(String text) { - for (MasAnnotType masAnnotType : MasAnnotType.values()) { - if (masAnnotType.masAnnotTypeText.equalsIgnoreCase(text)) { - return masAnnotType; - } - } - return UNKNOWN; - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasAnnotation.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasAnnotation.java deleted file mode 100644 index 45c98223d2..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasAnnotation.java +++ /dev/null @@ -1,73 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -/** - * MAS annotation class. Fields are populated by automated processing of supporting documents - * related to a given claim. A single @code{MasDocument} may be associated with - * multiple @code{MasAnnotation}s. - * - * @author warren @Date 10/5/22 - */ -@NoArgsConstructor -@Getter -@Setter -@JsonIgnoreProperties(ignoreUnknown = true) -public class MasAnnotation { - // Maps to one of the values in the enum type @code{MasAnnotType} - @JsonProperty("annot_type") - private String annotType; - - // Refers to the location of the extracted @code{annotVal} text within the document - @JsonProperty("page_num") - private String pageNum; - - @JsonProperty("eFolderVersionRefId") - private String eFolderVersionRefId; - - @JsonProperty("dates") - private String dates; - - @JsonProperty("recDate") - private String recDate; - - @JsonProperty("docTypedescription") - private String docTypedescription; - - @JsonProperty("annot_name") - private String annotName; - - // Raw text extracted from the document - @JsonProperty("annot_val") - private String annotVal; - - @JsonProperty("spellcheck_val") - private String spellCheckVal; - - @JsonProperty("observation_date") - private String observationDate; - - // Beginning location of @code{annotVal} on @code{pageNum} - @JsonProperty("start") - private int start; - - // Ending location of @code{annotVal} on @code{pageNum} - @JsonProperty("end") - private int end; - - @JsonProperty("acd_pref_name") - private String acdPrefName; - - @JsonProperty("relevant") - private boolean relevant; - - @JsonProperty("partial_date") - private String partialDate; - - @JsonProperty("sorted_date") - private String sortedDate; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasAutomatedClaimPayload.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasAutomatedClaimPayload.java deleted file mode 100644 index dee3c28385..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasAutomatedClaimPayload.java +++ /dev/null @@ -1,165 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import gov.va.vro.model.rrd.event.Auditable; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; -import lombok.SneakyThrows; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; - -@Builder(toBuilder = true) -@Getter -public class MasAutomatedClaimPayload implements Auditable { - - public static final String BLOOD_PRESSURE_DIAGNOSTIC_CODE = "7101"; - public static final String DISABILITY_ACTION_TYPE_NEW = "NEW"; - public static final String DISABILITY_ACTION_TYPE_INCREASE = "INCREASE"; - public static final String AGENT_ORANGE_FLASH_ID = "266"; - public static final String CLAIM_V2_ID_TYPE = "mas-Form526Submission"; - - private String correlationId; - - @NotBlank(message = "Date of Birth cannot be empty") - private String dateOfBirth; - - @NotBlank(message = "First Name cannot be empty") - private String firstName; - - @NotBlank(message = "Last Name cannot be empty") - private String lastName; - - private String gender; - - @NotNull(message = "Collection ID cannot be empty") - private Integer collectionId; - - @NotNull @Valid private VeteranIdentifiers veteranIdentifiers; - - @NotNull @Valid private ClaimDetail claimDetail; - - @Builder.Default @NotNull private String idType = CLAIM_V2_ID_TYPE; - - @Setter private String offRampReason; - - @Setter private UUID evidenceSummaryDocumentId; - - private List veteranFlashIds; - - @JsonIgnore - public String getConditionName() { - if (claimDetail == null || claimDetail.getConditions() == null) { - return null; - } - return claimDetail.getConditions().getName(); - } - - @JsonIgnore - public String getDiagnosticCode() { - if (claimDetail == null || claimDetail.getConditions() == null) { - return null; - } - return claimDetail.getConditions().getDiagnosticCode(); - } - - @JsonIgnore - public String getDisabilityClassificationCode() { - if (claimDetail == null || claimDetail.getConditions() == null) { - return null; - } - return claimDetail.getConditions().getDisabilityClassificationCode(); - } - - @JsonIgnore - public String getDisabilityActionType() { - if (claimDetail == null || claimDetail.getConditions() == null) { - return null; - } - return claimDetail.getConditions().getDisabilityActionType(); - } - - /** - * Check if it is in scope. - * - * @return true or false. - */ - @JsonIgnore - public boolean isInScope() { - return Objects.equals(getDiagnosticCode(), BLOOD_PRESSURE_DIAGNOSTIC_CODE) - && (Objects.equals(getDisabilityActionType(), DISABILITY_ACTION_TYPE_NEW) - || Objects.equals(getDisabilityActionType(), DISABILITY_ACTION_TYPE_INCREASE)); - } - - @JsonIgnore - public Boolean isPresumptive() { - if (Objects.equals(getDisabilityActionType(), DISABILITY_ACTION_TYPE_NEW)) { - return (veteranFlashIds != null - && !Collections.disjoint( - veteranFlashIds, - Arrays.asList(MasVeteranFlashProps.getInstance().getAgentOrangeFlashIds()))); - } - return null; - } - - @JsonIgnore - public String getBenefitClaimId() { - return claimDetail == null ? null : claimDetail.getBenefitClaimId(); - } - - @JsonIgnore - public String getVeteranIcn() { - return veteranIdentifiers == null ? null : veteranIdentifiers.getIcn(); - } - - @JsonIgnore - public String getVeteranParticipantId() { - return veteranIdentifiers == null ? null : veteranIdentifiers.getParticipantId(); - } - - @JsonIgnore - @Override - public String getEventId() { - return correlationId; - } - - @Override - @SneakyThrows - @JsonIgnore - public Map getDetails() { - Map detailsMap = new HashMap<>(); - detailsMap.put("benefitClaimId", getBenefitClaimId()); - detailsMap.put("collectionId", Objects.toString(getCollectionId())); - detailsMap.put("conditionName", getConditionName()); - detailsMap.put("diagnosticCode", getDiagnosticCode()); - detailsMap.put("veteranIcn", getVeteranIcn()); - detailsMap.put("disabilityActionType", getDisabilityActionType()); - detailsMap.put("disabilityClassificationCode", getDisabilityClassificationCode()); - detailsMap.put( - "flashIds", getVeteranFlashIds() == null ? null : Objects.toString(getVeteranFlashIds())); - detailsMap.put("inScope", Objects.toString(isInScope())); - detailsMap.put("presumptive", Objects.toString(isPresumptive())); - detailsMap.put( - "submissionSource", claimDetail == null ? null : claimDetail.getClaimSubmissionSource()); - detailsMap.put( - "submissionDate", - claimDetail == null ? null : Objects.toString(claimDetail.getClaimSubmissionDateTime())); - detailsMap.put("offRampReason", getOffRampReason()); - return detailsMap; - } - - @JsonIgnore - @Override - public String getDisplayName() { - return "Automated Claim"; - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasCollectionAnnotation.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasCollectionAnnotation.java deleted file mode 100644 index 3132738ea0..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasCollectionAnnotation.java +++ /dev/null @@ -1,35 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.List; - -/** - * MAS collection annotation class. - * - * @author warren @Date 10/5/22 - */ -@NoArgsConstructor -@Getter -@Setter -@JsonIgnoreProperties(ignoreUnknown = true) -public class MasCollectionAnnotation { - @JsonProperty("collectionsId") - private int collectionsId; - - @JsonProperty("vtrnFileId") - private String veteranFileId; - - @JsonProperty("creationDate") - private String creationDate; - - @JsonProperty("documents") - private List documents; - - @JsonProperty("documentsWithoutAnnotationsChecked") - private List documentsWithoutAnnotationsChecked; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasCollectionStatus.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasCollectionStatus.java deleted file mode 100644 index df65847cff..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasCollectionStatus.java +++ /dev/null @@ -1,18 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -/** - * MAS collection status class. - * - * @author warren @Date 10/5/22 - */ -@Getter -@Setter -@NoArgsConstructor -public class MasCollectionStatus { - private int collectionsId; - private String collectionStatus; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasDocument.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasDocument.java deleted file mode 100644 index 0df105cf27..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasDocument.java +++ /dev/null @@ -1,36 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.List; - -/** - * MAS document class. - * - * @author warren @Date 10/5/22 - */ -@NoArgsConstructor -@Getter -@Setter -@JsonIgnoreProperties(ignoreUnknown = true) -public class MasDocument { - - @JsonProperty("docTypeDescription") - private String docTypeDescription; - - @JsonProperty("eFolderVersionRefId") - private String efolderversionrefid; - - @JsonProperty("recDate") - private String recDate; - - @JsonProperty("condition") - private String condition; - - @JsonProperty("annotations") - private List annotations; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasEventDetails.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasEventDetails.java deleted file mode 100644 index 32fd073dbf..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasEventDetails.java +++ /dev/null @@ -1,25 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import lombok.Builder; -import lombok.Getter; - -import java.util.List; - -@Builder -@Getter -public class MasEventDetails { - - private String benefitClaimId; - private String collectionId; - private String veteranIcn; - private String conditionName; - private String diagnosticCode; - private String offRampReason; - private String disabilityActionType; - private String disabilityClassificationCode; - private Boolean presumptive; - private boolean inScope; - private List flashIds; - private String submissionDate; - private String submissionSource; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasExamOrderStatusPayload.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasExamOrderStatusPayload.java deleted file mode 100644 index b193895083..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasExamOrderStatusPayload.java +++ /dev/null @@ -1,57 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import gov.va.vro.model.rrd.event.Auditable; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; - -import java.util.HashMap; -import java.util.Map; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; - -@Builder -@Getter -@Schema(name = "MASExamOrderingStatusRequest", description = "Initiate a MAS request") -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonIgnoreProperties(ignoreUnknown = true) -public class MasExamOrderStatusPayload implements Auditable { - - @JsonIgnore @Setter private String correlationId; - - @NotNull(message = "Collection ID is required") - @Schema(description = "Collection ID", example = "999") - private Integer collectionId; - - @NotBlank(message = "Collection Status is required") - @Schema(description = "Collection Status", example = "DRAFT") - private String collectionStatus; - - @Schema(description = "Exam order timestamp", example = "2018-11-04T17:45:59Z") - private String examOrderDateTime; - - @JsonIgnore - @Override - public String getEventId() { - return correlationId; - } - - @JsonIgnore - @Override - public Map getDetails() { - Map detailsMap = new HashMap<>(); - detailsMap.put("collectionId", Integer.toString(collectionId)); - detailsMap.put("collectionStatus", collectionStatus); - detailsMap.put("examOrderDateTime", examOrderDateTime); - return detailsMap; - } - - @Override - public String getDisplayName() { - return "Exam Order Status"; - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasOrderExam.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasOrderExam.java deleted file mode 100644 index bf66e69612..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasOrderExam.java +++ /dev/null @@ -1,21 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -/** - * MAS order exam class. - * - * @author warren @Date 10/11/22 - */ -@NoArgsConstructor -@Getter -@Setter -@JsonIgnoreProperties(ignoreUnknown = true) -public class MasOrderExam { - @JsonProperty("response") - private String response; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasOrderExamConditions.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasOrderExamConditions.java deleted file mode 100644 index e7fbc4a4db..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasOrderExamConditions.java +++ /dev/null @@ -1,24 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -/** - * MAS order exam conditions. - * - * @author warren @Date 10/11/22 - */ -@NoArgsConstructor -@Getter -@Setter -@JsonIgnoreProperties(ignoreUnknown = true) -public class MasOrderExamConditions { - @JsonProperty("contentionText") - private String contentionText; - - @JsonProperty("conditionCode") - private String conditionCode; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasStatus.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasStatus.java deleted file mode 100644 index 06bb3a3778..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasStatus.java +++ /dev/null @@ -1,54 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import java.util.HashMap; -import java.util.Map; - -/** - * MAS status class. - * - * @author warren @Date 10/12/22 - */ -public enum MasStatus { - INPROGRESS("inProgress"), - PROCESSED("processed"), - OFFRAMPED("offramped"), - VRONOTIFIED("vroNotified"), - UNKNOWN(""); - - private final String status; - - private static final Map lookup = new HashMap(); - - static { - for (MasStatus d : MasStatus.values()) { - lookup.put(d.getStatus(), d); - } - } - - public static MasStatus getMasStatus(String status) { - return lookup.get(status) == null ? UNKNOWN : lookup.get(status); - } - - MasStatus(String status) { - this.status = status; - } - - public String getStatus() { - return status; - } - - /** - * Gets MAS status. - * - * @param status status - * @return return. - */ - public static MasStatus getMasStatus1(String status) { - for (MasStatus s : MasStatus.values()) { - if (status.equals(s.getStatus())) { - return s; - } - } - return UNKNOWN; - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasVeteranFlashProps.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasVeteranFlashProps.java deleted file mode 100644 index 6386d5b5b3..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/MasVeteranFlashProps.java +++ /dev/null @@ -1,26 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import lombok.Getter; - -@Getter -public class MasVeteranFlashProps { - - private static MasVeteranFlashProps INSTANCE; - private String[] agentOrangeFlashIds = {}; - - private MasVeteranFlashProps(String[] agentOrangeFlashIds) { - this.agentOrangeFlashIds = agentOrangeFlashIds; - } - ; - - public static MasVeteranFlashProps getInstance(String[] agentOrangeFlashIds) { - if (INSTANCE == null) { - INSTANCE = new MasVeteranFlashProps(agentOrangeFlashIds); - } - return INSTANCE; - } - - public static MasVeteranFlashProps getInstance() { - return INSTANCE; - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/VeteranIdentifiers.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/VeteranIdentifiers.java deleted file mode 100644 index 9daf4929e9..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/VeteranIdentifiers.java +++ /dev/null @@ -1,33 +0,0 @@ -package gov.va.vro.model.rrd.mas; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Getter; -import lombok.Setter; - -import jakarta.validation.constraints.NotBlank; - -@Getter -@Setter -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonIgnoreProperties(ignoreUnknown = true) -public class VeteranIdentifiers { - - @NotBlank(message = "ICN is required") - @Schema(description = "Veteran ICN", example = "mock1012666073V986297") - private String icn; - - @Schema(description = "Social Security Number", example = "111-11-1111") - @NotBlank(message = "SSN is required") - private String ssn; - - @NotBlank(message = "Veteran File ID is required") - private String veteranFileId; - - @NotBlank(message = "EDIPN is required") - private String edipn; - - @NotBlank(message = "Participant ID is required") - private String participantId; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasAutomatedClaimRequest.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasAutomatedClaimRequest.java deleted file mode 100644 index 58051ba666..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasAutomatedClaimRequest.java +++ /dev/null @@ -1,62 +0,0 @@ -package gov.va.vro.model.rrd.mas.request; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import gov.va.vro.model.rrd.mas.ClaimDetail; -import gov.va.vro.model.rrd.mas.VeteranIdentifiers; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; - -import java.util.List; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; - -@Builder -@Getter -@Schema(name = "MASClaimDetailsRequest", description = "Initiate a MAS request") -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonIgnoreProperties(ignoreUnknown = true) -public class MasAutomatedClaimRequest { - - @Schema(hidden = true) - @Setter - @Getter - private String correlationId; - - @NotBlank(message = "Date of Birth cannot be empty") - @Schema(description = "Veteran Date of Birth", example = "1968-02-19") - @JsonProperty("dob") - private String dateOfBirth; - - @NotBlank(message = "First Name cannot be empty") - @Schema(description = "Veteran First Name", example = "David") - private String firstName; - - @NotBlank(message = "Last Name cannot be empty") - @Schema(description = "Veteran Last Name", example = "Skyscraper") - private String lastName; - - @Schema(description = "Veteran Gender") - private String gender; - - @NotNull(message = "Collection ID cannot be empty") - @Schema(description = "Collection ID", example = "376") - private Integer collectionId; - - @NotNull - @Valid - @Schema(description = "Veteran Identifiers") - private VeteranIdentifiers veteranIdentifiers; - - @NotNull - @Valid - @Schema(description = "Details of the Claim") - private ClaimDetail claimDetail; - - @Schema(description = "Veteran Flash Ids", example = "[\"Agent Orange Exposure Verified\"]") - private List veteranFlashIds; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasCollectionAnnotationRequest.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasCollectionAnnotationRequest.java deleted file mode 100644 index f8717edfcd..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasCollectionAnnotationRequest.java +++ /dev/null @@ -1,21 +0,0 @@ -package gov.va.vro.model.rrd.mas.request; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -/** - * MAS collection annotation request class. - * - * @author warren @Date 10/5/22 - */ -@NoArgsConstructor -@Getter -@Setter -@JsonIgnoreProperties(ignoreUnknown = true) -public class MasCollectionAnnotationRequest { - @JsonProperty("collectionsId") - private int collectionsId; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasCollectionStatusRequest.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasCollectionStatusRequest.java deleted file mode 100644 index a26bc1823b..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasCollectionStatusRequest.java +++ /dev/null @@ -1,16 +0,0 @@ -package gov.va.vro.model.rrd.mas.request; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -@JsonIgnoreProperties(ignoreUnknown = true) -public class MasCollectionStatusRequest { - @JsonProperty("collectionsId") - private int collectionsId; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasOrderExamRequest.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasOrderExamRequest.java deleted file mode 100644 index a585e88d1a..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/request/MasOrderExamRequest.java +++ /dev/null @@ -1,27 +0,0 @@ -package gov.va.vro.model.rrd.mas.request; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import gov.va.vro.model.rrd.mas.MasOrderExamConditions; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.List; - -/** - * MAS order exam request class. - * - * @author warren @Date 10/11/22 - */ -@NoArgsConstructor -@Getter -@Setter -@JsonIgnoreProperties(ignoreUnknown = true) -public class MasOrderExamRequest { - @JsonProperty("conditions") - private List conditions; - - @JsonProperty("collectionsId") - private Integer collectionsId; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/response/FetchPdfResponse.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/response/FetchPdfResponse.java deleted file mode 100644 index 0c682d71c1..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/response/FetchPdfResponse.java +++ /dev/null @@ -1,27 +0,0 @@ -package gov.va.vro.model.rrd.mas.response; - -import com.fasterxml.jackson.annotation.JsonInclude; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import jakarta.validation.constraints.NotBlank; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -@JsonInclude(JsonInclude.Include.NON_EMPTY) -public class FetchPdfResponse { - - @NotBlank private String claimSubmissionId; - private String status; - private String diagnosis; - private String pdfData; - private String reason; - - public boolean hasContent() { - return pdfData != null && pdfData.length() > 0; - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/response/GeneratePdfResponse.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/response/GeneratePdfResponse.java deleted file mode 100644 index e83a02c6ce..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/model/rrd/mas/response/GeneratePdfResponse.java +++ /dev/null @@ -1,17 +0,0 @@ -package gov.va.vro.model.rrd.mas.response; - -import com.fasterxml.jackson.annotation.JsonInclude; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import jakarta.validation.constraints.NotBlank; - -@Getter -@AllArgsConstructor -@JsonInclude(JsonInclude.Include.NON_EMPTY) -public class GeneratePdfResponse { - - @NotBlank private String claimSubmissionId; - private String status; - private String reason; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/audit/AuditEventService.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/audit/AuditEventService.java deleted file mode 100644 index b9101d1c74..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/audit/AuditEventService.java +++ /dev/null @@ -1,12 +0,0 @@ -package gov.va.vro.service.spi.audit; - -import gov.va.vro.model.rrd.event.AuditEvent; - -/** - * Service responsible for logging an audit event using some communication channel or persistence - * mechanism such as database, queue, slack channel, etc. - */ -public interface AuditEventService { - - void logEvent(AuditEvent auditEvent); -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/db/SaveToDbService.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/db/SaveToDbService.java deleted file mode 100644 index 4252cc8ffa..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/db/SaveToDbService.java +++ /dev/null @@ -1,32 +0,0 @@ -package gov.va.vro.service.spi.db; - -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.service.spi.model.Claim; -import gov.va.vro.service.spi.model.ExamOrder; -import gov.va.vro.service.spi.model.GeneratePdfPayload; - -import java.util.List; -import java.util.UUID; - -public interface SaveToDbService { - Claim insertClaim(Claim claim); - - void insertAssessmentResult(UUID claimId, AbdEvidenceWithSummary evidence, String diagnosticCode); - - void insertAssessmentResult(AbdEvidenceWithSummary evidence, String diagnosticCode); - - void insertEvidenceSummaryDocument(GeneratePdfPayload request, String documentName); - - void updateEvidenceSummaryDocument(UUID eFolderId, MasAutomatedClaimPayload payload); - - void insertOrUpdateExamOrderingStatus(ExamOrder examOrder); - - void insertFlashIds(List veteranFlashIds, String veteranIcn); - - void updateRfdFlag(String claimId, boolean rfdFlag); - - void setOffRampReason(Claim payload); - - void updateSufficientEvidenceFlag(AbdEvidenceWithSummary evidence, String diagnosticCode); -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/model/ClaimInfoData.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/model/ClaimInfoData.java deleted file mode 100644 index 8af89f04d9..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/model/ClaimInfoData.java +++ /dev/null @@ -1,28 +0,0 @@ -package gov.va.vro.service.spi.model; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; - -import java.util.List; -import java.util.Map; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -@Builder -@ToString(includeFieldNames = true) -public class ClaimInfoData { - String claimSubmissionId; - String veteranIcn; - int contentionsCount; - int assessmentResultsCount; - int evidenceSummaryDocumentsCount; - List contentions; - Map evidenceSummary; - String errorMessage; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/model/ExamOrder.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/model/ExamOrder.java deleted file mode 100644 index 6d8aa6f567..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/model/ExamOrder.java +++ /dev/null @@ -1,30 +0,0 @@ -package gov.va.vro.service.spi.model; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; - -import java.time.OffsetDateTime; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor(onConstructor_ = {@JsonIgnore}) -@EqualsAndHashCode -@Builder -@ToString -public class ExamOrder { - - private String collectionId; - - private String idType; - - private String status; - - private OffsetDateTime examOrderDateTime; -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/model/GeneratePdfPayload.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/model/GeneratePdfPayload.java deleted file mode 100644 index 82a0690dc9..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/model/GeneratePdfPayload.java +++ /dev/null @@ -1,57 +0,0 @@ -package gov.va.vro.service.spi.model; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.ServiceLocation; -import gov.va.vro.model.rrd.VeteranInfo; -import gov.va.vro.model.rrd.mas.ClaimCondition; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import lombok.Setter; - -import java.util.Date; -import java.util.List; -import jakarta.validation.constraints.NotNull; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode -@Builder -public class GeneratePdfPayload { - @NonNull private String claimSubmissionId; - - @Builder.Default @NotNull private String idType = Claim.V1_ID_TYPE; - - @NonNull private String diagnosticCode; - - @JsonProperty("veteranInfo") - private VeteranInfo veteranInfo; - - @JsonProperty("serviceLocations") - private List serviceLocations; - - @NotNull private ClaimCondition conditions; - - @JsonProperty("evidence") - private AbdEvidence evidence; - - private String status; - private String reason; - - private String pdfTemplate; - - private String veteranFileId; - - @JsonIgnore - public static String createPdfFilename(String diagnosis) { - String timestamp = String.format("%1$tY%1$tm%1$td", new Date()); - return String.format("VAMC_%s_Rapid_Decision_Evidence--%s.pdf", diagnosis, timestamp); - } -} diff --git a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/services/ClaimMetricsService.java b/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/services/ClaimMetricsService.java deleted file mode 100644 index 1947674e21..0000000000 --- a/domain-rrd/rrd-shared/src/main/java/gov/va/vro/service/spi/services/ClaimMetricsService.java +++ /dev/null @@ -1,20 +0,0 @@ -package gov.va.vro.service.spi.services; - -import gov.va.vro.model.rrd.claimmetrics.ClaimInfoQueryParams; -import gov.va.vro.model.rrd.claimmetrics.ClaimsInfo; -import gov.va.vro.model.rrd.claimmetrics.ExamOrderInfoQueryParams; -import gov.va.vro.model.rrd.claimmetrics.ExamOrdersInfo; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimInfoResponse; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimMetricsResponse; - -public interface ClaimMetricsService { - ClaimMetricsResponse getClaimMetrics(); - - ClaimInfoResponse findClaimInfo(String claimSubmissionId, String idType); - - ClaimsInfo findAllClaimInfo(ClaimInfoQueryParams params); - - ExamOrdersInfo findExamOrderInfo(ExamOrderInfoQueryParams params); - - ExamOrdersInfo findExamOrderInfoOlderThan24(ExamOrderInfoQueryParams params); -} diff --git a/domain-rrd/rrd-workflows/build.gradle.bak b/domain-rrd/rrd-workflows/build.gradle.bak deleted file mode 100644 index 25aae1fb34..0000000000 --- a/domain-rrd/rrd-workflows/build.gradle.bak +++ /dev/null @@ -1,45 +0,0 @@ -plugins { - id 'local.std.java.library-spring-conventions' -} - -dependencies { - implementation project(':domain-rrd:rrd-shared') - implementation project(':persistence:model') - api project(':shared:lib-camel-connector') - - implementation 'org.apache.commons:commons-lang3:3.12.0' - implementation 'com.google.guava:guava:31.1-jre' - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - - // Apache Camel - implementation "org.apache.camel.springboot:camel-spring-boot-starter:${camel_version}" - implementation "org.apache.camel.springboot:camel-jms-starter:${camel_version}" - implementation "org.apache.camel.springboot:camel-jackson-starter:${camel_version}" - implementation "org.apache.camel.springboot:camel-slack-starter:${camel_version}" - - // Redis - implementation "org.springframework.boot:spring-boot-starter-data-redis" - implementation "org.apache.camel.springboot:camel-spring-redis-starter:${camel_version}" - implementation "org.apache.camel.springboot:camel-jsonpath-starter:${camel_version}" - - // Needed? - // implementation "org.apache.camel.springboot:camel-rabbitmq-starter:${camel_version}" - // implementation "org.apache.camel.springboot:camel-jackson-starter:${camel_version}" - // implementation "org.apache.camel.springboot:camel-servlet-starter:${camel_version}" - // implementation "org.apache.camel.springboot:camel-swagger-java-starter:${camel_version}" - - //MAS oAuth2 webclient libs - implementation "org.springframework.boot:spring-boot-starter-webflux:${sb_webflux}" - implementation "org.springframework.security:spring-security-oauth2-client:${spring_security_version}" - implementation "org.springframework.boot:spring-boot-starter-security:${sb_security}" - - implementation 'io.jsonwebtoken:jjwt:0.2' - //testImplementation 'io.jsonwebtoken:jjwt:0.2' - - testImplementation "org.apache.camel:camel-test-junit5:${camel_version}" -} - -ext { - // TODO: improve test code coverage so that the following can be removed - jacoco_minimum_coverage = 0.09 -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/BipApiProps.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/BipApiProps.java deleted file mode 100644 index e67706c134..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/BipApiProps.java +++ /dev/null @@ -1,60 +0,0 @@ -package gov.va.vro.service.provider; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import lombok.Getter; -import lombok.Setter; -import org.springframework.boot.context.properties.ConfigurationProperties; - -import java.util.Calendar; -import java.util.Date; - -/** - * Properties used in BIP API services. - * - * @author warren @Date 10/31/22 - */ -@Getter -@Setter -@ConfigurationProperties(prefix = "bip") -public class BipApiProps { - - private String claimBaseUrl; - - private String claimSecret; - - private String claimClientId; - - private String claimIssuer; - - private String evidenceBaseUrl; - - private String evidenceSecret; - - private String evidenceClientId; - - private String evidenceIssuer; - - private String stationId; - - private String applicationId; - - /** - * Creates common Jwt claims. - * - * @return Claims - */ - public Claims toCommonJwtClaims() { - Calendar cal = Calendar.getInstance(); - cal.add(Calendar.MINUTE, 30); - Date expired = cal.getTime(); - Claims claims = Jwts.claims(); - claims.put("applicationID", applicationId); - claims.put("stationID", stationId); - claims.put("userID", claimClientId); - Date now = cal.getTime(); - claims.put("iat", now.getTime()); - claims.put("expires", expired.getTime()); - return claims; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/CamelEntrance.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/CamelEntrance.java deleted file mode 100644 index 39c3a331c4..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/CamelEntrance.java +++ /dev/null @@ -1,109 +0,0 @@ -package gov.va.vro.service.provider; - -import gov.va.vro.model.rrd.event.AuditEvent; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.MasExamOrderStatusPayload; -import gov.va.vro.service.provider.camel.MasIntegrationRoutes; -import gov.va.vro.service.provider.camel.PrimaryRoutes; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import gov.va.vro.service.spi.model.Claim; -import gov.va.vro.service.spi.model.GeneratePdfPayload; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.ProducerTemplate; -import org.springframework.stereotype.Service; - -import java.util.Map; - -/** - * Used to programmatically inject messages into a Camel endpoint. AKA an entrance ramp onto a Camel - * route. Intended to be used by Controller classes to initiate routing requests. - */ -@Service -@Slf4j -@RequiredArgsConstructor -public class CamelEntrance { - - private final ProducerTemplate producerTemplate; - - public String submitClaimFull(Claim claim) { - return producerTemplate.requestBody( - PrimaryRoutes.ENDPOINT_SUBMIT_CLAIM_FULL, claim, String.class); - } - - public String generatePdf(GeneratePdfPayload resource) { - return producerTemplate.requestBody( - PrimaryRoutes.ENDPOINT_GENERATE_PDF, resource, String.class); - } - - public String fetchPdf(String claimSubmissionId) { - return producerTemplate.requestBody( - PrimaryRoutes.ENDPOINT_FETCH_PDF, claimSubmissionId, String.class); - } - - public String immediatePdf(GeneratePdfPayload resource) { - return producerTemplate.requestBody( - PrimaryRoutes.ENDPOINT_GENERATE_FETCH_PDF, resource, String.class); - } - - /** - * Notify automated claim. - * - * @param payload mas payload - * @param delay delay time - * @param retryCount amount of retries - */ - public void notifyAutomatedClaim(MasAutomatedClaimPayload payload, long delay, int retryCount) { - log.info( - "Notify automated claim for claim ID: {}, collection ID: {}, icn: {}", - payload.getBenefitClaimId(), - payload.getCollectionId(), - payload.getVeteranIcn()); - producerTemplate.sendBodyAndHeaders( - MasIntegrationRoutes.ENDPOINT_AUTOMATED_CLAIM, - payload, - Map.of( - MasIntegrationRoutes.MAS_DELAY_PARAM, - delay, - MasIntegrationRoutes.MAS_RETRY_PARAM, - retryCount)); - } - - public void examOrderingStatus(MasExamOrderStatusPayload payload) { - producerTemplate.requestBody(MasIntegrationRoutes.ENDPOINT_EXAM_ORDER_STATUS, payload); - } - - /** - * Main entry point for processing an automated MAS claim - * - * @param masAutomatedClaimPayload the original payload - */ - public MasProcessingObject processClaim(MasAutomatedClaimPayload masAutomatedClaimPayload) { - return producerTemplate.requestBody( - MasIntegrationRoutes.ENDPOINT_MAS_PROCESSING, - masAutomatedClaimPayload, - MasProcessingObject.class); - } - - /** - * Last processing step for a MAS claim whether it has been accepted or off-ramped - * - * @param masProcessingObject the complete processing object - */ - public void completeProcessing(MasProcessingObject masProcessingObject) { - producerTemplate.requestBody(MasIntegrationRoutes.ENDPOINT_MAS_COMPLETE, masProcessingObject); - } - - /** - * Send appropriate notifications when a claim is off-ramped - * - * @param auditEvent the event to broadcast - */ - public void offrampClaim(AuditEvent auditEvent) { - producerTemplate.sendBody(MasIntegrationRoutes.ENDPOINT_NOTIFY_AUDIT, auditEvent); - } - - public void examOrderSlack(AuditEvent message) { - producerTemplate.sendBody(MasIntegrationRoutes.ENDPOINT_EXAM_ORDER_SLACK, message); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/ClaimProps.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/ClaimProps.java deleted file mode 100644 index 17ab726509..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/ClaimProps.java +++ /dev/null @@ -1,14 +0,0 @@ -package gov.va.vro.service.provider; - -import lombok.Getter; -import lombok.Setter; -import org.springframework.boot.context.properties.ConfigurationProperties; - -/** @author warren @Date 2/7/23 */ -@Getter -@Setter -@ConfigurationProperties(prefix = "claim") -public class ClaimProps { - private String specialIssue1; - private String specialIssue2; -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/EntityNotFoundException.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/EntityNotFoundException.java deleted file mode 100644 index b1d8103235..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/EntityNotFoundException.java +++ /dev/null @@ -1,7 +0,0 @@ -package gov.va.vro.service.provider; - -public class EntityNotFoundException extends RuntimeException { - public EntityNotFoundException(String entityType, Object id) { - super("Could not find " + entityType + " with id: " + id); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/ExternalCallException.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/ExternalCallException.java deleted file mode 100644 index 9e889046e0..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/ExternalCallException.java +++ /dev/null @@ -1,12 +0,0 @@ -package gov.va.vro.service.provider; - -public class ExternalCallException extends RuntimeException { - - public ExternalCallException(String message, Throwable cause) { - super(message, cause); - } - - public ExternalCallException(String message) { - super(message); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/MasApiProps.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/MasApiProps.java deleted file mode 100644 index 349ba2e66c..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/MasApiProps.java +++ /dev/null @@ -1,14 +0,0 @@ -package gov.va.vro.service.provider; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Getter -public class MasApiProps { - - private final String baseUrl; - private final String collectionStatusPath; - private final String collectionAnnotsPath; - private final String createExamOrderPath; -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/MasConfig.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/MasConfig.java deleted file mode 100644 index f7bfc6dfe5..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/MasConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package gov.va.vro.service.provider; - -import lombok.Builder; -import lombok.Getter; - -@Builder -@Getter -public class MasConfig { - - private long masProcessingInitialDelay; - - private long masProcessingSubsequentDelay; - - private int masRetryCount; - - private String slackExceptionChannel; - - private String slackExceptionWebhook; -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/RedisConnectionConfig.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/RedisConnectionConfig.java deleted file mode 100644 index 43f3faa972..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/RedisConnectionConfig.java +++ /dev/null @@ -1,38 +0,0 @@ -package gov.va.vro.service.provider; - -import lombok.RequiredArgsConstructor; -import org.springframework.boot.autoconfigure.data.redis.RedisProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisStandaloneConfiguration; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -@Configuration -@RequiredArgsConstructor -class RedisConnectionConfig { - - // Loads properties spring.redis.* - final RedisProperties redisProperties; - - @Bean - LettuceConnectionFactory lettuceConnectionFactory() { - RedisStandaloneConfiguration config = - new RedisStandaloneConfiguration(redisProperties.getHost(), redisProperties.getPort()); - config.setDatabase(redisProperties.getDatabase()); - config.setUsername(redisProperties.getUsername()); - config.setPassword(redisProperties.getPassword()); - return new LettuceConnectionFactory(config); - } - - // https://stackoverflow.com/questions/37402717/camel-redis-automatically-prepends-string-to-key - // https://dzone.com/articles/using-redis-spring - @Bean - RedisTemplate redisTemplate() { - RedisTemplate template = new RedisTemplate<>(); - template.setConnectionFactory(lettuceConnectionFactory()); - template.setDefaultSerializer(new StringRedisSerializer()); - return template; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/ServiceProviderConfig.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/ServiceProviderConfig.java deleted file mode 100644 index 9b56b3b16a..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/ServiceProviderConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package gov.va.vro.service.provider; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -@Configuration -public class ServiceProviderConfig { - - @Value("${vro.env:test}") - public String vroEnv; - - // Default to false for unit tests - @Value("${vro.persist.tracking.enabled:false}") - public boolean persistTrackingEnabled; - - @Value("${vro.persist.tracking.base_folder}") - @NotNull - @NotBlank - public String baseTrackingFolder; -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsApiClient.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsApiClient.java deleted file mode 100644 index 258ec8812a..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsApiClient.java +++ /dev/null @@ -1,90 +0,0 @@ -package gov.va.vro.service.provider.bgs.service; - -import static gov.va.vro.service.provider.bgs.service.BgsClaimNotes.OFFRAMP_ERROR_2_CLAIM_NOTE; -import static gov.va.vro.service.provider.bgs.service.BgsVeteranNote.getArsdUploadedNote; - -import gov.va.vro.model.rrd.bgs.BgsApiClientRequest; -import gov.va.vro.persistence.model.EvidenceSummaryDocumentEntity; -import gov.va.vro.persistence.repository.EvidenceSummaryDocumentRepository; -import gov.va.vro.service.provider.EntityNotFoundException; -import gov.va.vro.service.provider.mas.MasCompletionStatus; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.jetbrains.annotations.NotNull; -import org.springframework.stereotype.Component; - -import java.time.OffsetDateTime; -import java.util.Arrays; -import java.util.Optional; -import java.util.UUID; - -@Component -@RequiredArgsConstructor -@Slf4j -public class BgsApiClient { - private final EvidenceSummaryDocumentRepository esDocRepository; - - private int retryDelayBaseMills = 130_000; - - // https://github.com/department-of-veterans-affairs/abd-vro/issues/1341 - public BgsNotesCamelBody buildRequests(MasProcessingObject mpo) { - BgsNotesCamelBody body = new BgsNotesCamelBody(mpo, retryDelayBaseMills); - MasCompletionStatus completionStatus = MasCompletionStatus.of(mpo); - switch (completionStatus) { - case READY_FOR_DECISION: - // Tested with VroV2Tests.testAutomatedClaimFullPositiveIncrease - log.info("Create BGS notes for RFD"); - body.pendingRequests.add(buildVeteranNoteRequest(mpo)); - body.pendingRequests.add( - buildClaimNotesRequest(mpo, BgsClaimNotes.RFD_NOTE, BgsClaimNotes.ARSD_COMPLETED_NOTE)); - break; - case EXAM_ORDER: - // Tested with VroV2Tests.testAutomatedClaimOrderExamNewClaim - log.info("Create BGS notes for EXAM_ORDER"); - body.pendingRequests.add(buildVeteranNoteRequest(mpo)); - body.pendingRequests.add(buildClaimNotesRequest(mpo, BgsClaimNotes.EXAM_REQUESTED_NOTE)); - break; - case OFF_RAMP: - // Tested with VroV2Tests.testAutomatedClaimSufficiencyIsNull, - // which only covers SUFFICIENCY_UNDETERMINED - var offRampReasonCode = mpo.getOffRampReason(); - log.info("Create BGS notes for offRampReasonCode=" + offRampReasonCode); - String claimNote = OFFRAMP_ERROR_2_CLAIM_NOTE.getOrDefault(offRampReasonCode, null); - if (claimNote != null) body.pendingRequests.add(buildClaimNotesRequest(mpo, claimNote)); - break; - } - return body; - } - - private BgsApiClientRequest buildVeteranNoteRequest(MasProcessingObject mpo) { - String veteranId = mpo.getClaimPayload().getVeteranParticipantId(); - var request = new BgsApiClientRequest(mpo.getBenefitClaimId(), veteranId); - request.veteranNote = getArsdUploadedNote(getDocUploadedAt(mpo)); - return request; - } - - private BgsApiClientRequest buildClaimNotesRequest( - MasProcessingObject mpo, String... claimsNotes) { - var request = new BgsApiClientRequest(mpo.getBenefitClaimId(), null); - request.claimNotes.addAll(Arrays.asList(claimsNotes)); - return request; - } - - private OffsetDateTime getDocUploadedAt(MasProcessingObject mpo) { - var doc = - getEvidenceSummaryDocumentEntity(mpo.getClaimPayload().getEvidenceSummaryDocumentId()); - OffsetDateTime docUploadedAt = doc.getUploadedAt(); - return docUploadedAt; - } - - @NotNull - private EvidenceSummaryDocumentEntity getEvidenceSummaryDocumentEntity(UUID uuid) { - Optional foundDoc = esDocRepository.findById(uuid); - if (foundDoc.isEmpty()) { - log.error("Could not find EvidenceSummaryDocumentEntity with uuid {}.", uuid); - throw new EntityNotFoundException("EvidenceSummaryDocumentEntity", uuid); - } - return foundDoc.get(); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsClaimNotes.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsClaimNotes.java deleted file mode 100644 index 920b91b33d..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsClaimNotes.java +++ /dev/null @@ -1,40 +0,0 @@ -package gov.va.vro.service.provider.bgs.service; - -import gov.va.vro.model.rrd.event.EventReason; - -import java.util.Map; - -class BgsClaimNotes { - - static final String RFD_NOTE = "Claim status updated to RFD via automation"; - - static final String ARSD_COMPLETED_NOTE = - "Please note, the automated review summary document (ARSD) has been completed in full. " - + "One or more contentions were determined to be RFD by current rating criteria. " - + "Necessary exams were requested or drafted."; - - static final String EXAM_REQUESTED_NOTE = - "Please note, the automated review summary document has been completed in full with the " - + "necessary exam(s) requested or drafted based on automation eligible contention(s). " - + "This claim/contention has been placed in the Open Status Development Life Cycle for " - + "further review by a claims processor."; - - static final String CANT_CONFIRM_PRESUMPTIVE_NOTE = - "Automation-eligible contentions reviewed, but no action taken based on existing evidence. " - + "This claim has been removed from the automation program and placed in Open status for " - + "development by a claims processor."; - static final String ARSD_NOT_UPLOADED_NOTE = - "Claim was offramped from VBA automation platform when ARSD could not be uploaded to eFolder."; - - static final Map OFFRAMP_ERROR_2_CLAIM_NOTE = - Map.of( - // aka newClaimMissingFlash266 - EventReason.NEW_NOT_PRESUMPTIVE.getCode(), - CANT_CONFIRM_PRESUMPTIVE_NOTE, - // aka insufficientHealthDataToOrderExam - EventReason.SUFFICIENCY_UNDETERMINED.getCode(), - CANT_CONFIRM_PRESUMPTIVE_NOTE, - // aka docUploadFailed - EventReason.PDF_UPLOAD_FAILED_AFTER_ORDER_EXAM.getCode(), - ARSD_NOT_UPLOADED_NOTE); -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsNotesCamelBody.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsNotesCamelBody.java deleted file mode 100644 index 17e1f0fb57..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsNotesCamelBody.java +++ /dev/null @@ -1,58 +0,0 @@ -package gov.va.vro.service.provider.bgs.service; - -import gov.va.vro.model.rrd.bgs.BgsApiClientRequest; -import gov.va.vro.model.rrd.bgs.BgsApiClientResponse; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import lombok.Data; -import lombok.RequiredArgsConstructor; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.concurrent.atomic.AtomicInteger; - -@Data -@RequiredArgsConstructor -public class BgsNotesCamelBody { - public final MasProcessingObject mpo; - - public AtomicInteger tryCount = new AtomicInteger(1); - - /* - From BGS team: The transaction time out configured on our internal domain is 120 seconds. So, I - would recommend that reasonable interval between retires should be at least 120 seconds for - transient faults to avoid any collusion (maybe use exponential back-off for retry if - transaction is carried out in an automated fashion). I guess limit the number of retries to - about 3 to 5 if the operation is part of user interaction on your side. - */ - public final int delayBaseMillis; - public int delayMillis; - - public BgsNotesCamelBody incrementTryCount() { - // Use exponential backoff for retries. The random term helps to avoid cases where many clients - // are synchronized by some situation and all retry at once. - delayMillis = - delayBaseMillis * ((int) Math.pow(2, tryCount.get() - 1)) + new Random().nextInt(2000); - tryCount.incrementAndGet(); - return this; - } - - // Since there are potentially several notes, we have to split up requests - public List pendingRequests = new ArrayList<>(); - - public BgsApiClientRequest currentRequest() { - request = pendingRequests.get(0); - response = null; - return request; - } - - // Called after successful request or done retrying - public void removePendingRequest(BgsApiClientRequest request) { - pendingRequests.remove(request); - tryCount.set(1); - } - - // current request and response objects - public BgsApiClientRequest request; - public BgsApiClientResponse response; -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsVeteranNote.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsVeteranNote.java deleted file mode 100644 index c75586fce0..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bgs/service/BgsVeteranNote.java +++ /dev/null @@ -1,17 +0,0 @@ -package gov.va.vro.service.provider.bgs.service; - -import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; - -class BgsVeteranNote { - - private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); - // The date should be in MM/DD/YYYY format - private static final String ARSD_UPLOADED_NOTE = - "Hypertension automated review summary document uploaded %s"; - - static String getArsdUploadedNote(OffsetDateTime docUploadedAt) { - String dateString = docUploadedAt.format(formatter); - return String.format(ARSD_UPLOADED_NOTE, dateString); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/BipException.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/BipException.java deleted file mode 100644 index e8029a9355..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/BipException.java +++ /dev/null @@ -1,30 +0,0 @@ -package gov.va.vro.service.provider.bip; - -import lombok.Getter; -import lombok.Setter; -import org.springframework.http.HttpStatus; - -/** - * Custom Bip Exception. - * - * @author warren date 10/31/22 - */ -@Getter -@Setter -public class BipException extends RuntimeException { - - private HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; - - public BipException(String message) { - super(message); - } - - public BipException(String message, Throwable cause) { - super(message, cause); - } - - public BipException(HttpStatus status, String message) { - super(message); - this.status = status; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipApiService.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipApiService.java deleted file mode 100644 index b591cb726f..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipApiService.java +++ /dev/null @@ -1,215 +0,0 @@ -package gov.va.vro.service.provider.bip.service; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.service.provider.BipApiProps; -import gov.va.vro.service.provider.bip.BipException; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Header; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; -import org.springframework.web.client.HttpStatusCodeException; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; - -import javax.crypto.spec.SecretKeySpec; -import java.nio.charset.StandardCharsets; -import java.security.Key; - -/** - * BIP claim API service. - * - * @author warren @Date 10/31/22 - */ -@Service -@RequiredArgsConstructor -@Slf4j -public class BipApiService implements IBipApiService { - private static final String CLAIM_DETAILS = "/claims/%s"; - private static final String UPDATE_CLAIM_STATUS = "/claims/%s/lifecycle_status"; - private static final String CONTENTION = "/claims/%s/contentions"; - private static final String SPECIAL_ISSUE_TYPES = "/contentions/special_issue_types"; - - @Qualifier("bipCERestTemplate") - @NonNull - private final RestTemplate restTemplate; - - private final BipApiProps bipApiProps; - - private final ObjectMapper mapper = new ObjectMapper(); - - @Override - public BipClaim getClaimDetails(long claimId) throws BipException { - try { - String url = bipApiProps.getClaimRequestUrl(String.format(CLAIM_DETAILS, claimId)); - log.info("call {} to get claim info.", url); - HttpHeaders headers = getBipHeader(); - HttpEntity> httpEntity = new HttpEntity<>(headers); - ResponseEntity bipResponse = - restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); - if (bipResponse.getStatusCode() == HttpStatus.OK) { - BipClaimResp result = mapper.readValue(bipResponse.getBody(), BipClaimResp.class); - return result.getClaim(); - } else { - log.error( - "Failed to get claim details for {}. {} \n{}", - claimId, - bipResponse.getStatusCode(), - bipResponse.getBody()); - throw new BipException(bipResponse.getStatusCode(), bipResponse.getBody()); - } - } catch (JsonProcessingException e) { - log.error("json processing error", e); - throw new BipException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); - } catch (HttpStatusCodeException e) { - String message = "Failed to get claim info for claim ID " + claimId; - log.error(message, e); - if (e.getStatusCode() == HttpStatus.NOT_FOUND) { - throw new BipException(HttpStatus.BAD_REQUEST, message); - } else { - throw new BipException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); - } - } catch (RestClientException e) { - log.error("failed to update status to {} for claim {}.", claimId, e); - throw new BipException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); - } - } - - /** - * Updates claim status. - * - * @param claimId claim ID for the claim to be updated. - * @return an object with status and message. - * @throws BipException error occurs - */ - @Override - public BipUpdateClaimResp setClaimToRfdStatus(long claimId) throws BipException { - return updateClaimStatus(claimId, ClaimStatus.RFD); - } - - @Override - public BipUpdateClaimResp updateClaimStatus(long claimId, ClaimStatus status) - throws BipException { - final String description = status.getDescription(); - try { - String url = bipApiProps.getClaimRequestUrl(String.format(UPDATE_CLAIM_STATUS, claimId)); - log.info("call {} to update claim status to {}.", url, description); - - HttpHeaders headers = getBipHeader(); - Map requestBody = new HashMap<>(); - requestBody.put("claimLifecycleStatus", description); - HttpEntity> httpEntity = new HttpEntity<>(requestBody, headers); - ResponseEntity bipResponse = - restTemplate.exchange(url, HttpMethod.PUT, httpEntity, String.class); - if (bipResponse.getStatusCode() == HttpStatus.OK) { - return new BipUpdateClaimResp(HttpStatus.OK, bipResponse.getBody()); - } else { - throw new BipException(bipResponse.getStatusCode(), bipResponse.getBody()); - } - } catch (RestClientException e) { - log.error("failed to update status to {} for claim {}.", description, claimId, e); - throw new BipException(e.getMessage(), e); - } - } - - @Override - public List getClaimContentions(long claimId) throws BipException { - try { - String url = bipApiProps.getClaimRequestUrl(String.format(CONTENTION, claimId)); - log.info("Call {} to get claim contention for {}.", url, claimId); - HttpHeaders headers = getBipHeader(); - HttpEntity> httpEntity = new HttpEntity<>(headers); - ResponseEntity bipResponse = - restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); - if (HttpStatus.OK == bipResponse.getStatusCode()) { - BipContentionResp resp = mapper.readValue(bipResponse.getBody(), BipContentionResp.class); - return resp.getContentions(); - } else if (HttpStatus.NO_CONTENT == bipResponse.getStatusCode()) { - return new ArrayList<>(); - } else { - log.error( - "getClaimContentions returned {} for {}. {}", - bipResponse.getStatusCode(), - claimId, - bipResponse.getBody()); - throw new BipException(bipResponse.getStatusCode(), bipResponse.getBody()); - } - } catch (RestClientException | JsonProcessingException e) { - log.error("failed to getClaimContentions for claim {}.", claimId, e); - throw new BipException(e.getMessage(), e); - } - } - - @Override - public BipUpdateClaimResp updateClaimContention(long claimId, UpdateContentionReq contention) - throws BipException { - try { - String url = bipApiProps.getClaimRequestUrl(String.format(CONTENTION, claimId)); - log.info("Call {} to update contention for {}.", url, claimId); - HttpHeaders headers = getBipHeader(); - String updtContention = mapper.writeValueAsString(contention); - HttpEntity httpEntity = new HttpEntity<>(updtContention, headers); - ResponseEntity bipResponse = - restTemplate.exchange(url, HttpMethod.PUT, httpEntity, String.class); - if (bipResponse.getStatusCode() == HttpStatus.OK) { - return new BipUpdateClaimResp(HttpStatus.OK, bipResponse.getBody()); - } else { - throw new BipException(bipResponse.getStatusCode(), bipResponse.getBody()); - } - } catch (RestClientException | JsonProcessingException e) { - log.error("failed to getClaimContentions for claim {}.", claimId, e); - throw new BipException(e.getMessage(), e); - } - } - - @Override - public boolean verifySpecialIssueTypes() { - String url = bipApiProps.getClaimRequestUrl(SPECIAL_ISSUE_TYPES); - log.info("Call {} to get special_issue_types", url); - - HttpHeaders headers = getBipHeader(); - HttpEntity httpEntity = new HttpEntity<>(headers); - - ResponseEntity response = - restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); - - return response.getStatusCode() == HttpStatus.OK && !response.getBody().isEmpty(); - } - - private HttpHeaders getBipHeader() throws BipException { - try { - HttpHeaders bipHttpHeaders = new HttpHeaders(); - bipHttpHeaders.setContentType(MediaType.APPLICATION_JSON); - - String jwt = createJwt(); - bipHttpHeaders.add("Authorization", "Bearer " + jwt); - return bipHttpHeaders; - } catch (Exception e) { - log.error("Failed to build BIP HTTP Headers.", e); - throw new BipException(e.getMessage(), e); - } - } - - private String createJwt() throws BipException { - Claims claims = bipApiProps.toCommonJwtClaims(); - Map headerType = new HashMap<>(); - headerType.put("typ", Header.JWT_TYPE); - - claims.put("iss", bipApiProps.getClaimIssuer()); - byte[] signSecretBytes = bipApiProps.getClaimSecret().getBytes(StandardCharsets.UTF_8); - Key signingKey = new SecretKeySpec(signSecretBytes, SignatureAlgorithm.HS256.getJcaName()); - return Jwts.builder() - .setSubject("Claim") - .setIssuedAt(Calendar.getInstance().getTime()) - .setExpiration(claims.getExpiration()) - .setClaims(claims) - .signWith(SignatureAlgorithm.HS256, signingKey) - .setHeaderParams(headerType) - .compact(); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipCeApiService.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipCeApiService.java deleted file mode 100644 index e7ba9c1e69..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipCeApiService.java +++ /dev/null @@ -1,162 +0,0 @@ -package gov.va.vro.service.provider.bip.service; - -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.model.rrd.bip.FileIdType; -import gov.va.vro.model.rrd.bipevidence.BipFileUploadPayload; -import gov.va.vro.model.rrd.bipevidence.BipFileUploadResp; -import gov.va.vro.model.rrd.bipevidence.response.UploadResponse; -import gov.va.vro.service.provider.BipApiProps; -import gov.va.vro.service.provider.bip.BipException; -import gov.va.vro.service.spi.db.SaveToDbService; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Header; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Calendar; -import java.util.HashMap; -import java.util.Map; -import javax.crypto.spec.SecretKeySpec; - -/** - * BIP claim API service. - * - * @author warren @Date 10/31/22 - */ -@Service -@RequiredArgsConstructor -@Slf4j -public class BipCeApiService implements IBipCeApiService { - private static final String X_FOLDER_URI = "VETERAN:%s:%s"; - private static final String HTTPS = "https://"; - - private static final String UPLOAD_FILE = "/files"; - private static final String DOCUMENT_TYPES = "/documenttypes"; - - @Qualifier("bipCERestTemplate") - @NonNull - private final RestTemplate ceRestTemplate; - - private final BipApiProps bipApiProps; - - private final SaveToDbService saveToDbService; - - private final ObjectMapper mapper = new ObjectMapper(); - - @Override - public BipFileUploadResp uploadEvidenceFile( - FileIdType idtype, - String fileId, - BipFileUploadPayload payload, - byte[] fileContent, - String diagnosticCode) - throws BipException { - try { - String url = HTTPS + bipApiProps.getEvidenceBaseUrl() + UPLOAD_FILE; - log.info("Call {} to uploadEvidenceFile for {}", url, idtype.name()); - - HttpHeaders headers = getBipHeader(MediaType.MULTIPART_FORM_DATA); - String headerFolderUri = String.format(X_FOLDER_URI, idtype.name(), fileId); - headers.set("X-Folder-URI", headerFolderUri); - - String filename = payload.getContentName(); - MultiValueMap body = new LinkedMultiValueMap<>(); - body.add("payload", mapper.writeValueAsString(payload)); - - ByteArrayResource contentsAsResource = - new ByteArrayResource(fileContent) { - @Override - public String getFilename() { - return filename; // Filename has to be returned in order to be able to post. - } - }; - - body.add("file", contentsAsResource); - HttpEntity> httpEntity = new HttpEntity<>(body, headers); - - ResponseEntity bipResponse = - ceRestTemplate.postForEntity(url, httpEntity, String.class); - - BipFileUploadResp resp = new BipFileUploadResp(); - ObjectMapper objMapper = new ObjectMapper(); - UploadResponse ur = objMapper.readValue(bipResponse.getBody(), UploadResponse.class); - log.info( - "bip response for upload: status: {}, message: {}", - bipResponse.getStatusCode(), - bipResponse.getBody()); - resp.setStatus(bipResponse.getStatusCode()); - resp.setMessage(mapper.writeValueAsString(bipResponse.getBody())); - resp.setUploadResponse(ur); - return resp; - } catch (RestClientException | IOException e) { - log.error("failed to upload file.", e); - throw new BipException(e.getMessage(), e); - } - } - - @Override - public boolean verifyDocumentTypes() { - String url = HTTPS + bipApiProps.getEvidenceBaseUrl() + DOCUMENT_TYPES; - log.info("Call {} to documentTypes", url); - - HttpHeaders headers = getBipHeader(MediaType.APPLICATION_JSON); - HttpEntity httpEntity = new HttpEntity<>(headers); - - ResponseEntity response = - ceRestTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); - - return response.getStatusCode() == HttpStatus.OK && !response.getBody().isEmpty(); - } - - private HttpHeaders getBipHeader(MediaType mediaType) throws BipException { - try { - HttpHeaders bipHttpHeaders = new HttpHeaders(); - bipHttpHeaders.setContentType(mediaType); - - String jwt = createJwt(); - bipHttpHeaders.add("Authorization", "Bearer " + jwt); - return bipHttpHeaders; - } catch (Exception e) { - log.error("Failed to build BIP HTTP Headers.", e); - throw new BipException(e.getMessage(), e); - } - } - - private String createJwt() throws BipException { - Claims claims = bipApiProps.toCommonJwtClaims(); - - Map headerType = new HashMap<>(); - headerType.put("typ", Header.JWT_TYPE); - - byte[] signSecretBytes = bipApiProps.getEvidenceSecret().getBytes(StandardCharsets.UTF_8); - SecretKeySpec signingKey = - new SecretKeySpec(signSecretBytes, SignatureAlgorithm.HS256.getJcaName()); - claims.put("iss", bipApiProps.getEvidenceIssuer()); - return Jwts.builder() - .setSubject("Evidence") - .setIssuedAt(Calendar.getInstance().getTime()) - .setExpiration(claims.getExpiration()) - .setClaims(claims) - .signWith(SignatureAlgorithm.HS256, signingKey) - .setHeaderParams(headerType) - .compact(); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipClaimService.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipClaimService.java deleted file mode 100644 index 5a99c10703..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipClaimService.java +++ /dev/null @@ -1,282 +0,0 @@ -package gov.va.vro.service.provider.bip.service; - -import gov.va.vro.model.rrd.bip.BipClaim; -import gov.va.vro.model.rrd.bip.ClaimContention; -import gov.va.vro.model.rrd.bip.ClaimStatus; -import gov.va.vro.model.rrd.bip.FileIdType; -import gov.va.vro.model.rrd.bip.UpdateContention; -import gov.va.vro.model.rrd.bip.UpdateContentionReq; -import gov.va.vro.model.rrd.bipevidence.BipFileProviderData; -import gov.va.vro.model.rrd.bipevidence.BipFileUploadPayload; -import gov.va.vro.model.rrd.bipevidence.BipFileUploadResp; -import gov.va.vro.model.rrd.bipevidence.response.UploadResponse; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.response.FetchPdfResponse; -import gov.va.vro.service.provider.ClaimProps; -import gov.va.vro.service.provider.bip.BipException; -import gov.va.vro.service.provider.mas.MasCompletionStatus; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import gov.va.vro.service.provider.utils.DiagnosisLookup; -import gov.va.vro.service.spi.db.SaveToDbService; -import gov.va.vro.service.spi.model.GeneratePdfPayload; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.ObjectUtils; -import org.springframework.stereotype.Service; - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.Base64; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - -@RequiredArgsConstructor -@Slf4j -@Service -public class BipClaimService { - - public static final String TSOJ = "398"; - - private final ClaimProps claimPorps; - - private final IBipApiService bipApiService; - - private final IBipCeApiService bipCeApiService; - - private final SaveToDbService saveToDbService; - - /** - * Check if all the anchors for fast-tracking are satisfied. - * - * @param claimId claim id identifying the claim - * @return true if the anchors are satisfied, false otherwise - */ - public boolean hasAnchors(long claimId) { - - var claimDetails = bipApiService.getClaimDetails(claimId); - if (claimDetails == null) { - log.warn("Claim with claim Id {} not found in BIP", claimId); - return false; - } - if (!TSOJ.equals(claimDetails.getTempStationOfJurisdiction())) { - log.info("Claim with claim Id {} does not have TSOJ = {}", claimId, TSOJ); - return false; - } - - var contentions = bipApiService.getClaimContentions(claimId); - if (contentions == null || contentions.size() == 0) { - log.info("Claim with claim Id {} does not have contentions.", claimId); - return false; - } - if (contentions.size() > 1) { - log.info("Claim with claim Id {} have multiple contentions.", claimId); - return false; - } - - log.info( - "SPECIAL_ISSUE_1: {}, SPECIAL_ISSUE_2: {}", - claimPorps.getSpecialIssue1(), - claimPorps.getSpecialIssue2()); - // collect all special issues - var specialIssues = - contentions.stream() - .filter(BipClaimService::hasSpecialIssues) - .map(ClaimContention::getSpecialIssueCodes) - .flatMap(Collection::stream) - .map(String::toLowerCase) // Ignore case - .collect(Collectors.toSet()); - boolean hasSpecialIssues = - specialIssues.contains(claimPorps.getSpecialIssue1().toLowerCase()) - && specialIssues.contains(claimPorps.getSpecialIssue2().toLowerCase()); - log.info("Claim {} contention special issues: {}", claimId, String.join(", ", specialIssues)); - log.info("Has special issues: {}", hasSpecialIssues); - return hasSpecialIssues; - } - - /** - * Updates the contention based on the completion status of automated benefit delivery processing. - * - * @param contention contention to be updated - * @param status completion status of automated benefit delivery processing - * @return - */ - private ClaimContention getUpdatedContention( - long claimId, ClaimContention contention, MasCompletionStatus status) { - long contentionId = contention.getContentionId(); - String messageId = String.format("for contention %s of claim %s", contentionId, claimId); - log.info("Finding necessary {} updates {}", status.getDescription(), messageId); - - boolean updated = false; - ClaimContention result = contention.toBuilder().build(); - - boolean necessaryAutomationIndicator = status.isAutomationIndicator(); - if (contention.isAutomationIndicator() != necessaryAutomationIndicator) { - log.info("Setting automation indicator to {} {}", necessaryAutomationIndicator, messageId); - result.setAutomationIndicator(necessaryAutomationIndicator); - updated = true; - } else { - log.info("Automation indicator is already {} {}", necessaryAutomationIndicator, messageId); - } - - Set issuesToRemove = status.getSpecialIssuesToRemove(claimPorps); - List specialIssueCodes = contention.getSpecialIssueCodes(); - List updatedIssueCodes = - specialIssueCodes.stream() - .filter(code -> !issuesToRemove.contains(code.toUpperCase())) - .collect(Collectors.toList()); - int removedCount = specialIssueCodes.size() - updatedIssueCodes.size(); - if (removedCount > 0) { - log.info("Removing {} special issues {}", removedCount, messageId); - log.info("Special issue codes were: {}", String.join(",", specialIssueCodes)); - log.info("Special issue code will be {}", String.join(",", updatedIssueCodes)); - result.setSpecialIssueCodes(updatedIssueCodes); - updated = true; - } else { - log.error("No special issues to remove {}", messageId); - log.info("Special issue codes were: {}", String.join(",", specialIssueCodes)); - } - - String necessaryLifecycleStatus = status.getClaimStatus().getDescription(); - if (!necessaryLifecycleStatus.equals(contention.getLifecycleStatus())) { - log.info("Setting lifecycle status to {} {}", necessaryLifecycleStatus, messageId); - result.setLifecycleStatus(necessaryLifecycleStatus); - updated = true; - } else { - log.info("Lifecycle status is already {} {}", necessaryLifecycleStatus, messageId); - } - - if (updated) { - return result; - } - return null; - } - - private BipClaim updateClaimProper(long claimId, MasCompletionStatus status) { - BipClaim claim = bipApiService.getClaimDetails(claimId); - ClaimStatus claimStatus = status.getClaimStatus(); - String necessaryLifecycleStatus = claimStatus.getDescription(); - if (!necessaryLifecycleStatus.equals(claim.getClaimLifecycleStatus())) { - log.info("Updating lifecycle status to {} for claim {}", necessaryLifecycleStatus, claimId); - bipApiService.updateClaimStatus(claimId, claimStatus); - if (claimStatus == ClaimStatus.RFD) { - saveToDbService.updateRfdFlag(String.valueOf(claimId), true); - } - } else { - log.info("Lifecycle status is already {} for claim {}", necessaryLifecycleStatus, claimId); - } - return claim; - } - - /** - * Updates claim and contentions at the end of MAS automated claim processing. - * - * @param payload the claim payload - * @param status the completion status for mas automation - * @return the claim payload - */ - public BipUpdateClaimResult updateClaim(MasProcessingObject payload, MasCompletionStatus status) { - long claimId = Long.parseLong(payload.getBenefitClaimId()); - log.info("Attempting necessary updates for claim id = {}", claimId); - - final BipClaim claim = updateClaimProper(claimId, status); - - var contentions = bipApiService.getClaimContentions(claimId); - if (ObjectUtils.isEmpty(contentions)) { - String message = String.format("Claim id = %s has no contentions.", claimId); - return BipUpdateClaimResult.ofError(message); - } - if (contentions.size() > 1) { - String message = String.format("Claim id = %s has multiple contentions.", claimId); - return BipUpdateClaimResult.ofError(message); - } - - List updatedContentions = new ArrayList<>(); - for (ClaimContention contention : contentions) { - ClaimContention update = getUpdatedContention(claimId, contention, status); - if (update != null) { - updatedContentions.add(update); - } - } - if (updatedContentions.isEmpty()) { - log.info("Nothing to update for claim {}.", claimId); - } else { - log.info("Preparing requests for contention updates for claim id = {}", claimId); - String action = "UPDATED_CONTENTION"; - List updateContentions = - updatedContentions.stream() - .map(c -> c.toUpdateContention(action)) - .collect(Collectors.toList()); - UpdateContentionReq request = - UpdateContentionReq.builder().updateContentions(updateContentions).build(); - log.info("Calling BIP AP Service for contention updates for claim id = {}", claimId); - bipApiService.updateClaimContention(claimId, request); - } - - String station = claim.getTempStationOfJurisdiction(); - if (!TSOJ.equals(station)) { - String message = - String.format("Claim %s is in station %s not in %s.", claimId, station, TSOJ); - return BipUpdateClaimResult.ofWarning(message); - } - - return new BipUpdateClaimResult(true); - } - - /** - * Uploads a pdf. - * - * @param pdfResponse pdf response. - * @return pdf response. - * @throws BipException if anything goes wrong - */ - public FetchPdfResponse uploadPdf(MasAutomatedClaimPayload payload, FetchPdfResponse pdfResponse) - throws BipException { - log.info("Uploading pdf for claim {}...", pdfResponse.getClaimSubmissionId()); - if (pdfResponse.getPdfData() == null) { - throw new BipException("PDF Response does not contain any data"); - } - String filename = - GeneratePdfPayload.createPdfFilename( - DiagnosisLookup.getDiagnosis(payload.getDiagnosticCode())); - - byte[] decoder = Base64.getDecoder().decode(pdfResponse.getPdfData()); - BipFileProviderData providerData = - BipFileProviderData.builder() - .contentSource("VRO") - .claimantFirstName(payload.getFirstName()) - .claimantLastName(payload.getLastName()) - .claimantSsn(payload.getVeteranIdentifiers().getSsn()) - .documentTypeId(1489) - .dateVaReceivedDocument(LocalDate.now().toString()) - .subject(pdfResponse.getDiagnosis()) // get a subject - .notes(pdfResponse.getReason() == null ? null : pdfResponse.getReason()) - .claimantParticipantId(payload.getVeteranIdentifiers().getParticipantId()) - .sourceComment("upload from VRO") - .claimantDateOfBirth(payload.getDateOfBirth()) - .build(); - - BipFileUploadResp bipResp = - bipCeApiService.uploadEvidenceFile( - FileIdType.FILENUMBER, - payload.getVeteranIdentifiers().getVeteranFileId(), - BipFileUploadPayload.builder().contentName(filename).providerData(providerData).build(), - decoder, - payload.getDiagnosticCode()); - // We check if bipResp is null only so that the uploadPdf() test does not fail in - // BipClaimServiceTest. - // We created a ticket to fix this test and remove this condition. - if (bipResp != null) { - UploadResponse ur = bipResp.getUploadResponse(); - UUID eFolderId = UUID.fromString(ur.getUuid()); - saveToDbService.updateEvidenceSummaryDocument(eFolderId, payload); - } - return pdfResponse; - } - - private static boolean hasSpecialIssues(ClaimContention claimContention) { - return claimContention.getSpecialIssueCodes() != null; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipUpdateClaimResult.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipUpdateClaimResult.java deleted file mode 100644 index 784c0325a6..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/BipUpdateClaimResult.java +++ /dev/null @@ -1,30 +0,0 @@ -package gov.va.vro.service.provider.bip.service; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Getter -@RequiredArgsConstructor -@AllArgsConstructor -@Slf4j -public class BipUpdateClaimResult { - @NonNull private final boolean success; - private String message; - - public boolean hasMessage() { - return message != null; - } - - public static BipUpdateClaimResult ofError(String message) { - log.error(message); - return new BipUpdateClaimResult(false, message); - } - - public static BipUpdateClaimResult ofWarning(String message) { - log.warn(message); - return new BipUpdateClaimResult(true, message); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/IBipApiService.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/IBipApiService.java deleted file mode 100644 index 74f47d13a8..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/IBipApiService.java +++ /dev/null @@ -1,68 +0,0 @@ -package gov.va.vro.service.provider.bip.service; - -import gov.va.vro.service.provider.bip.BipException; - -import java.util.List; - -/** - * BIP Claims API service. - * - * @author warren @Date 11/8/22 - */ -public interface IBipApiService { - - /** - * Gets a claim detail information. - * - * @param collectionId the claim ID - * @return a BipClaim object. - * @throws BipException error occurs. - */ - BipClaim getClaimDetails(long collectionId) throws BipException; - - /** - * Updates claim status to RFD. - * - * @param collectionId claim ID - * @return a claim info object. - * @throws BipException error occurs. - */ - BipUpdateClaimResp setClaimToRfdStatus(long collectionId) throws BipException; - - /** - * Updates a claim status. - * - * @param collectionId claim ID. - * @param status status to be updated to. - * @return a claim update info object. - * @throws BipException error occurs. - */ - BipUpdateClaimResp updateClaimStatus(long collectionId, ClaimStatus status) throws BipException; - - /** - * Gets a list of contentions in a claim. - * - * @param claimId claim ID. - * @return a list of contention objects. - * @throws BipException error occurs. - */ - List getClaimContentions(long claimId) throws BipException; - - /** - * Updates a contention in a cloim. - * - * @param claimId claim ID. - * @param contention updated contention. - * @return an object with the information of update status and a message. - * @throws BipException error occurs. - */ - BipUpdateClaimResp updateClaimContention(long claimId, UpdateContentionReq contention) - throws BipException; - - /** - * Verifies a call to the BIP Claims API can be made by getting document types. - * - * @return boolean verification status - */ - boolean verifySpecialIssueTypes(); -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/IBipCeApiService.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/IBipCeApiService.java deleted file mode 100644 index 4054083e30..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/bip/service/IBipCeApiService.java +++ /dev/null @@ -1,34 +0,0 @@ -package gov.va.vro.service.provider.bip.service; - -import gov.va.vro.model.rrd.bip.FileIdType; -import gov.va.vro.model.rrd.bipevidence.BipFileUploadPayload; -import gov.va.vro.model.rrd.bipevidence.BipFileUploadResp; -import gov.va.vro.service.provider.bip.BipException; - -/** BIP Claims Evidence API service. */ -public interface IBipCeApiService { - /** - * Uploads an evidence file for the claim. - * - * @param idType ID type. It should be FILENUMBER, SSN, ARTICIPANT_ID, or EDIPI - * @param fileId id - * @param payload upload payload data. - * @param fileContent the file to be uploaded. - * @return an object for the upload status. - * @throws BipException exception - */ - BipFileUploadResp uploadEvidenceFile( - FileIdType idType, - String fileId, - BipFileUploadPayload payload, - byte[] fileContent, - String diagnosticCode) - throws BipException; - - /** - * Verifies a call to the BIP Claim Evidence API can be made by getting document types. - * - * @return boolean verification status - */ - boolean verifyDocumentTypes(); -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/BgsApiClientException.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/BgsApiClientException.java deleted file mode 100644 index a3559167ac..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/BgsApiClientException.java +++ /dev/null @@ -1,7 +0,0 @@ -package gov.va.vro.service.provider.camel; - -public class BgsApiClientException extends RuntimeException { - public BgsApiClientException(String message) { - super(message); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/BgsApiClientRoutes.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/BgsApiClientRoutes.java deleted file mode 100644 index 619dbcc007..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/BgsApiClientRoutes.java +++ /dev/null @@ -1,167 +0,0 @@ -package gov.va.vro.service.provider.camel; - -import gov.va.vro.camel.RabbitMqCamelUtils; -import gov.va.vro.camel.ToRabbitMqRouteHelper; -import gov.va.vro.camel.processor.FunctionProcessor; -import gov.va.vro.camel.processor.RequestAndMerge; -import gov.va.vro.model.rrd.bgs.BgsApiClientRequest; -import gov.va.vro.model.rrd.bgs.BgsApiClientResponse; -import gov.va.vro.service.provider.MasConfig; -import gov.va.vro.service.provider.bgs.service.BgsApiClient; -import gov.va.vro.service.provider.bgs.service.BgsNotesCamelBody; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.ExchangePattern; -import org.apache.camel.ProducerTemplate; -import org.apache.camel.builder.RouteBuilder; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; - -import java.util.concurrent.atomic.AtomicInteger; - -@Slf4j -@Component -@RequiredArgsConstructor -public class BgsApiClientRoutes extends RouteBuilder { - - public static final String ADD_BGS_NOTES = "seda:addBgsNotes-entry"; - static final String BGSCLIENT_ADDNOTES = "direct:toRabbit-bgsClient-addNotes"; - static final String ADD_NOTES_RETRIES = "direct:addBgsNotesWithRetries"; - - private final ProducerTemplate producerTemplate; - - private final BgsApiClient bgsApiClient; - - static final int RETRY_LIMIT = 5; - - @Override - public void configure() throws Exception { - var routeId = "add-bgs-notes-route"; - configureAddNotesRoute(routeId); - configureRouteToBgsApiClientMicroservice(); - configureRouteToSlackNotification(); - - String env = System.getenv("ENV"); - log.info("ENV=" + env); - // TODO: workaround until a BGS Mock is used in end2end integration tests - if ("end2end-test".equals(env)) configureMockBgsApiMicroservice(); - } - - private void configureAddNotesRoute(String routeId) { - from(ADD_BGS_NOTES) - .routeId(routeId) - .setExchangePattern(ExchangePattern.InOut) - // expecting body MasProcessingObject.class - .log("addBgsNotes: ${body}") - .bean(bgsApiClient, "buildRequests") - .loopDoWhile(simple("${body.pendingRequests.size} > 0")) - .log("addBgsNotes loop: ${body.pendingRequests.size} pendingRequests") - .to(ADD_NOTES_RETRIES) - .end(); // of loopDoWhile - - from(ADD_NOTES_RETRIES) - .routeId("add-bgs-notes-retry-route") - .doTry() - .log("addBgsNotes: microservice request: ${body}") - .process(requestBgsToAddNotesProcessor()) - .id("requestBgsToAddNotes") - .doCatch(BgsApiClientException.class) - .setBody(simple("${body.incrementTryCount()}")) - .log( - "caught: ${exception.message}: tryCount=${body.tryCount} will retry in ${body.delayMillis} ms") - .delay(simple("${body.delayMillis}")) - .to(ADD_NOTES_RETRIES) - .end(); // of try-catch block - } - - private RequestAndMerge - requestBgsToAddNotesProcessor() { - return RequestAndMerge.factory(producerTemplate) - .requestUri(BGSCLIENT_ADDNOTES) - .prepareRequest(body -> body.currentRequest()) - // set responseClass so that Camel auto-converts JSON into object - .responseClass(BgsApiClientResponse.class) - .mergeResponse( - (body, response) -> { - body.setResponse(response); - if (response.getStatusCode() < 300) { - body.removePendingRequest(body.request); - } else { - if (body.tryCount.get() >= RETRY_LIMIT) { - body.removePendingRequest(body.request); - producerTemplate.requestBody(ENDPOINT_SLACK_BGS_FAILED, body); - } else { - // cause a retry - throw new BgsApiClientException( - "Failed to add note. collection id: " + body.mpo.getCollectionId()); - } - } - return body; - }) - .build(); - } - - // https://github.com/department-of-veterans-affairs/abd-vro/issues/1289 - void configureRouteToBgsApiClientMicroservice() { - new ToRabbitMqRouteHelper(this, BGSCLIENT_ADDNOTES) - .toMq("bgs-api", "add-note") - .rabbitMqEndpointId("to-rabbitmq-bgsclient-addnote") - .responseClass(BgsApiClientResponse.class) - .createRoute() - .log("addBgsNotes: response: ${body}"); - } - - private final MasConfig masConfig; - public static final String ENDPOINT_SLACK_BGS_FAILED = "seda:slack-bgs-api-failure"; - - void configureRouteToSlackNotification() { - var buildErrorMessage = - FunctionProcessor.fromFunction( - model -> - // The mock Slack service expects `collection id: ` to be in the message - String.format( - "Failed to add VBMS notes for claim %s, collection id: %s; status code %s: %s. Note: %s %s", - model.request.getVbmsClaimId(), - model.mpo.getCollectionId(), - model.response.getStatusCode(), - model.response.getStatusMessage(), - model.request.veteranNote, - model.request.claimNotes)); - - String webhook = masConfig.getSlackExceptionWebhook(); - String channel = masConfig.getSlackExceptionChannel(); - - from(ENDPOINT_SLACK_BGS_FAILED) - .routeId("slack-bgs-failed-route") - .filter(exchange -> StringUtils.isNotBlank(webhook)) - .process(buildErrorMessage) - .log("slack: ${body}") - .to(String.format("slack:#%s?webhookUrl=%s", channel, webhook)) - .id("message-to-slack"); - } - - // TODO: remove once a BGS Mock and associated microservice is used in end2end integration tests - void configureMockBgsApiMicroservice() { - final AtomicInteger requestCounter = new AtomicInteger(0); - var mockService = - FunctionProcessor.builder() - .inputBodyClass(BgsApiClientRequest.class) - .function( - request -> { - log.warn("++ MOCK BgsApiClientMicroservice: " + request.toString()); - var response = new BgsApiClientResponse(); - if (requestCounter.incrementAndGet() % 1 == 0) { - log.warn("++++ Mock success"); - response.setStatusCode(200); - } else { - log.warn("++++ Mock error"); - response.setStatusMessage("Mocked error"); - response.setStatusCode(400); - } - return response; - }) - .build(); - - RabbitMqCamelUtils.fromRabbitmq(this, "bgs-api", "add-note").process(mockService); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/CamelProcessingException.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/CamelProcessingException.java deleted file mode 100644 index 9b4ed0ccab..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/CamelProcessingException.java +++ /dev/null @@ -1,8 +0,0 @@ -package gov.va.vro.service.provider.camel; - -public class CamelProcessingException extends RuntimeException { - - public CamelProcessingException(String message) { - super(message); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/ExchangeAuditTransformer.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/ExchangeAuditTransformer.java deleted file mode 100644 index 83250d7314..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/ExchangeAuditTransformer.java +++ /dev/null @@ -1,27 +0,0 @@ -package gov.va.vro.service.provider.camel; - -import gov.va.vro.model.rrd.event.AuditEvent; -import gov.va.vro.model.rrd.event.Auditable; -import org.apache.camel.Exchange; -import org.apache.camel.Message; -import org.apache.camel.Processor; - -/** Extract an AuditEvent from the information on the Exchange. */ -public class ExchangeAuditTransformer implements Processor { - @Override - public void process(Exchange exchange) { - String routeId = exchange.getProperty("originalRouteId", String.class); - if (routeId == null) { - routeId = exchange.getFromRouteId(); - } - String endpoint = exchange.getFromEndpoint().getEndpointUri(); - Message message = exchange.getMessage(); - Auditable body = message.getBody(Auditable.class); - Throwable exception = (Throwable) exchange.getProperty(Exchange.EXCEPTION_CAUGHT); - var event = - exception == null - ? AuditEvent.fromAuditable(body, routeId, "Received message from endpoint " + endpoint) - : AuditEvent.fromException(body, routeId, exception); - message.setBody(event); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/MasIntegrationRoutes.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/MasIntegrationRoutes.java deleted file mode 100644 index 7b102d6698..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/MasIntegrationRoutes.java +++ /dev/null @@ -1,434 +0,0 @@ -package gov.va.vro.service.provider.camel; - -import static gov.va.vro.service.provider.camel.processor.MasIntegrationProcessors.auditProcessor; -import static gov.va.vro.service.provider.camel.processor.MasIntegrationProcessors.combineExchangesProcessor; -import static gov.va.vro.service.provider.camel.processor.MasIntegrationProcessors.convertToMasProcessingObject; -import static gov.va.vro.service.provider.camel.processor.MasIntegrationProcessors.convertToPdfResponse; -import static gov.va.vro.service.provider.camel.processor.MasIntegrationProcessors.generatePdfProcessor; -import static gov.va.vro.service.provider.camel.processor.MasIntegrationProcessors.lighthouseContinueProcessor; -import static gov.va.vro.service.provider.camel.processor.MasIntegrationProcessors.payloadToClaimProcessor; -import static gov.va.vro.service.provider.camel.processor.MasIntegrationProcessors.setOffRampReasonProcessor; -import static gov.va.vro.service.provider.camel.processor.MasIntegrationProcessors.slackEventProcessor; -import static gov.va.vro.service.provider.camel.processor.MasIntegrationProcessors.slackEventPropertyProcessor; - -import gov.va.vro.camel.FunctionProcessor; -import gov.va.vro.camel.RabbitMqCamelUtils; -import gov.va.vro.camel.ToRabbitMqRouteHelper; -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.model.rrd.HealthDataAssessment; -import gov.va.vro.model.rrd.event.AuditEvent; -import gov.va.vro.model.rrd.event.Auditable; -import gov.va.vro.model.rrd.event.EventReason; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.response.FetchPdfResponse; -import gov.va.vro.service.provider.ExternalCallException; -import gov.va.vro.service.provider.MasConfig; -import gov.va.vro.service.provider.bip.BipException; -import gov.va.vro.service.provider.bip.service.BipClaimService; -import gov.va.vro.service.provider.camel.processor.EvidenceSummaryDocumentProcessor; -import gov.va.vro.service.provider.camel.processor.HealthEvidenceProcessor; -import gov.va.vro.service.provider.camel.processor.LighthouseErrCheckProcessor; -import gov.va.vro.service.provider.camel.processor.MasAccessErrProcessor; -import gov.va.vro.service.provider.camel.processor.MasAssessmentResultProcessor; -import gov.va.vro.service.provider.camel.processor.MasIntegrationProcessors; -import gov.va.vro.service.provider.camel.processor.MasOrderExamProcessor; -import gov.va.vro.service.provider.camel.processor.MasPollingProcessor; -import gov.va.vro.service.provider.camel.processor.ServiceLocationsExtractorProcessor; -import gov.va.vro.service.provider.mas.MasException; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import gov.va.vro.service.provider.mas.service.MasCollectionService; -import gov.va.vro.service.provider.mas.service.MasProcessingService; -import gov.va.vro.service.spi.audit.AuditEventService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.ExchangePattern; -import org.apache.camel.ExchangeTimedOutException; -import org.apache.camel.ProducerTemplate; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.processor.aggregate.GroupedExchangeAggregationStrategy; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -@Slf4j -public class MasIntegrationRoutes extends RouteBuilder { - - public static final String ENDPOINT_MAS = - "rabbitmq:mas-notification-exchange?queue=mas-notification" - + "-queue&routingKey=mas-notification&requestTimeout=0"; - - public static final String ENDPOINT_AUTOMATED_CLAIM = "seda:automated-claim"; - - public static final String IMVP_EXCHANGE = "imvp"; - public static final String NOTIFY_AUTOMATED_CLAIM_QUEUE = "notifyAutomatedClaim"; - - public static final String ENDPOINT_EXAM_ORDER_STATUS = "direct:exam-order-status"; - - public static final String MAS_DELAY_PARAM = "masDelay"; - - public static final String MAS_RETRY_PARAM = "masRetryCount"; - - public static final String ENDPOINT_MAS_PROCESSING = "direct:mas-processing"; - - public static final String ENDPOINT_AUDIT_EVENT = "seda:audit-event"; - - public static final String ENDPOINT_SLACK_EVENT = "seda:slack-event"; - - public static final String ENDPOINT_MAS_COMPLETE = "direct:mas-complete"; - - public static final String ENDPOINT_LIGHTHOUSE_EVIDENCE = "direct:lighthouse-claim-submit"; - public static final String ENDPOINT_UPLOAD_PDF = "direct:upload-pdf"; - public static final String ENDPOINT_AUDIT_WIRETAP = "direct:wire"; - private static final String ENDPOINT_COLLECT_EVIDENCE = "direct:collect-evidence"; - public static final String ENDPOINT_NOTIFY_AUDIT = "seda:notify-audit"; - public static final String END_POINT_RFD = "direct:rfd"; - public static final String ENDPOINT_ORDER_EXAM = "direct:order-exam"; - public static final String ENDPOINT_EXAM_ORDER_SLACK = "direct: exam-order-slack"; - - // Base names for wiretap endpoints - public static final String MAS_CLAIM_WIRETAP = "mas-claim-submitted"; - public static final String EXAM_ORDER_STATUS_WIRETAP = "exam-order-status"; - - private final ProducerTemplate producerTemplate; - - private final BipClaimService bipClaimService; - - private final MasProcessingService masProcessingService; - - private final AuditEventService auditEventService; - - private final MasConfig masConfig; - - private final MasPollingProcessor masPollingProcessor; - - private final MasOrderExamProcessor masOrderExamProcessor; - - private final MasAccessErrProcessor masAccessErrProcessor; - - private final MasCollectionService masCollectionService; - private final MasAssessmentResultProcessor masAssessmentResultProcessor; - - private final SlipClaimSubmitRouter slipClaimSubmitRouter; - - private final EvidenceSummaryDocumentProcessor evidenceSummaryDocumentProcessor; - - private final LighthouseErrCheckProcessor lighthouseErrCheckProcessor; - - public static final String LIGHTHOUSE_ERROR_MSG = "Lighthouse health data not retrieved."; - - @Override - public void configure() { - configureAuditing(); - configureNotify(); - configureExamOrderSlack(); - configureAutomatedClaim(); - configureMasProcessing(); - configureCollectEvidence(); - configureUploadPdf(); - configureCompleteProcessing(); - configureOrderExamStatus(); - } - - private void configureAutomatedClaim() { - RabbitMqCamelUtils.fromRabbitmq(this, IMVP_EXCHANGE, NOTIFY_AUTOMATED_CLAIM_QUEUE) - .setExchangePattern(ExchangePattern.InOnly) - .routeId("mas-request-injection") - .convertBodyTo(MasAutomatedClaimPayload.class) - .wireTap(RabbitMqCamelUtils.wiretapProducer(this, MAS_CLAIM_WIRETAP)) - .to(ENDPOINT_AUTOMATED_CLAIM); - - final String DIRECT_TO_MQ_MAS = "direct:toMq-mas-notification"; - final String MAS_NOTIFICATION_EXCHANGE = "mas-notification-exchange"; - final String MAS_NOTIFICATION_ROUTING_KEY = "mas-notification"; - new ToRabbitMqRouteHelper(this, DIRECT_TO_MQ_MAS) - .toMq(MAS_NOTIFICATION_EXCHANGE, MAS_NOTIFICATION_ROUTING_KEY, "&requestTimeout=0") - .createRoute(); - - var checkClaimRouteId = "mas-claim-notification"; - from(ENDPOINT_AUTOMATED_CLAIM) - .routeId(checkClaimRouteId) - .wireTap(ENDPOINT_AUDIT_WIRETAP) - // For the ENDPOINT_AUDIT_WIRETAP, use auditProcessor to convert body to type AuditEvent - .onPrepare(auditProcessor(checkClaimRouteId, "Checking if claim is ready...")) - // Msg body is still a MasAutomatedClaimPayload - .delay(header(MAS_DELAY_PARAM)) - .setExchangePattern(ExchangePattern.InOnly) - .to(DIRECT_TO_MQ_MAS); - - var processClaimRouteId = "mas-claim-processing"; - RabbitMqCamelUtils.fromRabbitmq(this, MAS_NOTIFICATION_EXCHANGE, MAS_NOTIFICATION_ROUTING_KEY) - .routeId(processClaimRouteId) - .convertBodyTo(MasAutomatedClaimPayload.class) - .process(masPollingProcessor) - .setExchangePattern(ExchangePattern.InOnly); // TODO Q: Why is this needed? - } - - private void configureMasProcessing() { - String routeId = "mas-processing"; - - from(ENDPOINT_MAS_PROCESSING) - .routeId(routeId) - .wireTap(ENDPOINT_AUDIT_WIRETAP) - .onPrepare(auditProcessor(routeId, "Started claim processing.")) - .process(convertToMasProcessingObject()) - .setProperty("diagnosticCode", simple("${body.diagnosticCode}")) - .setProperty("idType", simple("${body.idType}")) - .to(ENDPOINT_COLLECT_EVIDENCE) // collect evidence from lighthouse and MAS - // determine if evidence is sufficient - .routingSlip(method(slipClaimSubmitRouter, "routeHealthSufficiency")) - .convertBodyTo(AbdEvidenceWithSummary.class) - .process(masAssessmentResultProcessor) - .choice() - .when(simple("${body.errorMessage} != null")) - .log("Health Assessment Processing failed. Off-ramping claim ${body.errorMessage}") - // Completion code needs the MasProcessingObject as the body. - .setBody(simple("${exchangeProperty.payload}")) - .process(setOffRampReasonProcessor(EventReason.HEALTH_PROCESSOR_FAILED.getCode())) - .to(ENDPOINT_MAS_COMPLETE) - .stop() // Do not continue processing - .otherwise() - .process(new HealthEvidenceProcessor()) // returns MasTransferObject - .end() - .choice() - .when(simple("${body.sufficientForFastTracking} == false")) - .to(ENDPOINT_ORDER_EXAM) - .when(simple("${body.sufficientForFastTracking} == true")) - .to(END_POINT_RFD) - .otherwise() - // Off ramp if the Sufficient For Fast Tracking is null - .process(setOffRampReasonProcessor(EventReason.SUFFICIENCY_UNDETERMINED.getCode())) - .log("Assessor Error. Off-ramping claim") - .process(masAccessErrProcessor) - .to(ENDPOINT_MAS_COMPLETE) - .end(); - - String rfdRouteId = "mas-rfd"; - - from(END_POINT_RFD) - // input: MasAutomatedClaimPayload - .routeId(rfdRouteId) - .wireTap(ENDPOINT_AUDIT_WIRETAP) - .onPrepare(auditProcessor(rfdRouteId, "Sufficient evidence for ready for decision.")) - // Upload PDF - .doTry() - .to(ENDPOINT_UPLOAD_PDF) - .doCatch(BipException.class) - // Completion code needs the MasProcessingObject as the body. - .setBody(simple("${exchangeProperty.payload}")) - .process( - setOffRampReasonProcessor( - EventReason.PDF_UPLOAD_FAILED_AFTER_RFD - .getCode())) // Continue to completion processor - .end() // End try - .to(ENDPOINT_MAS_COMPLETE); - - // Call "Order Exam" in the absence of evidence .i.e Sufficient For Fast Tracking is "false" - var orderExamRouteId = "mas-order-exam"; - final String pdfFailMessage = - String.format( - "reason code: %s, narrative:%s", - EventReason.PDF_UPLOAD_FAILED_AFTER_ORDER_EXAM.getCode(), - EventReason.PDF_UPLOAD_FAILED_AFTER_ORDER_EXAM.getNarrative()); - - from(ENDPOINT_ORDER_EXAM) - // input: MasAutomatedClaimPayload - .routeId(orderExamRouteId) - .wireTap(ENDPOINT_AUDIT_WIRETAP) - .onPrepare( - auditProcessor(orderExamRouteId, "There is insufficient evidence. Ordering an exam")) - .doTry() - .process(masOrderExamProcessor) - // Upload PDF but catch errors since exam was ordered and continue - .to(ENDPOINT_UPLOAD_PDF) - .to(ENDPOINT_MAS_COMPLETE) - .doCatch(MasException.class) - // Body is still the Mas Processing object. - .process(setOffRampReasonProcessor(EventReason.EXAM_ORDER_FAILED.getCode())) - .to(ENDPOINT_MAS_COMPLETE) - .stop() // Offramp and don't continue processing - .doCatch(BipException.class) - // Mas Complete Processing code expects this to be the body of the message - .setBody(simple("${exchangeProperty.payload}")) - // Wiretap will cause no code to execute after the end of the try. Intentional here. - .wireTap(ENDPOINT_NOTIFY_AUDIT) // Send error notification to slack - .onPrepare(slackEventProcessor(orderExamRouteId, pdfFailMessage)) - .to(ENDPOINT_MAS_COMPLETE) - .end(); - } - - private void configureCollectEvidence() { - String lighthouseRetryRoute = "direct:lighthouse-retry"; - String lighthouseRoute = "mas-automated-claim-lighthouse"; - String wiretapLighthouse = "direct:wiretap-lighthouse"; - - String routeId = "mas-collect-evidence"; - from(ENDPOINT_COLLECT_EVIDENCE) - .onException( - MasException - .class) // Do not go to the main error processor. Mas complete route handles. - .handled(true) - .end() // End Exception - .routeId(routeId) - .wireTap(ENDPOINT_AUDIT_WIRETAP) - .onPrepare(auditProcessor(routeId, "Collecting evidence")) - .setProperty("payload", simple("${body}")) - .multicast(new GroupedExchangeAggregationStrategy()) - .stopOnException() // Stop does not handle the exception. - .doTry() - .process( - FunctionProcessor.fromFunction(masCollectionService::collectAnnotations)) // call MAS - .doCatch(MasException.class) // offramp claim if we get no MAS annotations - .setBody(simple("${exchangeProperty.payload}")) - .process(setOffRampReasonProcessor(EventReason.ANNOTATIONS_FAILED.getCode())) - .to(ENDPOINT_MAS_COMPLETE) - .throwException( - new MasException("annotationDataRequestFailed")) // this will stop the multicast above. - .end() // End Try - .to(ENDPOINT_LIGHTHOUSE_EVIDENCE) // call lighthouse, if it fails we retry - .end() // end multicast - .process(combineExchangesProcessor()) // returns HealthDataAssessment - .process(new ServiceLocationsExtractorProcessor()); // put service locations to property - - from(ENDPOINT_LIGHTHOUSE_EVIDENCE) - .routeId(lighthouseRoute) - .setProperty("payload", simple("${body}")) - .process(payloadToClaimProcessor()) - .doTry() - .to(lighthouseRetryRoute) - .doCatch(ExchangeTimedOutException.class, ExternalCallException.class) - .to(wiretapLighthouse) - .process(lighthouseContinueProcessor()) // But keep processing - .end(); - - // Wiretap breaks onCatch behavior, onException wont work here. This is the workaround. - from(wiretapLighthouse) - .wireTap(ENDPOINT_NOTIFY_AUDIT) // Send error notification to slack - .onPrepare(slackEventPropertyProcessor(lighthouseRoute, LIGHTHOUSE_ERROR_MSG, "payload")); - - from(lighthouseRetryRoute) - .doTry() - .setProperty("retryBody", simple("${body}")) - .routingSlip(method(slipClaimSubmitRouter, "routeClaimSubmit")) - .convertBodyTo(HealthDataAssessment.class) - .process(lighthouseErrCheckProcessor) // Check for errors, and throw or do not alter - .endDoTry() - .doCatch(ExchangeTimedOutException.class, ExternalCallException.class) - .log("Retrying lighthouse due to error") - .setBody(simple("${exchangeProperty.retryBody}")) - .removeProperty("retryBody") - .routingSlip(method(slipClaimSubmitRouter, "routeClaimSubmit")) - .convertBodyTo(HealthDataAssessment.class) - .process(lighthouseErrCheckProcessor) - .endDoCatch(); - } - - private void configureUploadPdf() { - var routeId = "mas-upload-pdf"; - from(ENDPOINT_UPLOAD_PDF) - .wireTap(ENDPOINT_AUDIT_WIRETAP) - .onPrepare(auditProcessor(routeId, "Generating PDF")) - .process(generatePdfProcessor()) // convert to PDF payload - .process(evidenceSummaryDocumentProcessor) // store evidence in DB - .to(PrimaryRoutes.ENDPOINT_GENERATE_FETCH_PDF) - .process(convertToPdfResponse()) - .process( - exchange -> { - var pdfResponse = exchange.getMessage().getBody(FetchPdfResponse.class); - var masProcessingObject = exchange.getProperty("payload", MasProcessingObject.class); - bipClaimService.uploadPdf(masProcessingObject.getClaimPayload(), pdfResponse); - }) - .setBody(simple("${exchangeProperty.payload}")) - .wireTap(ENDPOINT_AUDIT_WIRETAP) - .onPrepare(auditProcessor(routeId, "Uploaded PDF")); - } - - private void configureOrderExamStatus() { - // This route does not do anything, but an audit event is persisted - String routeId = "mas-exam-order-status"; - from(ENDPOINT_EXAM_ORDER_STATUS) - .routeId(routeId) - .wireTap(RabbitMqCamelUtils.wiretapProducer(this, EXAM_ORDER_STATUS_WIRETAP)) - .wireTap(ENDPOINT_AUDIT_WIRETAP) - .onPrepare(auditProcessor(routeId, "Exam Order Status Called")) - .log("Invoked " + routeId); - } - - private void configureCompleteProcessing() { - var routeId = "mas-complete-claim"; - from(ENDPOINT_MAS_COMPLETE) - .routeId(routeId) - .wireTap(ENDPOINT_AUDIT_WIRETAP) - .onPrepare(auditProcessor(routeId, "Updating claim and contentions")) - .process( - MasIntegrationProcessors.completionProcessor(bipClaimService, masProcessingService)) - .to(ExchangePattern.InOnly, BgsApiClientRoutes.ADD_BGS_NOTES) - .log("completionSlackMessages: ${exchangeProperty.completionSlackMessages}") - .choice() - .when(simple("${exchangeProperty.completionSlackMessages} != null")) - .wireTap(ENDPOINT_NOTIFY_AUDIT) - .onPrepare( - MasIntegrationProcessors.slackEventArrayProcessor(routeId, "completionSlackMessages")) - .endChoice() - .otherwise() - .wireTap(ENDPOINT_AUDIT_WIRETAP) - .onPrepare(auditProcessor(routeId, "Successful processing")) - .end(); - } - - private void configureNotify() { - from(ENDPOINT_NOTIFY_AUDIT) - .routeId("vro-notify") - .multicast() - .to(ENDPOINT_SLACK_EVENT) - .to(ENDPOINT_AUDIT_EVENT); - } - - private void configureExamOrderSlack() { - var routeId = "exam-order-slack"; - from(ENDPOINT_EXAM_ORDER_SLACK).routeId(routeId).wireTap(ENDPOINT_NOTIFY_AUDIT); - } - - /** Configure auditing. */ - public void configureAuditing() { - String transformUri = "seda:audit-transform?multipleConsumers=true"; - - // Capture exceptions - onException(Throwable.class) - .filter(exchange -> exchange.getMessage().getBody() instanceof Auditable) - .setProperty("originalRouteId", simple("${exchange.fromRouteId}")) - .setProperty("recipientList", constant(ENDPOINT_AUDIT_EVENT, ENDPOINT_SLACK_EVENT)) - .to(transformUri); - - // Capture audit events - from(ENDPOINT_AUDIT_WIRETAP) - .process( - exchange -> { - AuditEvent event = exchange.getMessage().getBody(AuditEvent.class); - auditEventService.logEvent(event); - }); - - // Transform to an AuditEvent and send to recipients - from(transformUri) - .process(new ExchangeAuditTransformer()) - .recipientList(exchangeProperty("recipientList")); - - // persist audit event - from(ENDPOINT_AUDIT_EVENT) - .process( - exchange -> { - AuditEvent event = exchange.getMessage().getBody(AuditEvent.class); - auditEventService.logEvent(event); - }); - - String webhook = masConfig.getSlackExceptionWebhook(); - String channel = masConfig.getSlackExceptionChannel(); - String slackRoute = String.format("slack:#%s?webhookUrl=%s", channel, webhook); - log.info("Routing to slack: {}", slackRoute); - from(ENDPOINT_SLACK_EVENT) - .routeId("mas-slack-event") - .filter(exchange -> StringUtils.isNotBlank(webhook)) - .process(FunctionProcessor.fromFunction(AuditEvent::toString)) - .to(slackRoute); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/PrimaryRoutes.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/PrimaryRoutes.java deleted file mode 100644 index a036777ff6..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/PrimaryRoutes.java +++ /dev/null @@ -1,85 +0,0 @@ -package gov.va.vro.service.provider.camel; - -import gov.va.vro.camel.FunctionProcessor; -import gov.va.vro.camel.RabbitMqCamelUtils; -import gov.va.vro.camel.ToRabbitMqRouteHelper; -import gov.va.vro.service.provider.camel.processor.AssessmentResultProcessor; -import gov.va.vro.service.provider.camel.processor.EvidenceSummaryDocumentProcessor; -import gov.va.vro.service.spi.db.SaveToDbService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.builder.RouteBuilder; -import org.springframework.stereotype.Component; - -/** Defines primary routes. */ -@Slf4j -@Component -@RequiredArgsConstructor -public class PrimaryRoutes extends RouteBuilder { - public static final String ENDPOINT_SUBMIT_CLAIM_FULL = "direct:claim-submit-full"; - public static final String ENDPOINT_GENERATE_PDF = "direct:generate-pdf"; - public static final String ENDPOINT_FETCH_PDF = "direct:fetch-pdf"; - public static final String ENDPOINT_GENERATE_FETCH_PDF = "direct:generate-fetch-pdf"; - - private static final String PDF_EXCHANGE = "pdf-generator"; - private static final String GENERATE_PDF_QUEUE = "generate-pdf"; - private static final String FETCH_PDF_QUEUE = "fetch-pdf"; - private static final String GENERATE_FETCH_PDF_QUEUE = "generate-fetch-pdf"; - - // Base names for wiretap endpoints - public static final String INCOMING_CLAIM_WIRETAP = "claim-submitted"; - public static final String GENERATE_PDF_WIRETAP = "generate-pdf"; - - private final SaveToDbService saveToDbService; - - private final AssessmentResultProcessor assessmentResultProcessor; - private final EvidenceSummaryDocumentProcessor evidenceSummaryDocumentProcessor; - private final SlipClaimSubmitRouter slipClaimSubmitRouter; - - @Override - public void configure() throws Exception { - configureRouteClaimSubmitForFull(); - configureRouteGeneratePdf(); - configureRouteFetchPdf(); - configureRouteimmediatePdf(); - } - - private void configureRouteClaimSubmitForFull() { - // send JSON-string payload to RabbitMQ - from(ENDPOINT_SUBMIT_CLAIM_FULL) - .routeId("claim-submit-full") - .wireTap(RabbitMqCamelUtils.wiretapProducer(this, INCOMING_CLAIM_WIRETAP)) - .process(FunctionProcessor.fromFunction(saveToDbService::insertClaim)) - // Use Properties not Headers - // https://examples.javacodegeeks.com/apache-camel-headers-vs-properties-example/ - .setProperty("diagnosticCode", simple("${body.diagnosticCode}")) - .setProperty("claim-id", simple("${body.recordId}")) - .routingSlip(method(slipClaimSubmitRouter, "routeClaimSubmit")) - .routingSlip(method(slipClaimSubmitRouter, "routeHealthAssess")) - .process(assessmentResultProcessor); - } - - private void configureRouteGeneratePdf() { - from(ENDPOINT_GENERATE_PDF) - .routeId("generate-pdf") - .wireTap(RabbitMqCamelUtils.wiretapProducer(this, GENERATE_PDF_WIRETAP)) - .process(evidenceSummaryDocumentProcessor) - .to(pdfRoute(GENERATE_PDF_QUEUE)); - } - - private void configureRouteFetchPdf() { - from(ENDPOINT_FETCH_PDF).routeId("fetch-pdf").to(pdfRoute(FETCH_PDF_QUEUE)); - } - - private void configureRouteimmediatePdf() { - from(ENDPOINT_GENERATE_FETCH_PDF) - .routeId("generate-fetch-pdf") - .to(pdfRoute(GENERATE_FETCH_PDF_QUEUE)); - } - - private String pdfRoute(String queueName) { - String uri = "direct:rabbitmq-" + queueName; - new ToRabbitMqRouteHelper(this, uri).toMq(PDF_EXCHANGE, queueName).createRoute(); - return uri; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/RedisRoutes.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/RedisRoutes.java deleted file mode 100644 index 721a75248d..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/RedisRoutes.java +++ /dev/null @@ -1,51 +0,0 @@ -package gov.va.vro.service.provider.camel; - -import gov.va.vro.camel.RabbitMqCamelUtils; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.redis.RedisConstants; -import org.apache.camel.model.RouteDefinition; -import org.apache.camel.support.builder.ValueBuilder; -import org.springframework.stereotype.Component; - -@Component -class RedisRoutes extends RouteBuilder { - - // https://camel.apache.org/manual/faq/how-do-i-configure-endpoints.html#HowdoIconfigureendpoints-ReferringbeansfromEndpointURIs - // `bean:redisTemplate` is provided by RedisConnectionConfig.redisTemplate() - static final String REDIS_ENDPOINT = "spring-redis://?redisTemplate=#bean:redisTemplate"; - - @Override - public void configure() throws Exception { - // for v1 - saveToRedis(PrimaryRoutes.INCOMING_CLAIM_WIRETAP, "claimSubmissionId", "submitted-claim"); - saveToRedis(PrimaryRoutes.GENERATE_PDF_WIRETAP, "claimSubmissionId", "submitted-pdf"); - - // for v2 - saveToRedis(MasIntegrationRoutes.MAS_CLAIM_WIRETAP, "collectionId", "mas-claim"); - saveToRedis( - MasIntegrationRoutes.EXAM_ORDER_STATUS_WIRETAP, "collectionId", "exam-order-status"); - } - - private void saveToRedis(String tapBasename, String idField, String hashKey) throws Exception { - RouteDefinition routeDef = - from(RabbitMqCamelUtils.wiretapConsumer("redis", tapBasename)) - .routeId("redis-" + tapBasename); - appendRedisCommand(routeDef, "HSET", redisKey(idField), hashKey).to(REDIS_ENDPOINT); - } - - private ValueBuilder redisKey(String idField) { - return constant("tracking-").append(jsonpath("." + idField)); - } - - private RouteDefinition appendRedisCommand( - RouteDefinition routeDef, String command, ValueBuilder redisKey, String hashKey) { - return routeDef - .setHeader(RedisConstants.COMMAND, constant(command)) - // the Redis key where hash is stored - .setHeader(RedisConstants.KEY, redisKey) - // hash key - .setHeader(RedisConstants.FIELD, constant(hashKey)) - // hash value as a String b/c redisTemplate's defaultSerializer is StringRedisSerializer - .setHeader(RedisConstants.VALUE, body().convertToString()); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/SaveToFileRoutes.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/SaveToFileRoutes.java deleted file mode 100644 index 8082bb2860..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/SaveToFileRoutes.java +++ /dev/null @@ -1,65 +0,0 @@ -package gov.va.vro.service.provider.camel; - -import gov.va.vro.camel.RabbitMqCamelUtils; -import gov.va.vro.service.provider.ServiceProviderConfig; -import lombok.RequiredArgsConstructor; -import org.apache.camel.Exchange; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.support.builder.ValueBuilder; -import org.springframework.stereotype.Component; - -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Paths; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; - -@RequiredArgsConstructor -@Component -class SaveToFileRoutes extends RouteBuilder { - - final ServiceProviderConfig config; - - @Override - public void configure() { - if (config.persistTrackingEnabled) { - // checks if folder is writeable - logToFile("VRO started"); - - // for v1 - saveRequestToFile(PrimaryRoutes.INCOMING_CLAIM_WIRETAP, "claimSubmissionId"); - saveRequestToFile(PrimaryRoutes.GENERATE_PDF_WIRETAP, "claimSubmissionId"); - - // for v2 - saveRequestToFile(MasIntegrationRoutes.MAS_CLAIM_WIRETAP, "collectionId"); - saveRequestToFile(MasIntegrationRoutes.EXAM_ORDER_STATUS_WIRETAP, "collectionId"); - } - } - - private void logToFile(String fileContents) { - DateFormat df = new SimpleDateFormat("yyyy-MM-dd-HHmmss"); - String filename = df.format(Calendar.getInstance().getTime()); - var path = Paths.get(config.baseTrackingFolder, filename); - try (PrintWriter printWriter = new PrintWriter(new FileWriter(path.toFile()))) { - printWriter.println(fileContents); - } catch (IOException e) { - log.error("Cannot write to " + config.baseTrackingFolder, e); - } - } - - private void saveRequestToFile(String tapBasename, String idField) { - var mqUri = RabbitMqCamelUtils.wiretapConsumer("toFile", tapBasename); - RabbitMqCamelUtils.fromRabbitmq(this, mqUri) - .routeId("saveToFile-" + tapBasename) - .setHeader(Exchange.FILE_NAME, filepath(idField)) - .to("file:" + Paths.get(config.baseTrackingFolder, tapBasename)) - .log("savedRequestToFile: ${headers}"); - } - - private ValueBuilder filepath(String idField) { - // https://camel.apache.org/components/3.18.x/languages/file-language.html - return simple("${date:now:yyyy-MM-dd}/").append(jsonpath("." + idField)).append(".json"); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/SlipClaimSubmitRouter.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/SlipClaimSubmitRouter.java deleted file mode 100644 index a7d0dcd5a2..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/SlipClaimSubmitRouter.java +++ /dev/null @@ -1,91 +0,0 @@ -package gov.va.vro.service.provider.camel; - -import gov.va.vro.service.provider.utils.DiagnosisLookup; -import gov.va.vro.service.spi.model.Claim; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.ExchangeProperties; -import org.springframework.stereotype.Component; - -import java.util.Map; - -/** - * Used by ClaimProcessorRoute to dynamically route claim to endpoints depending on claim - * attributes. https://camel.apache.org/components/3.11.x/eips/dynamicRouter-eip.html. - */ -@Slf4j -@Component -public class SlipClaimSubmitRouter { - - private static final long DEFAULT_REQUEST_TIMEOUT = 120000; - public static final String NO_DIAGNOSTIC_CODE_ERROR = "No diagnostic code in properties."; - - /** - * Computes endpoint where claim should be routed next. - * - * @param claim the message body - * @return endpoints to go, or null to indicate the end - */ - public String routeClaimSubmit(Claim claim) { - String diagnosis = DiagnosisLookup.getDiagnosis(claim.getDiagnosticCode()).toLowerCase(); - String route = - String.format( - "rabbitmq:claim-submit-exchange?queue=claim-submit&" - + "routingKey=code.%s&requestTimeout=%d", - diagnosis, DEFAULT_REQUEST_TIMEOUT); - log.info( - "Routing to {} for claim {} in collection {}", - route, - claim.getBenefitClaimId(), - claim.getCollectionId()); - return route; - } - - /** - * Computes endpoint where health data should be routed next. - * - * @param body the message body - * @param props the exchange properties where we can store state between invocations - * @return endpoints to go, or null to indicate the end - */ - @SneakyThrows - public String routeHealthAssess(Object body, @ExchangeProperties Map props) { - String diagnosticCode = getDiagnosticCode(props); - String diagnosis = DiagnosisLookup.getDiagnosis(diagnosticCode).toLowerCase(); - String route = - String.format( - "rabbitmq:health-assess-exchange?routingKey=health-assess.%s&requestTimeout=%d", - diagnosis, DEFAULT_REQUEST_TIMEOUT); - log.info("Routing to {}.", route); - return route; - } - - /** - * Route health sufficiency. - * - * @param body body object - * @param props exchange properties map - * @return string - */ - @SneakyThrows - public String routeHealthSufficiency(Object body, @ExchangeProperties Map props) { - String diagnosticCode = getDiagnosticCode(props); - String diagnosis = DiagnosisLookup.getDiagnosis(diagnosticCode).toLowerCase(); - String route = - String.format( - "rabbitmq:health-assess-exchange?routingKey=health" - + "-sufficiency-assess.%s&requestTimeout=%d", - diagnosis, DEFAULT_REQUEST_TIMEOUT); - log.info("Routing to {}.", route); - return route; - } - - private static String getDiagnosticCode(Map props) { - Object diagnosticCodeObj = props.get("diagnosticCode"); - if (diagnosticCodeObj == null) { - log.error(NO_DIAGNOSTIC_CODE_ERROR); - throw new CamelProcessingException(NO_DIAGNOSTIC_CODE_ERROR); - } - return diagnosticCodeObj.toString(); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/AssessmentResultProcessor.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/AssessmentResultProcessor.java deleted file mode 100644 index 7dffb02949..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/AssessmentResultProcessor.java +++ /dev/null @@ -1,39 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.service.spi.db.SaveToDbService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.springframework.stereotype.Component; - -import java.util.UUID; - -@Component -@RequiredArgsConstructor -@Slf4j -public class AssessmentResultProcessor implements Processor { - - private final SaveToDbService saveToDbService; - - @Override - public void process(Exchange exchange) { - UUID claimId = exchange.getProperty("claim-id", UUID.class); - if (claimId == null) { - log.warn("Claim Id was empty, exiting"); - return; - } - String diagnosticCode = exchange.getProperty("diagnosticCode", String.class); - if (diagnosticCode == null) { - log.warn("Diagnostic Code was empty, exiting."); - return; - } - AbdEvidenceWithSummary evidence = exchange.getIn().getBody(AbdEvidenceWithSummary.class); - if (evidence == null) { - log.warn("Evidence was empty, exiting"); - return; - } - saveToDbService.insertAssessmentResult(claimId, evidence, diagnosticCode); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/EvidenceSummaryDocumentProcessor.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/EvidenceSummaryDocumentProcessor.java deleted file mode 100644 index dddc202627..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/EvidenceSummaryDocumentProcessor.java +++ /dev/null @@ -1,46 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import gov.va.vro.service.provider.utils.DiagnosisLookup; -import gov.va.vro.service.spi.db.SaveToDbService; -import gov.va.vro.service.spi.model.GeneratePdfPayload; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -@Slf4j -public class EvidenceSummaryDocumentProcessor implements Processor { - private final SaveToDbService saveToDbService; - - @Override - public void process(Exchange exchange) { - // String body = exchange.getIn().getBody(String.class); - // log.info(">>>>> exchange > body: " + body); - GeneratePdfPayload payload = exchange.getIn().getBody(GeneratePdfPayload.class); - // log.info(">>>>> exchange > payload~1: " + payload); - if (payload == null) { - log.warn("Payload is empty, returning..."); - return; - } - // log.info(">>>>> exchange > payload~2: " + Objects.toString(payload)); - String diagnosis = matchDiagnosticCode(payload.getDiagnosticCode()); - if (diagnosis == null) { - log.warn("Could not match diagnostic code with a diagnosis, exiting."); - return; - } - saveToDbService.insertEvidenceSummaryDocument( - payload, GeneratePdfPayload.createPdfFilename(diagnosis)); - } - - private String matchDiagnosticCode(String diagnosticCode) { - String diagnosis = DiagnosisLookup.getDiagnosis(diagnosticCode); - if (diagnosis == null) { - log.warn("Could not match diagnostic code with a diagnosis, exiting."); - return null; - } - return diagnosis; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/HealthEvidenceProcessor.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/HealthEvidenceProcessor.java deleted file mode 100644 index f63f3dc0b7..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/HealthEvidenceProcessor.java +++ /dev/null @@ -1,61 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.model.rrd.ServiceLocation; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; - -import java.util.Collections; -import java.util.List; - -@Slf4j -public class HealthEvidenceProcessor implements Processor { - - /** Set the flag "sufficient for fast-tracking". */ - @Override - public void process(Exchange exchange) { - MasProcessingObject masTransferObject = (MasProcessingObject) exchange.getProperty("payload"); - List serviceLocations = - (List) exchange.getProperty("serviceLocations"); - List docsWoutAnnotsChecked = - (List) exchange.getProperty("docsWoutAnnotsChecked"); - - AbdEvidenceWithSummary evidence = exchange.getMessage().getBody(AbdEvidenceWithSummary.class); - - masTransferObject.setSufficientForFastTracking(evidence.getSufficientForFastTracking()); - log.info( - " MAS Processing >> Sufficient Evidence >>> " + evidence.getSufficientForFastTracking()); - - // Transfer service locations. Assessment does not populate that one. - AbdEvidence currentEvidenceData = evidence.getEvidence(); - currentEvidenceData.setServiceLocations(serviceLocations); - currentEvidenceData.setDocumentsWithoutAnnotationsChecked(docsWoutAnnotsChecked); - - masTransferObject.setEvidence(getValidEvidence(currentEvidenceData)); - exchange.getMessage().setBody(masTransferObject); - } - - /** - * The list must be provided to the PDF processor, even if they are empty. Otherwise, it will fail - * to process - */ - private AbdEvidence getValidEvidence(AbdEvidence evidence) { - var validEvidence = new AbdEvidence(); - validEvidence.setConditions(emptyIfNull(evidence.getConditions())); - validEvidence.setMedications(emptyIfNull(evidence.getMedications())); - validEvidence.setBloodPressures(emptyIfNull(evidence.getBloodPressures())); - validEvidence.setProcedures(emptyIfNull(evidence.getProcedures())); - validEvidence.setServiceLocations(emptyIfNull(evidence.getServiceLocations())); - List docsWoutAnnotsChecked = evidence.getDocumentsWithoutAnnotationsChecked(); - validEvidence.setDocumentsWithoutAnnotationsChecked(emptyIfNull(docsWoutAnnotsChecked)); - - return validEvidence; - } - - private List emptyIfNull(List list) { - return list == null ? Collections.emptyList() : list; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/LighthouseErrCheckProcessor.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/LighthouseErrCheckProcessor.java deleted file mode 100644 index a0286207a3..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/LighthouseErrCheckProcessor.java +++ /dev/null @@ -1,28 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import gov.va.vro.model.rrd.HealthDataAssessment; -import gov.va.vro.service.provider.ExternalCallException; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -@Slf4j -public class LighthouseErrCheckProcessor implements Processor { - @Override - @SneakyThrows - public void process(Exchange exchange) { - - HealthDataAssessment hda = exchange.getMessage().getBody(HealthDataAssessment.class); - - if (hda.getErrorMessage() != null) { - log.error("Health Data Assessment sent back with error : {}", hda.getErrorMessage()); - throw new ExternalCallException(hda.getErrorMessage()); - } - // Else processing should continue do not alter the exchange body or properties - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasAccessErrProcessor.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasAccessErrProcessor.java deleted file mode 100644 index dc17165c44..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasAccessErrProcessor.java +++ /dev/null @@ -1,31 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import gov.va.vro.service.provider.mas.MasException; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -@Slf4j -public class MasAccessErrProcessor implements Processor { - - @Override - @SneakyThrows - public void process(Exchange exchange) { - var claimPayload = exchange.getMessage().getBody(MasProcessingObject.class); - - log.info("Off Ramp : Sufficiency can't be determined {}.", claimPayload.getCollectionId()); - try { - // TODO: Why would this throw a MasException? Why is "OffRampAccessError" needed? - exchange.setProperty("OffRampAccessError", "OffRampSufficiencyNull"); - } catch (MasException e) { - log.error("Error in calling MasAccessErrProcessor ", e); - throw new MasException("Error in MasAccessErrProcessor ", e); - } - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasAssessmentResultProcessor.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasAssessmentResultProcessor.java deleted file mode 100644 index ccc0b01396..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasAssessmentResultProcessor.java +++ /dev/null @@ -1,30 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.service.spi.db.SaveToDbService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -@Slf4j -public class MasAssessmentResultProcessor implements Processor { - - private final SaveToDbService saveToDbService; - - @Override - public void process(Exchange exchange) throws Exception { - var evidence = exchange.getMessage().getBody(AbdEvidenceWithSummary.class); - String diagnosticCode = exchange.getProperty("diagnosticCode", String.class); - String idType = exchange.getProperty("idType", String.class); - evidence.setIdType(idType); - if (diagnosticCode == null) { - log.warn("Diagnostic Code was empty, exiting."); - return; - } - saveToDbService.insertAssessmentResult(evidence, diagnosticCode); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasIntegrationProcessors.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasIntegrationProcessors.java deleted file mode 100644 index 3667fddeb1..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasIntegrationProcessors.java +++ /dev/null @@ -1,281 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.camel.FunctionProcessor; -import gov.va.vro.model.rrd.HealthAssessmentSource; -import gov.va.vro.model.rrd.HealthDataAssessment; -import gov.va.vro.model.rrd.VeteranInfo; -import gov.va.vro.model.rrd.event.AuditEvent; -import gov.va.vro.model.rrd.event.Auditable; -import gov.va.vro.model.rrd.event.EventReason; -import gov.va.vro.model.rrd.mas.ClaimCondition; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.response.FetchPdfResponse; -import gov.va.vro.service.provider.bip.BipException; -import gov.va.vro.service.provider.bip.service.BipClaimService; -import gov.va.vro.service.provider.bip.service.BipUpdateClaimResult; -import gov.va.vro.service.provider.mas.MasCamelStage; -import gov.va.vro.service.provider.mas.MasCompletionStatus; -import gov.va.vro.service.provider.mas.MasException; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import gov.va.vro.service.provider.mas.service.MasCollectionService; -import gov.va.vro.service.provider.mas.service.MasProcessingService; -import gov.va.vro.service.spi.model.Claim; -import gov.va.vro.service.spi.model.GeneratePdfPayload; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.function.Function; - -/** Helper processors for Mas Integration. */ -@Slf4j -public class MasIntegrationProcessors { - - public static Processor convertToMasProcessingObject() { - return FunctionProcessor.fromFunction( - (Function) - payload -> new MasProcessingObject(payload, MasCamelStage.DURING_PROCESSING)); - } - - public static Processor combineExchangesProcessor() { - return FunctionProcessor.fromFunction(combineExchangesFunction()); - } - - private static Function, HealthDataAssessment> combineExchangesFunction() { - return exchanges -> { - for (Exchange exchange : exchanges) { - if (exchange.isFailed()) { - throw new MasException( - "Failed to collect evidence", exchange.getException(Throwable.class)); - } - } - Exchange exchange1 = exchanges.get(0); - Exchange exchange2 = exchanges.get(1); - var evidence1 = exchange1.getMessage().getBody(HealthDataAssessment.class); - var evidence2 = exchange2.getMessage().getBody(HealthDataAssessment.class); - return MasCollectionService.combineEvidence(evidence1, evidence2); - }; - } - - /** - * Processor that turns payload to claim. - * - * @return return - */ - public static Processor payloadToClaimProcessor() { - return FunctionProcessor.fromFunction( - (Function) - payload -> - Claim.builder() - .benefitClaimId(payload.getBenefitClaimId()) - .collectionId(String.valueOf(payload.getCollectionId())) - .idType(payload.getIdType()) - .diagnosticCode(payload.getDiagnosticCode()) - .veteranIcn(payload.getVeteranIcn()) - .build()); - } - - public static Processor convertToPdfResponse() { - return exchange -> { - String response = exchange.getMessage().getBody(String.class); - var pdfResponse = new ObjectMapper().readValue(response, FetchPdfResponse.class); - exchange.getMessage().setBody(pdfResponse); - }; - } - - public static Processor generatePdfProcessor() { - return FunctionProcessor.fromFunction(MasIntegrationProcessors::getGeneratePdfPayload); - } - - private static GeneratePdfPayload getGeneratePdfPayload(MasProcessingObject transferObject) { - MasAutomatedClaimPayload claimPayload = transferObject.getClaimPayload(); - GeneratePdfPayload generatePdfPayload = new GeneratePdfPayload(); - generatePdfPayload.setEvidence(transferObject.getEvidence()); - generatePdfPayload.setClaimSubmissionId(String.valueOf(claimPayload.getCollectionId())); - generatePdfPayload.setIdType(transferObject.getIdType()); - generatePdfPayload.setPdfTemplate("v2"); - generatePdfPayload.setDiagnosticCode( - claimPayload.getClaimDetail().getConditions().getDiagnosticCode()); - VeteranInfo veteranInfo = new VeteranInfo(); - veteranInfo.setFirst(claimPayload.getFirstName()); - veteranInfo.setLast(claimPayload.getLastName()); - veteranInfo.setMiddle(""); - veteranInfo.setBirthdate(claimPayload.getDateOfBirth()); - String fileId = claimPayload.getVeteranIdentifiers().getVeteranFileId(); - generatePdfPayload.setVeteranFileId(fileId); - generatePdfPayload.setVeteranInfo(veteranInfo); - - String disabilityActionType = transferObject.getDisabilityActionType(); - if (disabilityActionType != null) { - ClaimCondition condition = new ClaimCondition(); - condition.setDisabilityActionType(disabilityActionType); - String conditionName = transferObject.getConditionName(); - if (conditionName == null) { - conditionName = "Not Available"; - } - condition.setName(conditionName); - generatePdfPayload.setConditions(condition); - } - - log.info( - "Generating pdf for claim: {} and diagnostic code {}", - generatePdfPayload.getClaimSubmissionId(), - generatePdfPayload.getDiagnosticCode()); - return generatePdfPayload; - } - - public static Processor auditProcessor(String routeId, String message) { - return exchange -> { - var auditable = exchange.getMessage().getBody(Auditable.class); - exchange.getIn().setBody(AuditEvent.fromAuditable(auditable, routeId, message)); - }; - } - - public static Processor auditProcessor( - String routeId, Function messageExtractor) { - return exchange -> { - var auditable = exchange.getMessage().getBody(Auditable.class); - String message = messageExtractor.apply(auditable); - exchange.getIn().setBody(AuditEvent.fromAuditable(auditable, routeId, message)); - }; - } - - public static Processor setOffRampReasonProcessor(String offRampReasonCode) { - return exchange -> { - MasProcessingObject mpoOfframp = exchange.getMessage().getBody(MasProcessingObject.class); - mpoOfframp.getClaimPayload().setOffRampReason(offRampReasonCode); - exchange.getMessage().setBody(mpoOfframp); - }; - } - - /** - * At the conclusion of automated claim processing this processor updates claims and contentions - * using BIP Claims API. - * - * @param bipClaimService - * @return Processor completion camel processor - */ - public static Processor completionProcessor( - BipClaimService bipClaimService, MasProcessingService masProcessingService) { - return exchange -> { - MasProcessingObject payload = exchange.getIn().getBody(MasProcessingObject.class); - - MasCamelStage origin = payload.getOrigin(); - String offRampErrorPayload = payload.getOffRampReason(); - ArrayList completionSlackMessages = new ArrayList<>(); - - // Update our database with offramp reason. - if (offRampErrorPayload != null) { - masProcessingService.offRampClaimForError(payload, offRampErrorPayload); - completionSlackMessages.add(offRampErrorPayload); - } - MasCompletionStatus completionStatus = - MasCompletionStatus.of( - origin, payload.getSufficientForFastTracking(), offRampErrorPayload); - try { - BipUpdateClaimResult result = bipClaimService.updateClaim(payload, completionStatus); - if (result.hasMessage()) { - completionSlackMessages.add(result.getMessage()); - } - } catch (BipException exception) { - log.error("Error using BIP Claims API", exception); - String slackMsg = - String.format( - "reason code: %s, narrative:%s. ", - EventReason.BIP_UPDATE_FAILED.getCode(), - EventReason.BIP_UPDATE_FAILED.getNarrative()); - String message = slackMsg + "BIP Claims API exception: " + exception.getMessage(); - completionSlackMessages.add(message); - } finally { - exchange.setProperty("completionSlackMessages", completionSlackMessages); - } - }; - } - - public static Processor slackEventProcessor(String routeId, String message) { - return exchange -> { - MasProcessingObject masProcessingObject = - exchange.getMessage().getBody(MasProcessingObject.class); - exchange - .getIn() - .setBody( - AuditEvent.fromAuditable( - masProcessingObject, routeId, getSlackMessage(masProcessingObject, message))); - }; - } - - public static Processor slackEventArrayProcessor(String routeId, String exchangeProperty) { - return exchange -> { - String[] messages = - exchange.getProperty(exchangeProperty, "Unidentified message", String[].class); - MasProcessingObject masProcessingObject = - exchange.getMessage().getBody(MasProcessingObject.class); - - String[] slackMessages = - Arrays.stream(messages) - .map(message -> getSlackMessage(masProcessingObject, message)) - .toArray(String[]::new); - - exchange - .getIn() - .setBody(AuditEvent.fromAuditable(masProcessingObject, routeId, slackMessages)); - }; - } - - // Used for inline grabbing of errors that need to go to audit and slack, but the - // MasProcessingObject was stored - // not in the body at that point in the code. - public static Processor slackEventPropertyProcessor( - String routeId, String message, String exchangeProperty) { - return exchange -> { - MasProcessingObject masProcessingObject = - exchange.getProperty(exchangeProperty, MasProcessingObject.class); - exchange - .getIn() - .setBody( - AuditEvent.fromAuditable( - masProcessingObject, routeId, getSlackMessage(masProcessingObject, message))); - }; - } - - public static String getSlackMessage(MasProcessingObject mpo, String originalMessage) { - String msg = originalMessage; - EventReason reason = EventReason.getEventReason(originalMessage.trim()); - if (reason != null) { - msg = reason.getReasonMessage(); - } - if (mpo != null) { - msg += - String.format( - " claim ID: %s, collection ID: %s", mpo.getBenefitClaimId(), mpo.getCollectionId()); - } - return msg; - } - - /** - * This sets up a skeleton lighthouse HealthDataAsessment object in the event of a timeout from - * lighthouse. We know the fields we MUST have for evidence merge from the properties we saved on - * the exchange. - * - *

We do this because of the request here - * https://github.com/department-of-veterans-affairs/abd-vro/issues/1314 That asks us to continue - * processing as if nothing has gone wrong in this case other than notifying slack. - * - * @return - */ - public static Processor lighthouseContinueProcessor() { - return exchange -> { - MasProcessingObject mpo = exchange.getProperty("payload", MasProcessingObject.class); - HealthDataAssessment hda = new HealthDataAssessment(); - hda.setSource(HealthAssessmentSource.LIGHTHOUSE); - hda.setDiagnosticCode(mpo.getDiagnosticCode()); - hda.setClaimSubmissionId(Integer.toString(mpo.getCollectionId())); - hda.setVeteranIcn(mpo.getVeteranIcn()); - exchange.getMessage().setBody(hda); - }; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasOrderExamProcessor.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasOrderExamProcessor.java deleted file mode 100644 index f5dcafedfc..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasOrderExamProcessor.java +++ /dev/null @@ -1,66 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.MasOrderExamConditions; -import gov.va.vro.model.rrd.mas.request.MasOrderExamRequest; -import gov.va.vro.service.provider.mas.MasException; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import gov.va.vro.service.provider.mas.service.IMasApiService; -import gov.va.vro.service.spi.db.SaveToDbService; -import gov.va.vro.service.spi.model.ExamOrder; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Map; - -@Component -@RequiredArgsConstructor -@Slf4j -public class MasOrderExamProcessor implements Processor { - - private final IMasApiService masApiService; - - private static final Map MAS_CONDITION_CODES = - Map.of("7101", "HYPERTENSION", "6602", "ASTHMA"); - - private static final String SUBMITTED_STATUS = "ORDER_SUBMITTED"; - private final SaveToDbService saveToDbService; - - @Override - @SneakyThrows - public void process(Exchange exchange) { - - var claimPayload = exchange.getMessage().getBody(MasProcessingObject.class); - - log.info("Ordering Exam for the collection {}.", claimPayload.getCollectionId()); - try { - MasOrderExamRequest masOrderExamRequest = new MasOrderExamRequest(); - masOrderExamRequest.setCollectionsId(claimPayload.getCollectionId()); - MasOrderExamConditions masOrderExamConditions = new MasOrderExamConditions(); - masOrderExamConditions.setConditionCode( - MAS_CONDITION_CODES.getOrDefault(claimPayload.getDiagnosticCode(), "NA")); - masOrderExamConditions.setContentionText( - MAS_CONDITION_CODES.getOrDefault(claimPayload.getDiagnosticCode(), "NA")); - masOrderExamRequest.setConditions(List.of(masOrderExamConditions)); - var response = masApiService.orderExam(masOrderExamRequest); - log.info("Order Exam Response : " + response + " saving as ORDER_SUBMITTED"); - ExamOrder examOrder = - ExamOrder.builder() - .collectionId(Integer.toString(claimPayload.getCollectionId())) - .idType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE) - .status(SUBMITTED_STATUS) - .build(); - saveToDbService.insertOrUpdateExamOrderingStatus(examOrder); - exchange.setProperty("orderExamResponse", response); - - } catch (MasException e) { - log.error("Error in calling Order Exam API ", e); - throw new MasException("Error in Order Exam API ", e); - } - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasPollingProcessor.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasPollingProcessor.java deleted file mode 100644 index 37cb84ab12..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/MasPollingProcessor.java +++ /dev/null @@ -1,62 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.service.provider.CamelEntrance; -import gov.va.vro.service.provider.MasConfig; -import gov.va.vro.service.provider.camel.MasIntegrationRoutes; -import gov.va.vro.service.provider.mas.MasException; -import gov.va.vro.service.provider.mas.service.MasCollectionService; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -@Slf4j -public class MasPollingProcessor implements Processor { - private static final String MAS_RETRY_LIMIT_PASSED = - "MAS Processing did not complete. Maximum reties exceeded."; - private final CamelEntrance camelEntrance; - private final MasConfig masDelays; - private final MasCollectionService masCollectionService; - - @Override - @SneakyThrows - public void process(Exchange exchange) { - int retryCounts = (int) exchange.getMessage().getHeader(MasIntegrationRoutes.MAS_RETRY_PARAM); - var claimPayload = exchange.getMessage().getBody(MasAutomatedClaimPayload.class); - if (retryCounts == 0) { - String msg = - String.format( - "%s Collection ID: %s, Claim ID: %s", - MAS_RETRY_LIMIT_PASSED, - claimPayload.getCollectionId(), - claimPayload.getBenefitClaimId()); - throw new MasException(msg); - } - - boolean isCollectionReady = - masCollectionService.checkCollectionStatus(claimPayload.getCollectionId()); - log.info( - "Collection status is {} for collection ID: {}, claim ID: {}, icn: {}", - isCollectionReady, - claimPayload.getCollectionId(), - claimPayload.getBenefitClaimId(), - claimPayload.getVeteranIcn()); - - if (isCollectionReady) { - camelEntrance.processClaim(claimPayload); - } else { - log.info( - "Collection {} is not ready. Retrying... {}", - claimPayload.getCollectionId(), - retryCounts); - // re-request after some time - camelEntrance.notifyAutomatedClaim( - claimPayload, masDelays.getMasProcessingSubsequentDelay(), retryCounts - 1); - } - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/ServiceLocationsExtractorProcessor.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/ServiceLocationsExtractorProcessor.java deleted file mode 100644 index 06ca1d814e..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/camel/processor/ServiceLocationsExtractorProcessor.java +++ /dev/null @@ -1,34 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.HealthDataAssessment; -import gov.va.vro.model.rrd.ServiceLocation; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.springframework.stereotype.Component; - -import java.util.List; - -@Component -@Slf4j -public class ServiceLocationsExtractorProcessor implements Processor { - - @Override - public void process(Exchange exchange) { - try { // Late change, be defensive - HealthDataAssessment assessment = exchange.getMessage().getBody(HealthDataAssessment.class); - AbdEvidence evidence = assessment.getEvidence(); - if (evidence != null) { - List serviceLocations = evidence.getServiceLocations(); - exchange.setProperty("serviceLocations", serviceLocations); - - List docsWout = evidence.getDocumentsWithoutAnnotationsChecked(); - exchange.setProperty("docsWoutAnnotsChecked", docsWout); - } - } catch (Exception e) { - // If this happens service locations in the pdf will be empty - log.info("unable to set the service location", e); - } - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasCamelStage.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasCamelStage.java deleted file mode 100644 index 63d7c67d26..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasCamelStage.java +++ /dev/null @@ -1,6 +0,0 @@ -package gov.va.vro.service.provider.mas; - -public enum MasCamelStage { - DURING_PROCESSING, - START_COMPLETE -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasCompletionStatus.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasCompletionStatus.java deleted file mode 100644 index baea8fae2c..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasCompletionStatus.java +++ /dev/null @@ -1,45 +0,0 @@ -package gov.va.vro.service.provider.mas; - -import gov.va.vro.model.rrd.bip.ClaimStatus; -import gov.va.vro.service.provider.ClaimProps; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.util.HashSet; -import java.util.Set; - -@Getter -@RequiredArgsConstructor -public enum MasCompletionStatus { - OFF_RAMP("off-ramp", false, true, ClaimStatus.OPEN), - EXAM_ORDER("exam order", true, false, ClaimStatus.OPEN), - READY_FOR_DECISION("ready for decision", true, false, ClaimStatus.RFD); - - private final String description; - private final boolean automationIndicator; - private final boolean removeRRDSpecialIssue; - private final ClaimStatus claimStatus; - - public Set getSpecialIssuesToRemove(ClaimProps claimProps) { - Set result = new HashSet<>(); - result.add(claimProps.getSpecialIssue1()); - if (removeRRDSpecialIssue) { - result.add(claimProps.getSpecialIssue2()); - } - return result; - } - - public static MasCompletionStatus of(MasProcessingObject mpo) { - return of(mpo.getOrigin(), mpo.getSufficientForFastTracking(), mpo.getOffRampReason()); - } - - public static MasCompletionStatus of( - MasCamelStage origin, Boolean sufficientForFastTracking, String offRampError) { - if (origin == MasCamelStage.START_COMPLETE - || sufficientForFastTracking == null - || offRampError != null) { - return OFF_RAMP; - } - return sufficientForFastTracking ? READY_FOR_DECISION : EXAM_ORDER; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasException.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasException.java deleted file mode 100644 index 5932fce8d7..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasException.java +++ /dev/null @@ -1,17 +0,0 @@ -package gov.va.vro.service.provider.mas; - -/** - * Exception thrown in MAS API service. - * - * @author warren @Date 10/5/22 - */ -public class MasException extends RuntimeException { - - public MasException(String message, Throwable cause) { - super(message, cause); - } - - public MasException(String message) { - super(message); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasProcessingObject.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasProcessingObject.java deleted file mode 100644 index 4e95d4908e..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/MasProcessingObject.java +++ /dev/null @@ -1,81 +0,0 @@ -package gov.va.vro.service.provider.mas; - -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.HealthDataAssessment; -import gov.va.vro.model.rrd.event.Auditable; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import lombok.Data; -import lombok.RequiredArgsConstructor; - -import java.util.Map; - -@Data -@RequiredArgsConstructor -public class MasProcessingObject implements Auditable { - private final MasAutomatedClaimPayload claimPayload; - private final MasCamelStage origin; - private AbdEvidence evidence; - private HealthDataAssessment healthDataAssessment; - private boolean isTSOJ = false; - - private Boolean sufficientForFastTracking; - - public int getCollectionId() { - return claimPayload.getCollectionId(); - } - - // benefitClaimId (aka vbmsId) - public String getBenefitClaimId() { - return claimPayload.getClaimDetail().getBenefitClaimId(); - } - - // TODO: verify that vbmsId is always a long or check the API spec where this long is submitted - public long getBenefitClaimIdAsLong() { - String claimIdString = getBenefitClaimId(); - long claimId = Long.parseLong(claimIdString); - return claimId; - } - - public String getIdType() { - return claimPayload.getIdType(); - } - - public String getVeteranIcn() { - return claimPayload.getVeteranIcn(); - } - - public String getDiagnosticCode() { - return claimPayload.getDiagnosticCode(); - } - - @Override - public String getEventId() { - return claimPayload.getEventId(); - } - - @Override - public Map getDetails() { - return claimPayload.getDetails(); - } - - public String getDisabilityActionType() { - return claimPayload.getDisabilityActionType(); - } - - public String getConditionName() { - return claimPayload.getConditionName(); - } - - @Override - public String getDisplayName() { - return claimPayload.getDisplayName(); - } - - public String getClaimSubmissionDateTime() { - return claimPayload.getClaimDetail().getClaimSubmissionDateTime(); - } - - public String getOffRampReason() { - return claimPayload.getOffRampReason(); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/IMasApiService.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/IMasApiService.java deleted file mode 100644 index 64bb19af12..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/IMasApiService.java +++ /dev/null @@ -1,16 +0,0 @@ -package gov.va.vro.service.provider.mas.service; - -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import gov.va.vro.model.rrd.mas.MasCollectionStatus; -import gov.va.vro.model.rrd.mas.request.MasOrderExamRequest; -import gov.va.vro.service.provider.mas.MasException; - -import java.util.List; - -public interface IMasApiService { - List getMasCollectionStatus(List collectionIds) throws MasException; - - List getCollectionAnnotations(Integer collectionId) throws MasException; - - String orderExam(MasOrderExamRequest masOrderExamRequest) throws MasException; -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasApiService.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasApiService.java deleted file mode 100644 index e095685e62..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasApiService.java +++ /dev/null @@ -1,159 +0,0 @@ -package gov.va.vro.service.provider.mas.service; - -import static java.util.Objects.isNull; - -import com.fasterxml.jackson.core.JsonGenerationException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import gov.va.vro.model.rrd.mas.MasCollectionStatus; -import gov.va.vro.model.rrd.mas.request.MasCollectionAnnotationRequest; -import gov.va.vro.model.rrd.mas.request.MasCollectionStatusRequest; -import gov.va.vro.model.rrd.mas.request.MasOrderExamRequest; -import gov.va.vro.service.provider.MasApiProps; -import gov.va.vro.service.provider.mas.MasException; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.security.oauth2.core.OAuth2AccessToken; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; - -import java.io.IOException; -import java.util.List; - -@Component -@RequiredArgsConstructor -@Slf4j -public class MasApiService implements IMasApiService { - - private final ObjectMapper mapper = new ObjectMapper(); - private final RestTemplate restTemplate; - private final MasAuthToken masAuthToken; - private final MasApiProps masApiProps; - - @Override - public List getMasCollectionStatus(List collectionIds) - throws MasException { - try { - String url = masApiProps.getBaseUrl() + masApiProps.getCollectionStatusPath(); - HttpHeaders headers = getMasHttpHeaders(); - List masCollectionStatusRequestList = - collectionIds.stream().map(this::statusRequest).toList(); - - HttpEntity httpEntity = - new HttpEntity<>(masCollectionStatusRequestList.get(0), headers); - - ResponseEntity masResponse = - restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); - log.info("Call {} to get MAS collection status.", url); - log.info("MAS Collection Status Response Status {}.", masResponse.getStatusCode()); - - String masReturn = masResponse.getBody(); - - log.trace("MAS Collection Status Response body {}.", masReturn); - return mapper.readValue(masReturn, new TypeReference<>() {}); - } catch (RestClientException | IOException e) { - log.error("Failed to get collection status.", e); - throw new MasException(e.getMessage(), e); - } - } - - private MasCollectionStatusRequest statusRequest(int collectionId) { - MasCollectionStatusRequest masCollectionStatusRequest = new MasCollectionStatusRequest(); - masCollectionStatusRequest.setCollectionsId(collectionId); - return masCollectionStatusRequest; - } - - @Override - public List getCollectionAnnotations(Integer collectionId) - throws MasException { - try { - String url = masApiProps.getBaseUrl() + masApiProps.getCollectionAnnotsPath(); - HttpHeaders headers = getMasHttpHeaders(); - - MasCollectionAnnotationRequest masCollectionAnnotationRequest = - new MasCollectionAnnotationRequest(); - masCollectionAnnotationRequest.setCollectionsId(collectionId); - HttpEntity httpEntity = - new HttpEntity<>(masCollectionAnnotationRequest, headers); - - ResponseEntity masResponse = - restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); - - String masReturn = masResponse.getBody(); - return mapper.readValue(masReturn, new TypeReference<>() {}); - } catch (RestClientException | IOException e) { - log.error("Failed to get collection annotations.", e); - throw new MasException(e.getMessage(), e); - } - } - - @Override - public String orderExam(MasOrderExamRequest masOrderExamRequest) throws MasException { - try { - String url = masApiProps.getBaseUrl() + masApiProps.getCreateExamOrderPath(); - ObjectMapper mapper = new ObjectMapper(); - try { - // convert user object to json string and return it - log.info("masOrderExamReq JSON : " + mapper.writeValueAsString(masOrderExamRequest)); - } catch (JsonGenerationException | JsonMappingException e) { - // catch various errors - // NOP; - } - log.info(" Exam Order >>>> API Service URL : " + url); - log.info( - " Exam Order >>>> API Service collectionsid : " - + masOrderExamRequest.getCollectionsId().toString()); - log.info( - " Exam Order >>>> API Service condition text: " - + masOrderExamRequest.getConditions().get(0).getContentionText()); - log.info( - " Exam Order >>>> API Service condition code : " - + masOrderExamRequest.getConditions().get(0).getConditionCode()); - HttpHeaders headers = getMasHttpHeaders(); - HttpEntity httpEntity = new HttpEntity<>(masOrderExamRequest, headers); - - ResponseEntity masResponse = - restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); - - JsonNode masResponseJson = new ObjectMapper().readTree(String.valueOf(masResponse.getBody())); - - String examOrderRespStatus = "success"; - if ((isNull(masResponseJson.get("success")))) { - examOrderRespStatus = "failed"; - } - return examOrderRespStatus; - } catch (RestClientException | IOException e) { - log.error("Failed to order exam", e); - // TODO: REPLACE WHEN FIXED - // Currently this MAS endpoint does not work, so mocking response in order to continue. - // return "OK"; - throw new MasException(e.getMessage(), e); - } - } - - private HttpHeaders getMasHttpHeaders() throws MasException { - HttpHeaders masHttpHeaders; - try { - // Get the MAS API Auth(JWT) Token - OAuth2AccessToken accessToken = masAuthToken.getMasApiAuthToken(); - - masHttpHeaders = new HttpHeaders(); - masHttpHeaders.setContentType(MediaType.APPLICATION_JSON); - masHttpHeaders.add("Authorization", "Bearer " + accessToken.getTokenValue()); - - } catch (Exception e) { - log.error("Failed to build MAS HTTP Headers.", e); - throw new MasException(e.getMessage(), e); - } - return masHttpHeaders; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasAuthToken.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasAuthToken.java deleted file mode 100644 index b11aae6e4c..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasAuthToken.java +++ /dev/null @@ -1,54 +0,0 @@ -package gov.va.vro.service.provider.mas.service; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.core.OAuth2AccessToken; -import org.springframework.stereotype.Component; - -import java.util.Objects; - -@Component -@RequiredArgsConstructor -@Slf4j -public class MasAuthToken { - - private static final String CLIENT_REGISTRATION_ID = "masAuthProvider"; - private static final String PRINCIPAL_NAME = "MAS Service"; - - // Inject the OAuth authorized client service and authorized client manager - // from the MasOauth2Config class (check the app folder). - private final AuthorizedClientServiceOAuth2AuthorizedClientManager - authorizedClientServiceAndManager; - - public final AuthorizedClientServiceOAuth2AuthorizedClientManager - getAuthorizedClientServiceAndManager() { - return authorizedClientServiceAndManager; - } - - // Retrieve the authorized JWT from MAS. - - /** - * Gets the MAS API token. - * - * @return token - */ - public OAuth2AccessToken getMasApiAuthToken() { - - // Build an OAuth2 request for the MAS Auth provider - OAuth2AuthorizeRequest authorizeRequest = - OAuth2AuthorizeRequest.withClientRegistrationId(CLIENT_REGISTRATION_ID) - .principal(PRINCIPAL_NAME) - .build(); - - // Perform the actual authorization request using the authorized client service and authorized - // client manager. This is where the JWT is retrieved from the MAS Auth servers. - OAuth2AuthorizedClient authorizedClient = - authorizedClientServiceAndManager.authorize(authorizeRequest); - - // Get the token from the authorized client object. - return Objects.requireNonNull(authorizedClient).getAccessToken(); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasCollectionService.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasCollectionService.java deleted file mode 100644 index a2bf51a6c3..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasCollectionService.java +++ /dev/null @@ -1,166 +0,0 @@ -package gov.va.vro.service.provider.mas.service; - -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.HealthAssessmentSource; -import gov.va.vro.model.rrd.HealthDataAssessment; -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import gov.va.vro.model.rrd.mas.MasCollectionStatus; -import gov.va.vro.model.rrd.mas.MasStatus; -import gov.va.vro.service.provider.mas.MasException; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import gov.va.vro.service.provider.mas.service.mapper.MasCollectionAnnotsResults; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -@Service -@Slf4j -@RequiredArgsConstructor -public class MasCollectionService { - - private final IMasApiService masApiService; - - /** - * Checks collection status on collection ID. - * - * @param collectionId collection ID - * @return true or false - * @throws MasException exception - */ - public boolean checkCollectionStatus(int collectionId) throws MasException { - - log.info("Checking collection status for collection {}.", collectionId); - try { - var response = masApiService.getMasCollectionStatus(Collections.singletonList(collectionId)); - log.info("Collection Status Response : response Size: " + response.size()); - for (MasCollectionStatus masCollectionStatus : response) { - log.info( - "Collection Status Response : Collection ID {} ", - masCollectionStatus.getCollectionsId()); - log.info( - "Collection Status Response : Collection Status {} ", - masCollectionStatus.getCollectionStatus()); - if ((MasStatus.VRONOTIFIED) - .equals(MasStatus.getMasStatus(masCollectionStatus.getCollectionStatus())) - || (MasStatus.PROCESSED) - .equals(MasStatus.getMasStatus(masCollectionStatus.getCollectionStatus()))) { - return true; - } - } - } catch (Exception e) { - log.error("Error in calling collection Status API ", e); - throw new MasException("Error in calling collection Status API ", e); - } - return false; - } - - /** - * Collects annotations. - * - * @param claimPayload claim - * @return health assessment - * @throws MasException exception - */ - public HealthDataAssessment collectAnnotations(MasProcessingObject claimPayload) - throws MasException { - - log.info( - "Collection {} is ready for processing, calling collection annotation service. Related claim {}, icn {}", - claimPayload.getCollectionId(), - claimPayload.getBenefitClaimId(), - claimPayload.getVeteranIcn()); - - var response = masApiService.getCollectionAnnotations(claimPayload.getCollectionId()); - if (response.isEmpty()) { - throw new MasException( - "No annotations found for collection id " + claimPayload.getCollectionId()); - } - MasCollectionAnnotation masCollectionAnnotation = response.get(0); - // Veteran File ID is PII -- do not log it. - log.info( - "Collection Annotation Response : Collection ID {}", - masCollectionAnnotation.getCollectionsId()); - - MasCollectionAnnotsResults masCollectionAnnotsResults = new MasCollectionAnnotsResults(); - AbdEvidence abdEvidence = - masCollectionAnnotsResults.mapAnnotationsToEvidence(masCollectionAnnotation); - - log.info("AbdEvidence : Medications {} ", abdEvidence.getMedications().size()); - log.info("AbdEvidence : Conditions {} ", abdEvidence.getConditions().size()); - log.info("AbdEvidence : BP {} ", abdEvidence.getBloodPressures().size()); - - HealthDataAssessment healthDataAssessment = new HealthDataAssessment(); - healthDataAssessment.setDiagnosticCode(claimPayload.getDiagnosticCode()); - healthDataAssessment.setEvidence(abdEvidence); - healthDataAssessment.setVeteranIcn(claimPayload.getVeteranIcn()); - healthDataAssessment.setClaimSubmissionDateTime(claimPayload.getClaimSubmissionDateTime()); - healthDataAssessment.setDisabilityActionType(claimPayload.getDisabilityActionType()); - healthDataAssessment.setSource(HealthAssessmentSource.MAS); - return healthDataAssessment; - } - - /** - * Combines the evidence. - * - * @return returns health assessment - */ - public static HealthDataAssessment combineEvidence( - HealthDataAssessment assessment1, HealthDataAssessment assessment2) { - var masAssessment = - HealthAssessmentSource.MAS == assessment1.getSource() ? assessment1 : assessment2; - var lighthouseAssessment = - HealthAssessmentSource.LIGHTHOUSE == assessment1.getSource() ? assessment1 : assessment2; - - AbdEvidence masApiEvidence = masAssessment.getEvidence(); - AbdEvidence lighthouseEvidence = lighthouseAssessment.getEvidence(); - - // for now, we just add up the lists - log.info("combineEvidence >> LH : " + ((lighthouseEvidence != null) ? "not null" : "null")); - log.info("combineEvidence >> MAS : " + ((masApiEvidence != null) ? "not null" : "null")); - AbdEvidence compositeEvidence = new AbdEvidence(); - compositeEvidence.setBloodPressures( - merge( - lighthouseEvidence != null ? lighthouseEvidence.getBloodPressures() : null, - masApiEvidence != null ? masApiEvidence.getBloodPressures() : null)); - compositeEvidence.setConditions( - merge( - lighthouseEvidence != null ? lighthouseEvidence.getConditions() : null, - masApiEvidence != null ? masApiEvidence.getConditions() : null)); - compositeEvidence.setMedications( - merge( - lighthouseEvidence != null ? lighthouseEvidence.getMedications() : null, - masApiEvidence != null ? masApiEvidence.getMedications() : null)); - compositeEvidence.setProcedures( - merge( - lighthouseEvidence != null ? lighthouseEvidence.getProcedures() : null, - masApiEvidence != null ? masApiEvidence.getProcedures() : null)); - if (masApiEvidence != null) { - compositeEvidence.setServiceLocations(masApiEvidence.getServiceLocations()); - List docsWout = masApiEvidence.getDocumentsWithoutAnnotationsChecked(); - compositeEvidence.setDocumentsWithoutAnnotationsChecked(docsWout); - } - HealthDataAssessment combinedAssessment = new HealthDataAssessment(); - combinedAssessment.setClaimSubmissionId(lighthouseAssessment.getClaimSubmissionId()); - combinedAssessment.setDiagnosticCode(lighthouseAssessment.getDiagnosticCode()); - combinedAssessment.setVeteranIcn(lighthouseAssessment.getVeteranIcn()); - combinedAssessment.setDisabilityActionType(masAssessment.getDisabilityActionType()); - combinedAssessment.setClaimSubmissionDateTime(masAssessment.getClaimSubmissionDateTime()); - combinedAssessment.setEvidence(compositeEvidence); - return combinedAssessment; - } - - private static List merge(List list1, List list2) { - List result = new ArrayList<>(); - if (list1 != null) { - result.addAll(list1); - } - if (list2 != null) { - result.addAll(list2); - } - return result; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasProcessingService.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasProcessingService.java deleted file mode 100644 index 74b93e0ee5..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/MasProcessingService.java +++ /dev/null @@ -1,216 +0,0 @@ -package gov.va.vro.service.provider.mas.service; - -import static gov.va.vro.service.provider.camel.MasIntegrationRoutes.IMVP_EXCHANGE; -import static gov.va.vro.service.provider.camel.MasIntegrationRoutes.NOTIFY_AUTOMATED_CLAIM_QUEUE; - -import gov.va.vro.camel.CamelEntry; -import gov.va.vro.model.rrd.event.AuditEvent; -import gov.va.vro.model.rrd.event.EventReason; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.MasExamOrderStatusPayload; -import gov.va.vro.service.provider.CamelEntrance; -import gov.va.vro.service.provider.MasConfig; -import gov.va.vro.service.provider.bip.service.BipClaimService; -import gov.va.vro.service.provider.camel.MasIntegrationRoutes; -import gov.va.vro.service.provider.mas.MasCamelStage; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import gov.va.vro.service.spi.db.SaveToDbService; -import gov.va.vro.service.spi.model.Claim; -import gov.va.vro.service.spi.model.ExamOrder; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.util.Map; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -@Service -@RequiredArgsConstructor -@Slf4j -public class MasProcessingService { - - private static final String customDateFormatRegex = - "^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])(Z)?$"; - private static final Pattern customDatePattern = Pattern.compile(customDateFormatRegex); - private final CamelEntrance camelEntrance; - - private final MasConfig masConfig; - - private final BipClaimService bipClaimService; - - private final SaveToDbService saveToDbService; - - private final CamelEntry camelEntry; - - /** - * Processes incoming claim. - * - * @param payload mas payload. - * @return String - */ - public void processIncomingClaimSaveToDB(MasAutomatedClaimPayload payload) { - log.info( - "Process MAS collection {}, claim {} , icn: {}", - payload.getCollectionId(), - payload.getBenefitClaimId(), - payload.getVeteranIcn()); - Claim claim = toClaim(payload); - saveToDbService.insertClaim(claim); - saveToDbService.insertFlashIds(payload.getVeteranFlashIds(), payload.getVeteranIcn()); - } - - public String processIncomingClaimGetUnprocessableReason(MasAutomatedClaimPayload payload) { - var unprocessableReasonOptional = getOffRampReasonScopeAndAnchorCheck(payload); - if (unprocessableReasonOptional.isPresent()) { - return unprocessableReasonOptional.get(); - } - return null; - } - - public String processIncomingClaimPresumptiveOffRampClaimCheck(MasAutomatedClaimPayload payload) { - var offRampReasonOptional = getOffRampReasonPresumptiveCheck(payload); - if (offRampReasonOptional.isPresent()) { - var offRampReason = offRampReasonOptional.get(); - payload.setOffRampReason(offRampReason); - MasProcessingObject mpo = new MasProcessingObject(payload, MasCamelStage.START_COMPLETE); - camelEntrance.completeProcessing(mpo); - return offRampReason; // Let the HTTP response continue - } - var headers = - Map.of( - MasIntegrationRoutes.MAS_DELAY_PARAM, - masConfig.getMasProcessingInitialDelay(), - MasIntegrationRoutes.MAS_RETRY_PARAM, - masConfig.getMasRetryCount()); - camelEntry.inOnly(IMVP_EXCHANGE, NOTIFY_AUTOMATED_CLAIM_QUEUE, payload, headers); - return String.format("Received Claim for collection Id %d.", payload.getCollectionId()); - } - - public Optional getOffRampReasonPresumptiveCheck(MasAutomatedClaimPayload payload) { - if (payload.isPresumptive() != null && !payload.isPresumptive()) { - var logMessageOnly = - String.format( - "Claim with collection id: %s, diagnostic code: %s," - + " and disability action type: %s is not in scope.", - payload.getCollectionId(), - payload.getDiagnosticCode(), - payload.getDisabilityActionType(), - payload.getVeteranFlashIds()); - log.info(logMessageOnly); - return Optional.of(EventReason.NEW_NOT_PRESUMPTIVE.getReasonMessage()); - } - return Optional.empty(); - } - - private Optional getOffRampReasonScopeAndAnchorCheck(MasAutomatedClaimPayload payload) { - if (!payload.isInScope()) { - var message = - String.format( - "Claim with collection id: %s, diagnostic code: %s," - + " and disability action type: %s is not in scope.", - payload.getCollectionId(), - payload.getDiagnosticCode(), - payload.getDisabilityActionType()); - return Optional.of(message); - } - - long claimId = Long.parseLong(payload.getClaimDetail().getBenefitClaimId()); - log.info("Check hasAnchors for claim ID, {}", claimId); - if (!bipClaimService.hasAnchors(claimId)) { - var message = - String.format( - "Claim with collection id: %s does not qualify for" - + " automated processing because it is missing anchors.", - payload.getCollectionId()); - log.info(message); - return Optional.of(message); - } - return Optional.empty(); - } - - public void examOrderingStatus(MasExamOrderStatusPayload payload, String claimIdType) { - saveToDbService.insertOrUpdateExamOrderingStatus(buildExamOrder(payload, claimIdType)); - camelEntrance.examOrderingStatus(payload); - } - - private void offRampClaim(MasAutomatedClaimPayload payload, String message) { - var auditEvent = buildAuditEvent(payload, message); - camelEntrance.offrampClaim(auditEvent); - var mpo = new MasProcessingObject(payload, MasCamelStage.START_COMPLETE); - camelEntrance.completeProcessing(mpo); - } - - private static AuditEvent buildAuditEvent(MasAutomatedClaimPayload payload, String message) { - return AuditEvent.builder() - .eventId(Integer.toString(payload.getCollectionId())) - .payloadType(payload.getDisplayName()) - .routeId("/automatedClaim") - .messages(new String[] {message}) - .build(); - } - - private Claim toClaim(MasAutomatedClaimPayload payload) { - return Claim.builder() - .benefitClaimId(payload.getBenefitClaimId()) - .collectionId(Integer.toString(payload.getCollectionId())) - .idType(payload.getIdType()) - .conditionName(payload.getConditionName()) - .diagnosticCode(payload.getDiagnosticCode()) - .veteranIcn(payload.getVeteranIcn()) - .veteranParticipantId(payload.getVeteranParticipantId()) - .inScope(payload.isInScope()) - .disabilityActionType(payload.getDisabilityActionType()) - .disabilityClassificationCode(payload.getDisabilityClassificationCode()) - .presumptiveFlag(payload.isPresumptive() != null && payload.isPresumptive()) - .offRampReason(payload.getOffRampReason()) - .submissionSource(payload.getClaimDetail().getClaimSubmissionSource()) - .submissionDate(parseCustomDate(payload.getClaimDetail().getClaimSubmissionDateTime())) - .build(); - } - - private OffsetDateTime parseCustomDate(String input) { - OffsetDateTime customDateTime = null; - try { - if (input != null && !input.isBlank()) { - // Attempt to parse non-standard ISO date we may be sent of YYYY-MM-DDZ - Matcher customDateMatcher = customDatePattern.matcher(input); - if (customDateMatcher.matches()) { - int year = Integer.parseInt(customDateMatcher.group(1)); - int month = Integer.parseInt(customDateMatcher.group(2)); - int day = Integer.parseInt(customDateMatcher.group(3)); - LocalDate customDate = LocalDate.of(year, month, day); - customDateTime = OffsetDateTime.of(customDate, LocalTime.MIN, ZoneOffset.UTC); - } else { - // Fall back to ISO 8601 Date Time - customDateTime = OffsetDateTime.parse(input); - } - } - } catch (Exception e) { - log.error("Unable to parse date time. Unexpected date format {}", input); - } - return customDateTime; - } - - private ExamOrder buildExamOrder(MasExamOrderStatusPayload payload, String claimIdType) { - OffsetDateTime examDateTime = parseCustomDate(payload.getExamOrderDateTime()); - return ExamOrder.builder() - .collectionId(Integer.toString(payload.getCollectionId())) - .idType(claimIdType) - .status(payload.getCollectionStatus()) - .examOrderDateTime(examDateTime) - .build(); - } - - public void offRampClaimForError(MasProcessingObject mpo, String offRampReason) { - MasAutomatedClaimPayload claimPayload = mpo.getClaimPayload(); - Claim claim = toClaim(claimPayload); - claim.setOffRampReason(offRampReason); - saveToDbService.setOffRampReason(claim); - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/mapper/MasCollectionAnnotsResults.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/mapper/MasCollectionAnnotsResults.java deleted file mode 100644 index f1da71cf11..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/mas/service/mapper/MasCollectionAnnotsResults.java +++ /dev/null @@ -1,311 +0,0 @@ -package gov.va.vro.service.provider.mas.service.mapper; - -import static java.util.Objects.isNull; - -import gov.va.vro.model.rrd.AbdBloodPressure; -import gov.va.vro.model.rrd.AbdBpMeasurement; -import gov.va.vro.model.rrd.AbdCondition; -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.AbdMedication; -import gov.va.vro.model.rrd.AbdProcedure; -import gov.va.vro.model.rrd.ServiceLocation; -import gov.va.vro.model.rrd.mas.MasAnnotType; -import gov.va.vro.model.rrd.mas.MasAnnotation; -import gov.va.vro.model.rrd.mas.MasCollectionAnnotation; -import gov.va.vro.model.rrd.mas.MasDocument; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -@Component -@RequiredArgsConstructor -@Slf4j -public class MasCollectionAnnotsResults { - - private static final String DATA_SOURCE = "MAS"; - private static final String UTC_TM = "T00:00:00Z"; - private static final String NOT_AVAILABLE_STR = "N/A"; - private static final String BP_CONDITION = "Hypertension"; - private static final String ASTHMA_CONDITION = "Asthma"; - private static final String BP_SYSTOLIC_CODE = "8480-6"; - private static final String BP_SYSTOLIC_DISPLAY = "Systolic blood pressure"; - private static final String BP_DIASTOLIC_CODE = "8462-4"; - private static final String BP_DIASTOLIC_DISPLAY = "Diastolic blood pressure"; - private static final String BP_UNIT = "mm[Hg]"; - private static final String BP_READING_REGEX = "(-|\\d+)"; // "^\\d{1,3}\\s*\\/\\s*\\d{1,3}\\s*$"; - private static final int BP_VALUE_LENGTH = 3; - DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); - DateFormat formatter1 = new SimpleDateFormat("M/d/yyyy"); - - /** - * Maps annotations to evidence. - * - * @param masCollectionAnnotation annotation - * @return abd evidence - */ - public AbdEvidence mapAnnotationsToEvidence(MasCollectionAnnotation masCollectionAnnotation) { - List medications = new ArrayList<>(); - List conditions = new ArrayList<>(); - List bpReadings = new ArrayList<>(); - List serviceLocations = new ArrayList<>(); - boolean isConditionBp = false; - boolean isConditionAsthma = false; - - for (MasDocument masDocument : masCollectionAnnotation.getDocuments()) { - isConditionBp = masDocument.getCondition().equalsIgnoreCase(BP_CONDITION); - isConditionAsthma = masDocument.getCondition().equalsIgnoreCase(ASTHMA_CONDITION); - if (masDocument.getAnnotations() != null) { - String documentId = masDocument.getEfolderversionrefid(); - String receiptDate = masDocument.getRecDate(); - try { - receiptDate = formatter1.format(formatter.parse(receiptDate)); - } catch (Exception e) { - log.error("Un-parsable date for ReceiptDate: {}.", receiptDate); - } - String source = masDocument.getDocTypeDescription(); - if (documentId == null) { - documentId = ""; - } - if (receiptDate == null) { - receiptDate = ""; - } else { - receiptDate = receiptDate.replaceAll("Z", ""); - } - if (source == null) { - source = ""; - } - - for (MasAnnotation masAnnotation : masDocument.getAnnotations()) { - log.info( - ">>>> Annotation Type <<<<<< : {} ", - MasAnnotType.fromString(masAnnotation.getAnnotType().toLowerCase())); - MasAnnotType annotationType = - MasAnnotType.fromString(masAnnotation.getAnnotType().toLowerCase()); - switch (annotationType) { - case MEDICATION -> { - AbdMedication abdMedication = createMedication(isConditionAsthma, masAnnotation); - abdMedication.setDocument(documentId); - abdMedication.setReceiptDate(receiptDate); - abdMedication.setOrganization(source); - medications.add(abdMedication); - } - case CONDITION -> { - AbdCondition abdCondition = createCondition(masAnnotation); - abdCondition.setDocument(documentId); - abdCondition.setReceiptDate(receiptDate); - abdCondition.setOrganization(source); - conditions.add(abdCondition); - } - case BLOOD_PRESSURE -> { - AbdBloodPressure abdBloodPressure = createBloodPressure(masAnnotation); - if (abdBloodPressure != null) { - abdBloodPressure.setDocument(documentId); - abdBloodPressure.setReceiptDate(receiptDate); - abdBloodPressure.setOrganization(source); - bpReadings.add(abdBloodPressure); - } - } - case SERVICE -> { - ServiceLocation veteranService = createServiceLocation(masAnnotation); - veteranService.setDocument(source); - - veteranService.setReceiptDate(receiptDate); - veteranService.setDocumentId(documentId); - serviceLocations.add(veteranService); - } - default -> { // NOP - } - } - } - } - } - List procedures = new ArrayList<>(); - AbdEvidence abdEvidence = new AbdEvidence(); - abdEvidence.setMedications(medications); - abdEvidence.setConditions(conditions); - abdEvidence.setProcedures(procedures); - abdEvidence.setBloodPressures(bpReadings); - abdEvidence.setServiceLocations(serviceLocations); - abdEvidence.setDocumentsWithoutAnnotationsChecked( - masCollectionAnnotation.getDocumentsWithoutAnnotationsChecked()); - return abdEvidence; - } - - private static BigDecimal getBpReadingValue(String valueString) { - if (valueString.length() > BP_VALUE_LENGTH) { - log.error("Invalid blood pressure reading value: {}.", valueString); - return null; - } - if (valueString.equals("-")) { // return default value. - return BigDecimal.valueOf(0); - } else { - try { - return new BigDecimal(valueString).setScale(1, RoundingMode.HALF_UP); - } catch (Exception e) { - log.error("Invalid blood pressure reading value: {}", valueString); - return null; - } - } - } - - private static AbdBloodPressure createBloodPressure(MasAnnotation masAnnotation) { - log.info("MasAnnotation: {}", masAnnotation.getAnnotVal()); - Pattern pattern = Pattern.compile(BP_READING_REGEX); - Matcher matcher = pattern.matcher(masAnnotation.getAnnotVal()); - - BigDecimal systolicVal; - BigDecimal diastolicVal; - if (matcher.find()) { - systolicVal = getBpReadingValue(matcher.group()); - if (systolicVal == null) { - return null; - } - - if (matcher.find()) { - String valueString = matcher.group(); - if (valueString.equals("-") && BigDecimal.ZERO.equals(systolicVal)) { - return null; // skip empty blood pressure reading. - } - diastolicVal = getBpReadingValue(matcher.group()); - if (diastolicVal == null) { - return null; - } - } else { - log.info( - "Missing blood pressure diastolic reading: {}. Default to 0.", - masAnnotation.getAnnotVal()); - diastolicVal = BigDecimal.valueOf(0); - } - } else { - log.error( - "Missing blood pressure reading in the MAS annotation: {}.", masAnnotation.getAnnotVal()); - return null; - } - if (systolicVal.equals("-") && diastolicVal.equals("-")) { // skip missing BP reading values. - return null; - } - - AbdBpMeasurement systolicReading = new AbdBpMeasurement(); - systolicReading.setCode(BP_SYSTOLIC_CODE); - systolicReading.setDisplay(BP_SYSTOLIC_DISPLAY); - systolicReading.setValue(systolicVal); - systolicReading.setUnit(BP_UNIT); - AbdBpMeasurement diastolicReading = new AbdBpMeasurement(); - diastolicReading.setCode(BP_DIASTOLIC_CODE); - diastolicReading.setDisplay(BP_DIASTOLIC_DISPLAY); - diastolicReading.setValue(diastolicVal); - diastolicReading.setUnit(BP_UNIT); - - AbdBloodPressure abdBloodPressure = new AbdBloodPressure(); - abdBloodPressure.setDataSource(DATA_SOURCE); - if (masAnnotation.getObservationDate() != null) { - abdBloodPressure.setDate(masAnnotation.getObservationDate().replaceAll("Z", "")); - } else { - abdBloodPressure.setDate(""); - } - if (masAnnotation.getPageNum() != null) { - abdBloodPressure.setPage(masAnnotation.getPageNum()); - } else { - abdBloodPressure.setPage(""); - } - if (masAnnotation.getRecDate() != null) { - abdBloodPressure.setReceiptDate(masAnnotation.getRecDate()); - } else { - abdBloodPressure.setReceiptDate(""); - } - if (masAnnotation.getEFolderVersionRefId() != null) { - abdBloodPressure.setDocument(masAnnotation.getEFolderVersionRefId()); - } else { - abdBloodPressure.setDocument(""); - } - if (masAnnotation.getDocTypedescription() != null) { - abdBloodPressure.setOrganization(masAnnotation.getDocTypedescription()); - } else { - abdBloodPressure.setOrganization(""); - } - abdBloodPressure.setSystolic(systolicReading); - abdBloodPressure.setDiastolic(diastolicReading); - abdBloodPressure.setOrganization(null); - abdBloodPressure.setPractitioner(null); - return abdBloodPressure; - } - - private static AbdMedication createMedication( - boolean isConditionAsthma, MasAnnotation masAnnotation) { - AbdMedication abdMedication = new AbdMedication(); - abdMedication.setDataSource(DATA_SOURCE); - abdMedication.setStatus(null); - abdMedication.setNotes(null); - abdMedication.setDescription(masAnnotation.getAnnotVal().toLowerCase()); - abdMedication.setRefills(-1); - abdMedication.setAsthmaRelevant(null); - abdMedication.setDuration(null); - if (masAnnotation.getObservationDate() != null) { - abdMedication.setAuthoredOn(masAnnotation.getObservationDate().replaceAll("Z", "") + UTC_TM); - } else { - abdMedication.setAuthoredOn(""); - } - if (masAnnotation.getPartialDate() != null) { - abdMedication.setPartialDate(masAnnotation.getPartialDate().replaceAll("Z", "")); - } else { - abdMedication.setPartialDate(""); - } - if (masAnnotation.getPageNum() != null) { - abdMedication.setPage(masAnnotation.getPageNum()); - } else { - abdMedication.setPage(""); - } - abdMedication.setRoute(null); - abdMedication.setAsthmaRelevant(isConditionAsthma); - return abdMedication; - } - - private static AbdCondition createCondition(MasAnnotation masAnnotation) { - AbdCondition abdCondition = new AbdCondition(); - abdCondition.setDataSource(DATA_SOURCE); - abdCondition.setCode(masAnnotation.getAnnotVal()); - abdCondition.setText(masAnnotation.getAcdPrefName()); - abdCondition.setStatus(null); - abdCondition.setAbatementDate(null); - if (masAnnotation.getObservationDate() != null) { - abdCondition.setRecordedDate(masAnnotation.getObservationDate().replaceAll("Z", "")); - } else { - abdCondition.setRecordedDate(""); - } - if (masAnnotation.getPartialDate() != null) { - abdCondition.setPartialDate(masAnnotation.getPartialDate().replaceAll("Z", "")); - } else { - abdCondition.setPartialDate(""); - } - if (masAnnotation.getPageNum() != null) { - abdCondition.setPage(masAnnotation.getPageNum()); - } else { - abdCondition.setPage(""); - } - return abdCondition; - } - - private static ServiceLocation createServiceLocation(MasAnnotation masAnnotation) { - ServiceLocation veteranService = new ServiceLocation(); - if (!isNull(masAnnotation.getAnnotVal())) { - veteranService.setLocation(masAnnotation.getAnnotVal()); - } else { - veteranService.setLocation(NOT_AVAILABLE_STR); - } - if (!isNull(masAnnotation.getPageNum())) { - veteranService.setPage(masAnnotation.getPageNum()); - } else { - veteranService.setPage(NOT_AVAILABLE_STR); - } - return veteranService; - } -} diff --git a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/utils/DiagnosisLookup.java b/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/utils/DiagnosisLookup.java deleted file mode 100644 index 97baa7824b..0000000000 --- a/domain-rrd/rrd-workflows/src/main/java/gov/va/vro/service/provider/utils/DiagnosisLookup.java +++ /dev/null @@ -1,15 +0,0 @@ -package gov.va.vro.service.provider.utils; - -import java.util.Map; - -public final class DiagnosisLookup { - - private DiagnosisLookup() {} - - private static final Map diagnosisMap = - Map.of("7101", "Hypertension", "6602", "Asthma"); - - public static String getDiagnosis(String diagnosticCode) { - return diagnosisMap.get(diagnosticCode); - } -} diff --git a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/MasProcessingObjectTestData.java b/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/MasProcessingObjectTestData.java deleted file mode 100644 index c80f3ae0c2..0000000000 --- a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/MasProcessingObjectTestData.java +++ /dev/null @@ -1,57 +0,0 @@ -package gov.va.vro.service.provider; - -import gov.va.vro.model.rrd.mas.ClaimCondition; -import gov.va.vro.model.rrd.mas.ClaimDetail; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.model.rrd.mas.VeteranIdentifiers; -import gov.va.vro.service.provider.mas.MasCamelStage; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import lombok.Builder; - -// TODO: merge with MasTestData -// TODO: refactor tests to use the resulting class to minimize duplicate code and facilitate changes -@Builder(toBuilder = true) -public class MasProcessingObjectTestData { - @Builder.Default int collectionId = 20230420; - @Builder.Default String claimId = "0613"; - - @Builder.Default String diagnosticCode = "7101"; - - @Builder.Default String veteranParticipantId = "vetPid20230421"; - - @Builder.Default MasCamelStage masCamelStage = MasCamelStage.START_COMPLETE; - - public MasProcessingObject create() { - ClaimDetail claimDetail = createClaimDetail(diagnosticCode, claimId); - claimDetail.setBenefitClaimId(claimId); - VeteranIdentifiers veteranIdentifiers = createVeteranIdentifiers(); - MasAutomatedClaimPayload claimPayload = - MasAutomatedClaimPayload.builder() - .collectionId(collectionId) - .claimDetail(claimDetail) - .veteranIdentifiers(veteranIdentifiers) - .build(); - return new MasProcessingObject(claimPayload, masCamelStage); - } - - public VeteranIdentifiers createVeteranIdentifiers() { - VeteranIdentifiers veteranIdentifiers = new VeteranIdentifiers(); - veteranIdentifiers.setEdipn("X"); - veteranIdentifiers.setParticipantId(veteranParticipantId); - veteranIdentifiers.setIcn("X"); - veteranIdentifiers.setSsn("X"); - veteranIdentifiers.setVeteranFileId("X"); - return veteranIdentifiers; - } - - private static ClaimDetail createClaimDetail(String diagnosticCode, String claimId) { - ClaimCondition conditions = new ClaimCondition(); - conditions.setDiagnosticCode(diagnosticCode); - conditions.setDisabilityActionType("INCREASE"); - ClaimDetail claimDetail = new ClaimDetail(); - claimDetail.setClaimSubmissionDateTime("2022-02-04T17:45:59Z"); - claimDetail.setConditions(conditions); - claimDetail.setBenefitClaimId(claimId); - return claimDetail; - } -} diff --git a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/bgs/service/BgsApiClientTest.java b/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/bgs/service/BgsApiClientTest.java deleted file mode 100644 index 1e642299db..0000000000 --- a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/bgs/service/BgsApiClientTest.java +++ /dev/null @@ -1,166 +0,0 @@ -package gov.va.vro.service.provider.bgs.service; - -import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -import gov.va.vro.model.rrd.bgs.BgsApiClientRequest; -import gov.va.vro.model.rrd.event.EventReason; -import gov.va.vro.persistence.model.EvidenceSummaryDocumentEntity; -import gov.va.vro.persistence.repository.EvidenceSummaryDocumentRepository; -import gov.va.vro.service.provider.EntityNotFoundException; -import gov.va.vro.service.provider.MasProcessingObjectTestData; -import gov.va.vro.service.provider.mas.MasCamelStage; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.time.OffsetDateTime; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.Random; -import java.util.stream.Collectors; - -// https://github.com/department-of-veterans-affairs/abd-vro/issues/1341 -@ExtendWith(MockitoExtension.class) -public class BgsApiClientTest { - - static EvidenceSummaryDocumentRepository esDocRepository; - static BgsApiClient client; - - @BeforeAll - static void setupStatics() { - esDocRepository = Mockito.mock(EvidenceSummaryDocumentRepository.class); - // The client is stateless, so a single instance can handle multiple tests - client = new BgsApiClient(esDocRepository); - } - - static final OffsetDateTime uploadedAt = OffsetDateTime.now(); - - private void mockEsdRepoFindById() { - EvidenceSummaryDocumentEntity entity = new EvidenceSummaryDocumentEntity(); - entity.setUploadedAt(uploadedAt); - when(esDocRepository.findById(any())).thenReturn(Optional.of(entity)); - } - - private MasProcessingObject mpoWithMasCamelStage(MasCamelStage stage) { - return MasProcessingObjectTestData.builder().masCamelStage(stage).build().create(); - } - - @Test - void buildRequestTest_ReadyForDecision() { - mockEsdRepoFindById(); - var mpo = mpoWithMasCamelStage(MasCamelStage.DURING_PROCESSING); - mpo.setSufficientForFastTracking(true); - var requests = client.buildRequests(mpo).getPendingRequests(); - - // Should be 2 separate requests -- one for veteran note, another for claim notes - assertEquals(2, requests.size()); - requests.forEach(request -> assertTrue(request.isConstraintSatisfied())); - - var claimNotes = extractClaimNotesFrom(requests); - assertThat(claimNotes) - .hasSize(2) - .containsExactlyInAnyOrder(BgsClaimNotes.RFD_NOTE, BgsClaimNotes.ARSD_COMPLETED_NOTE); - - var veteranNotes = extractVeteranNotesFrom(requests); - assertEquals(1, veteranNotes.size()); - var expectedVeteranNote = BgsVeteranNote.getArsdUploadedNote(uploadedAt); - assertEquals(expectedVeteranNote, veteranNotes.get(0)); - } - - @Test - void buildRequestTest_ReadyForDecision_missingEsdEntity() { - when(esDocRepository.findById(any())).thenReturn(Optional.empty()); - - var mpo = mpoWithMasCamelStage(MasCamelStage.DURING_PROCESSING); - mpo.setSufficientForFastTracking(true); - // Should never occur -- throw an exception so we can investigate - assertThrows( - EntityNotFoundException.class, () -> client.buildRequests(mpo).getPendingRequests()); - } - - @Test - void buildRequestTest_ExamOrder() { - mockEsdRepoFindById(); - var mpo = mpoWithMasCamelStage(MasCamelStage.DURING_PROCESSING); - mpo.setSufficientForFastTracking(false); - var requests = client.buildRequests(mpo).getPendingRequests(); - - // Should be 2 separate requests -- one for veteran note, another for claim notes - assertEquals(2, requests.size()); - requests.forEach(request -> assertTrue(request.isConstraintSatisfied())); - - var claimNotes = extractClaimNotesFrom(requests); - assertThat(claimNotes).hasSize(1).containsExactlyInAnyOrder(BgsClaimNotes.EXAM_REQUESTED_NOTE); - - var veteranNotes = extractVeteranNotesFrom(requests); - assertEquals(1, veteranNotes.size()); - var expectedVeteranNote = BgsVeteranNote.getArsdUploadedNote(uploadedAt); - assertEquals(expectedVeteranNote, veteranNotes.get(0)); - } - - @NotNull - private static List extractClaimNotesFrom(List requests) { - return requests.stream() - .flatMap(request -> request.getClaimNotes().stream()) - .collect(Collectors.toList()); - } - - @NotNull - private static List extractVeteranNotesFrom(List requests) { - return requests.stream() - .map(request -> request.getVeteranNote()) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - @Test - void buildRequestTest_NewButNotPresumptive() { - testClaimNotesForOffRampReason( - EventReason.NEW_NOT_PRESUMPTIVE, BgsClaimNotes.CANT_CONFIRM_PRESUMPTIVE_NOTE); - } - - @Test - void buildRequestTest_SufficientUndetermined() { - testClaimNotesForOffRampReason( - EventReason.SUFFICIENCY_UNDETERMINED, BgsClaimNotes.CANT_CONFIRM_PRESUMPTIVE_NOTE); - } - - @Test - void buildRequestTest_PdfUploadFailed() { - testClaimNotesForOffRampReason( - EventReason.PDF_UPLOAD_FAILED_AFTER_ORDER_EXAM, BgsClaimNotes.ARSD_NOT_UPLOADED_NOTE); - } - - void testClaimNotesForOffRampReason(EventReason reason, String expectedClaimNote) { - var mpo = mpoWithOfframpReason(reason); - var requests = client.buildRequests(mpo).getPendingRequests(); - - assertEquals(1, requests.size()); - var claimNotes = requests.get(0).claimNotes; - assertEquals(expectedClaimNote, claimNotes.get(0)); - } - - MasProcessingObject mpoWithOfframpReason(EventReason reason) { - var mpo = mpoWithMasCamelStage(masCamelStageForOfframp()); - mpo.getClaimPayload().setOffRampReason(reason.getCode()); - return mpo; - } - - private static final Random random = new Random(); - - MasCamelStage masCamelStageForOfframp() { - // stage doesn't matter as long as there is an setOffRampReason - MasCamelStage[] stages = {MasCamelStage.START_COMPLETE, MasCamelStage.DURING_PROCESSING}; - return stages[random.nextInt(stages.length)]; - } -} diff --git a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/BgsApiClientRoutesTest.java b/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/BgsApiClientRoutesTest.java deleted file mode 100644 index 39a297bbf2..0000000000 --- a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/BgsApiClientRoutesTest.java +++ /dev/null @@ -1,158 +0,0 @@ -package gov.va.vro.service.provider.camel; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -import gov.va.vro.camel.processor.FunctionProcessor; -import gov.va.vro.model.rrd.bgs.BgsApiClientRequest; -import gov.va.vro.model.rrd.bgs.BgsApiClientResponse; -import gov.va.vro.service.provider.MasConfig; -import gov.va.vro.service.provider.MasProcessingObjectTestData; -import gov.va.vro.service.provider.bgs.service.BgsApiClient; -import gov.va.vro.service.provider.bgs.service.BgsNotesCamelBody; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.camel.RoutesBuilder; -import org.apache.camel.builder.AdviceWith; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.test.junit5.CamelTestSupport; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.ArrayList; -import java.util.stream.IntStream; - -@Slf4j -@ExtendWith(MockitoExtension.class) -public class BgsApiClientRoutesTest extends CamelTestSupport { - - public static final String TEST_BGS_CLIENT_SERVICE = "direct:test-microservice"; - @Mock BgsApiClient client; - - @Override - protected RoutesBuilder createRouteBuilder() { - mockBgsApiClient(); - MasConfig masConfig = MasConfig.builder().slackExceptionWebhook("http://nowhere").build(); - var rb = new BgsApiClientRoutes(template, client, masConfig); - configureMockBgsApiMicroservice(rb); - return rb; - } - - // See https://camel.apache.org/manual/advice-with.html#_enabling_advice_during_testing - @Override - public boolean isUseAdviceWith() { - return true; - } - - public static final String CLAIM_ID_MULTIPLE_REQUESTS = "111"; - public static final String CLAIM_ID_RETRY_FAILED = "222"; - - void configureMockBgsApiMicroservice(RouteBuilder rb) { - rb.from(TEST_BGS_CLIENT_SERVICE) - .process( - FunctionProcessor.builder() - .inputBodyClass(BgsApiClientRequest.class) - .function( - request -> { - var response = new BgsApiClientResponse(); - switch (request.getVbmsClaimId()) { - case CLAIM_ID_MULTIPLE_REQUESTS: - response.setStatusCode(200); - break; - case CLAIM_ID_RETRY_FAILED: - if ("pid2".equals(request.getVeteranParticipantId())) - response.setStatusCode(400); - else response.setStatusCode(200); - break; - } - // return an error on the second request - return response; - }) - .build()); - } - - static final int NUM_REQUESTS = 2; - - private void mockBgsApiClient() { - when(client.buildRequests(any())) - .thenAnswer( - invocation -> { - final var mpo = invocation.getArgument(0, MasProcessingObject.class); - // For testing, set tiny delay between retries - BgsNotesCamelBody body = new BgsNotesCamelBody(mpo, 200); - IntStream.rangeClosed(1, NUM_REQUESTS) - // For testing, use the veteranParticipantId to uniquely identify each request - .forEach( - i -> - body.pendingRequests.add( - new BgsApiClientRequest(mpo.getBenefitClaimId(), "pid" + i))); - return body; - }); - } - - public static final String MOCK_SLACK = "mock:slack"; - - @BeforeEach - @SneakyThrows - void mockEndpointsThenStart() { - AdviceWith.adviceWith( - context, - "to-rabbitmq-bgs-api-add-note-route", - false, - rb -> { - // replace the rabbitmq endpoint to avoid "Failed to create connection." - rb.weaveById("to-rabbitmq-bgsclient-addnote").replace().to(TEST_BGS_CLIENT_SERVICE); - // mock so we can count the number of requests sent to client service - rb.mockEndpoints(TEST_BGS_CLIENT_SERVICE); - }); - - AdviceWith.adviceWith( - context, - "slack-bgs-failed-route", - false, - rb -> { - // replace the rabbitmq endpoint to avoid "Failed to create connection." - rb.weaveById("message-to-slack").replace().to(MOCK_SLACK); - }); - - if (isUseAdviceWith()) context.start(); - } - - @Test - @SneakyThrows - void multipleRequestsTest() { - MasProcessingObject mpo = - MasProcessingObjectTestData.builder().claimId(CLAIM_ID_MULTIPLE_REQUESTS).build().create(); - template.sendBody(BgsApiClientRoutes.ADD_BGS_NOTES, mpo); - - getMockEndpoint("mock:" + TEST_BGS_CLIENT_SERVICE).expectedMessageCount(NUM_REQUESTS); - assertMockEndpointsSatisfied(); - } - - @Test - @SneakyThrows - void retryFailedRequestsTest() { - MasProcessingObject mpo = - MasProcessingObjectTestData.builder().claimId(CLAIM_ID_RETRY_FAILED).build().create(); - template.sendBody(BgsApiClientRoutes.ADD_BGS_NOTES, mpo); - - // 1st request succeeds; tries the 2nd request RETRY_LIMIT times - // https://github.com/department-of-veterans-affairs/abd-vro/issues/1343 - getMockEndpoint("mock:" + TEST_BGS_CLIENT_SERVICE) - .expectedMessageCount(NUM_REQUESTS - 1 + BgsApiClientRoutes.RETRY_LIMIT); - - // Since the 2nd request fails all retries, a Slack message is sent - // https://github.com/department-of-veterans-affairs/abd-vro/issues/1342 - var msg = - String.format( - "Failed to add VBMS notes for claim %s, collection id: %s; status code %s: %s. Note: %s %s", - mpo.getBenefitClaimId(), mpo.getCollectionId(), 400, null, null, new ArrayList()); - getMockEndpoint(MOCK_SLACK).expectedBodiesReceived(msg); - - assertMockEndpointsSatisfied(); - } -} diff --git a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/processor/AssessmentResultProcessorTest.java b/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/processor/AssessmentResultProcessorTest.java deleted file mode 100644 index 227050d9e3..0000000000 --- a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/processor/AssessmentResultProcessorTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.read.ListAppender; -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.service.spi.db.SaveToDbService; -import org.apache.camel.CamelContext; -import org.apache.camel.Exchange; -import org.apache.camel.impl.DefaultCamelContext; -import org.apache.camel.support.DefaultExchange; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import org.slf4j.LoggerFactory; - -import java.util.UUID; - -@ExtendWith(MockitoExtension.class) -public class AssessmentResultProcessorTest { - - private SaveToDbService saveToDbService; - private AssessmentResultProcessor processor; - - private final CamelContext ctx = new DefaultCamelContext(); - private Exchange testExchange; - - private static final String diagnosticCode = "7101"; - private static final UUID claimId = UUID.randomUUID(); - - private static final AbdEvidenceWithSummary evidence = new AbdEvidenceWithSummary(); - private ListAppender listAppender; - - @BeforeEach - void setup() { - saveToDbService = Mockito.mock(SaveToDbService.class); - processor = new AssessmentResultProcessor(saveToDbService); - testExchange = new DefaultExchange(ctx); - final var log = (Logger) LoggerFactory.getLogger(AssessmentResultProcessor.class); - listAppender = new ListAppender<>(); - listAppender.start(); - log.addAppender(listAppender); - } - - @Test - void testMissingClaimId() { - testExchange.setProperty("diagnosticCode", diagnosticCode); - testExchange.getIn().setBody(evidence); - processor.process(testExchange); - Mockito.verify(saveToDbService, Mockito.never()) - .insertAssessmentResult(Mockito.any(), Mockito.any(), Mockito.any()); - String message = listAppender.list.get(0).getFormattedMessage(); - assertThat(message).contains("Claim Id was empty, exiting"); - } - - @Test - void testMissingDiagnosticCode() { - testExchange.setProperty("claim-id", UUID.randomUUID()); - testExchange.getIn().setBody(evidence); - processor.process(testExchange); - Mockito.verify(saveToDbService, Mockito.never()) - .insertAssessmentResult(Mockito.any(), Mockito.any(), Mockito.any()); - String message = listAppender.list.get(0).getFormattedMessage(); - assertThat(message).contains("Diagnostic Code was empty, exiting."); - } - - @Test - void testEmptyEvidence() { - testExchange.setProperty("claim-id", claimId); - testExchange.setProperty("diagnosticCode", diagnosticCode); - processor.process(testExchange); - Mockito.verify(saveToDbService, Mockito.never()) - .insertAssessmentResult(Mockito.any(), Mockito.any(), Mockito.any()); - String message = listAppender.list.get(0).getFormattedMessage(); - assertThat(message).contains("Evidence was empty, exiting"); - } - - @Test - void testSuccessfulSave() { - testExchange.setProperty("claim-id", claimId); - testExchange.setProperty("diagnosticCode", diagnosticCode); - testExchange.getIn().setBody(evidence); - processor.process(testExchange); - Mockito.verify(saveToDbService, Mockito.times(1)) - .insertAssessmentResult(claimId, evidence, diagnosticCode); - } -} diff --git a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/processor/HealthEvidenceProcessorTest.java b/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/processor/HealthEvidenceProcessorTest.java deleted file mode 100644 index 7afc90e12f..0000000000 --- a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/processor/HealthEvidenceProcessorTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.read.ListAppender; -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.service.provider.MasProcessingObjectTestData; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import org.apache.camel.CamelContext; -import org.apache.camel.Exchange; -import org.apache.camel.impl.DefaultCamelContext; -import org.apache.camel.support.DefaultExchange; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; - -@ExtendWith(MockitoExtension.class) -public class HealthEvidenceProcessorTest { - private HealthEvidenceProcessor processor; - private final CamelContext ctx = new DefaultCamelContext(); - private Exchange testExchange; - private ListAppender listAppender; - - @BeforeEach - void setup() { - processor = new HealthEvidenceProcessor(); - testExchange = new DefaultExchange(ctx); - final var log = (Logger) LoggerFactory.getLogger(HealthEvidenceProcessor.class); - listAppender = new ListAppender<>(); - listAppender.start(); - log.addAppender(listAppender); - } - - @Test - void testProcess() { - AbdEvidenceWithSummary evidence = new AbdEvidenceWithSummary(); - evidence.setEvidence(new AbdEvidence()); - MasProcessingObject mpo = - MasProcessingObjectTestData.builder().claimId("1234").build().create(); - List docsWoutAnnotsChecked = new ArrayList<>(); - docsWoutAnnotsChecked.add("doc1"); - testExchange.setProperty("docsWoutAnnotsChecked", docsWoutAnnotsChecked); - testExchange.setProperty("payload", mpo); - testExchange.getIn().setBody(evidence); - processor.process(testExchange); - String message = listAppender.list.get(0).getFormattedMessage(); - assertThat(message).contains(" MAS Processing >> Sufficient Evidence >>> null"); - var body = testExchange.getMessage().getBody(); - assertThat(body).isEqualTo(mpo); - assertThat(mpo.getSufficientForFastTracking()).isNull(); - assertThat(mpo.getEvidence().getConditions()).isNotNull(); - } -} diff --git a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/processor/MasOrderExamProcessorTest.java b/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/processor/MasOrderExamProcessorTest.java deleted file mode 100644 index 56ae1d535c..0000000000 --- a/domain-rrd/rrd-workflows/src/test/java/gov/va/vro/service/provider/camel/processor/MasOrderExamProcessorTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package gov.va.vro.service.provider.camel.processor; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.read.ListAppender; -import gov.va.vro.service.provider.MasProcessingObjectTestData; -import gov.va.vro.service.provider.mas.MasException; -import gov.va.vro.service.provider.mas.MasProcessingObject; -import gov.va.vro.service.provider.mas.service.IMasApiService; -import gov.va.vro.service.spi.db.SaveToDbService; -import org.apache.camel.CamelContext; -import org.apache.camel.Exchange; -import org.apache.camel.impl.DefaultCamelContext; -import org.apache.camel.support.DefaultExchange; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import org.slf4j.LoggerFactory; - -@ExtendWith(MockitoExtension.class) -public class MasOrderExamProcessorTest { - - private IMasApiService masApiService; - private SaveToDbService saveToDbService; - private MasOrderExamProcessor processor; - - private final MasProcessingObject mpo = - MasProcessingObjectTestData.builder().claimId("1234").build().create(); - private final CamelContext ctx = new DefaultCamelContext(); - private Exchange testExchange; - private ListAppender listAppender; - - @BeforeEach - void setup() { - saveToDbService = Mockito.mock(SaveToDbService.class); - masApiService = Mockito.mock(IMasApiService.class); - processor = new MasOrderExamProcessor(masApiService, saveToDbService); - testExchange = new DefaultExchange(ctx); - final var log = (Logger) LoggerFactory.getLogger(MasOrderExamProcessor.class); - listAppender = new ListAppender<>(); - listAppender.start(); - log.addAppender(listAppender); - } - - @Test - void testSuccessfulExamOrder() { - testExchange.getIn().setBody(mpo); - processor.process(testExchange); - Mockito.verify(masApiService, Mockito.times(1)).orderExam(Mockito.any()); - Mockito.verify(saveToDbService, Mockito.times(1)) - .insertOrUpdateExamOrderingStatus(Mockito.any()); - String message = listAppender.list.get(0).getFormattedMessage(); - assertThat(message).contains("Ordering Exam for the collection"); - String lastMessage = listAppender.list.get(listAppender.list.size() - 1).getFormattedMessage(); - assertThat(lastMessage).contains("saving as ORDER_SUBMITTED"); - } - - @Test - void testMasException() { - Mockito.when(masApiService.orderExam(Mockito.any())) - .thenThrow(new MasException("Mas Service Sent Error")); - testExchange.getIn().setBody(mpo); - try { - processor.process(testExchange); - } catch (MasException ignored) { - } - Mockito.verify(masApiService, Mockito.times(1)).orderExam(Mockito.any()); - Mockito.verify(saveToDbService, Mockito.never()) - .insertOrUpdateExamOrderingStatus(Mockito.any()); - String message = listAppender.list.get(0).getFormattedMessage(); - assertThat(message).contains("Ordering Exam for the collection"); - String lastMessage = listAppender.list.get(listAppender.list.size() - 1).getFormattedMessage(); - assertThat(lastMessage).contains("Error in calling Order Exam API"); - } -} diff --git a/domain-rrd/scrap-docker-compose.rrd.yml b/domain-rrd/scrap-docker-compose.rrd.yml deleted file mode 100644 index de08210e2e..0000000000 --- a/domain-rrd/scrap-docker-compose.rrd.yml +++ /dev/null @@ -1,149 +0,0 @@ -# IMPORTANT NOTE: -# This file is not intended to be a valid docker-compose configuration. -# Rather, it is intended to host code previously used by the `app` project -# to expose functionality on behalf of the `domain-rrd` project. -# It has been moved here purely as an artifact. - -version: '3.9' - -networks: - # Creates `vro_intranet` network if env variable COMPOSE_PROJECT_NAME=vro - intranet: - -x-mas-vars: &mas-vars - MAS_API_AUTH_CLIENTID: ${MAS_API_AUTH_CLIENTID} - MAS_API_AUTH_CLIENT_SECRET: ${MAS_API_AUTH_CLIENT_SECRET} - MAS_API_AUTH_TOKEN_URI: ${MAS_API_AUTH_TOKEN_URI} - # MAS_API_AUTH_SCOPE: ${MAS_API_AUTH_SCOPE} - MAS_API_BASE_URL: ${MAS_API_BASE_URL} - # MAS_COLLECTION_ANNOTS_PATH: ${MAS_COLLECTION_ANNOTS_PATH} - # MAS_COLLECTION_STATUS_PATH: ${MAS_COLLECTION_STATUS_PATH} - # MAS_CREATE_EXAM_ORDER_PATH: ${MAS_CREATE_EXAM_ORDER_PATH} - -x-rabbitmq-client-vars: &rabbitmq-client-vars - RABBITMQ_PORT: 5672 - RABBITMQ_RETRY_LIMIT: 3 - RABBITMQ_TIMEOUT: 10800 - -x-python-healthcheck: &python-healthcheck - healthcheck: - test: ["CMD-SHELL", "pgrep python || exit 1"] - interval: 10s - timeout: 5s - retries: 5 - -x-common-security-opt: &common-security-opt - security_opt: - - no-new-privileges:true - -x-common-sde-security: &common-sde-security - ulimits: - nproc: 65535 - -x-rabbitmq-placeholder-vars: &rabbitmq-placeholder-vars - RABBITMQ_PLACEHOLDERS_HOST: rabbitmq-service - RABBITMQ_PLACEHOLDERS_USERNAME: ${RABBITMQ_PLACEHOLDERS_USERNAME} - RABBITMQ_PLACEHOLDERS_USERPASSWORD: ${RABBITMQ_PLACEHOLDERS_USERPASSWORD} - -# Don't start VRO microservices until VRO Platform services are up -x-svc-depends-on: &svc-depends-on - rabbitmq-service: - condition: service_healthy - postgres-service: - condition: service_healthy - redis-service: - condition: service_started - -x-redis-placeholder-vars: &redis-placeholder-vars - REDIS_PLACEHOLDERS_HOST: redis-service - REDIS_PASSWORD: ${REDIS_PLACEHOLDERS_PASSWORD} - -services: - svc-assessor-dc7101: - profiles: [ "all","svc","assessor","v2" ] - image: va/abd_vro-assessclaimdc7101:latest - <<: [ *python-healthcheck, *common-sde-security, *common-security-opt ] - environment: - <<: [ *rabbitmq-client-vars, *rabbitmq-placeholder-vars ] - depends_on: - <<: *svc-depends-on - networks: - - intranet - - svc-assessor-dc6602: - profiles: [ "all","svc","assessor","v2" ] - image: va/abd_vro-assessclaimdc6602:latest - <<: [ *python-healthcheck, *common-sde-security, *common-security-opt ] - environment: - <<: [ *rabbitmq-client-vars, *rabbitmq-placeholder-vars ] - depends_on: - <<: *svc-depends-on - networks: - - intranet - - svc-assessor-dc6602v2: - profiles: [ "all","svc","assessor","prototype" ] - image: va/abd_vro-assessclaimdc6602v2:latest - <<: [ *python-healthcheck, *common-sde-security, *common-security-opt ] - environment: - <<: [ *rabbitmq-client-vars, *rabbitmq-placeholder-vars ] - depends_on: - <<: *svc-depends-on - networks: - - intranet - - svc-assessor-cancer: - profiles: [ "all","svc","assessor","prototype" ] - image: va/abd_vro-assessclaimcancer:latest - <<: [ *python-healthcheck, *common-sde-security, *common-security-opt ] - environment: - <<: [ *rabbitmq-client-vars, *rabbitmq-placeholder-vars ] - depends_on: - <<: *svc-depends-on - networks: - - intranet - - svc-assessor-dc6510: - profiles: [ "all","svc","assessor","prototype" ] - image: va/abd_vro-assessclaimdc6510:latest - <<: [ *python-healthcheck, *common-sde-security, *common-security-opt ] - environment: - <<: [ *rabbitmq-client-vars, *rabbitmq-placeholder-vars ] - depends_on: - <<: *svc-depends-on - networks: - - intranet - - svc-assessor-dc6522: - profiles: [ "all","svc","assessor","prototype" ] - image: va/abd_vro-assessclaimdc6522:latest - <<: [ *python-healthcheck, *common-sde-security, *common-security-opt ] - environment: - <<: [ *rabbitmq-client-vars, *rabbitmq-placeholder-vars ] - depends_on: - <<: *svc-depends-on - networks: - - intranet - - svc-pdf-generator: - profiles: [ "all","svc","pdfgen" ] - image: va/abd_vro-pdfgenerator:latest - <<: [ *python-healthcheck, *common-sde-security, *common-security-opt ] - environment: - MODE: "docker" - <<: [ *rabbitmq-client-vars, *rabbitmq-placeholder-vars, *redis-placeholder-vars ] - depends_on: - <<: *svc-depends-on - networks: - - intranet - - svc-feature-toggle: - profiles: [ "all","svc","feature-toggle" ] - image: va/abd_vro-featuretoggle:latest - <<: [ *common-sde-security, *common-security-opt ] - environment: - <<: [ *rabbitmq-client-vars, *rabbitmq-placeholder-vars, *redis-placeholder-vars ] - depends_on: - <<: *svc-depends-on - networks: - - intranet diff --git a/domain-rrd/service-python/README.md b/domain-rrd/service-python/README.md deleted file mode 100644 index d13e378cb9..0000000000 --- a/domain-rrd/service-python/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# Claims Assessment + PDF Generator - -## RabbitMQ configuration -Each folder in `service-python` contains the infrastructure necessary to build a queue using a RabbitMQ connection. - - -## VRO version 1 -[Plan to Deploy](https://github.com/department-of-veterans-affairs/abd-vro/wiki/(March-2022)-Plan-to-Deploy-to-LHDI#vro-software) - -Claims for Hypertension (7101) or Asthma (6602) are sent to their corresponding assessment service. - -## VRO version 2 -[VRO v2 Roadmap](https://github.com/department-of-veterans-affairs/abd-vro/wiki/VRO-v2-Roadmap#workflow-diagram) - -Hypertension claims that have two data sources, MAS and Lighthouse, are evaluated for RFD. - -## Request message validation -The schema validation for messages sent to `assessclaim` processors is kept in the `data_model.py` file. The message includes -an `evidence` body similar to the ABDEvidence Java object. - -## VRO prototype -The folders not used in version 1.0 or 2.0 are outlines for logic to evaluate new conditions or update existing -processors. Rhinitis, sinusitis, asthma, cancer condition logic are in development. Use the Gradle flag to build the -prototype containers and set an environment variable for the docker compose configuration. - -` -./gradlew -PenablePrototype build check docker -` - -` -export COMPOSE_PROFILES=prototype -` - - -## Contributing - -Tests for each service can be found in `tests/assessclaim`. Testing coverage must be 85%. diff --git a/domain-rrd/service-python/build.gradle.bak b/domain-rrd/service-python/build.gradle.bak deleted file mode 100644 index 3164aa0f40..0000000000 --- a/domain-rrd/service-python/build.gradle.bak +++ /dev/null @@ -1,41 +0,0 @@ -import ru.vyarus.gradle.plugin.python.task.PythonTask - -plugins { - id('ru.vyarus.use-python') version "3.0.0" -} - -python { - installVirtualenv = true -} - -def requirements = tasks.register("requirements", PythonTask) { - module = 'pip' - command = "install -r requirements.txt" -} - -pipInstall { - // Requirements are installed above because this task does not support - // `-r assessclaimdc6602/src/requirements.txt` in requirements.txt - enabled = false -} - -def pyflake8 = tasks.register("pyflake8", PythonTask) { - module = 'flake8' - command = "." - dependsOn requirements -} - -// Runs pytest when `./gradlew test` is run -// Also skips pytest when `./gradlew build -x test` is run -tasks.register("test", PythonTask) { - module = 'pytest' - command = "--ignore=pdfgenerator/src/local_pdf_test.py --cov-report term-missing --cov=. --cov-fail-under=80 --cov-config=../../.coveragerc" - dependsOn pyflake8 -} - -check { - dependsOn test - dependsOn checkPython -} - -clean.dependsOn(cleanPython) diff --git a/domain-rrd/service-python/data_model.py b/domain-rrd/service-python/data_model.py deleted file mode 100644 index 03ba48813c..0000000000 --- a/domain-rrd/service-python/data_model.py +++ /dev/null @@ -1,178 +0,0 @@ -from cerberus import Validator - - -def validate_request_body(request_body): - """ - Validates that the request body conforms to the expected data format - - :param request_body: request body converted from json - :type request_body: dict - :return: dict with boolean result showing if request is valid and if not, any applicable errors - :rtype: dict - """ - schema = { - "veteranIcn": {"type": "string"}, - "claimSubmissionDateTime": {"type": "string"}, - "diagnosticCode": {"type": "string"}, - "disabilityActionType": {"type": "string"}, - "disabilityClassificationCode": {"type": "string"}, - "ratedDisabilityId": {"type": "string"}, - "evidence": { - "type": "dict", - "schema": { - "medications": { - "type": "list", - "default": [], - "schema": { - "type": "dict", - "schema": { - "authoredOn": {"type": "string"}, - "status": {"type": "string"}, - "dosageInstructions": { - "type": "list", - "nullable": True, - "schema": {"type": "string", "default": ""}, - }, - "route": {"type": "string", "nullable": True}, - "refills": {}, - "duration": {"type": "string", "nullable": True}, - "description": {"type": "string"}, - "notes": { - "type": "list", - "nullable": True, - "schema": {"type": "string"}, - }, - "document": { - "type": "string", - "default": "", - }, - "organization": { - "type": "string", - "default": "", - }, - "page": { - "type": "string", - "default": "", - }, - "receiptDate": { - "type": "string", - "default": "", - }, - "partialDate": { - "type": "string", - "default": "", - }, - }, - }, - }, - "bp_readings": { - "type": "list", - "schema": { - "type": "dict", - "schema": { - "diastolic": { - "type": "dict", - "required": True, - "schema": { - "value": {"type": "number", "required": True}, - "code": {"type": "string"}, - "display": {"type": "string"}, - "unit": {"type": "string"}, - }, - }, - "systolic": { - "type": "dict", - "required": True, - "schema": { - "value": {"type": "number", "required": True}, - "code": {"type": "string"}, - "display": {"type": "string"}, - "unit": {"type": "string"}, - }, - }, - "date": {"type": "string", "default": ""}, - "practitioner": {"type": "string", "nullable": True}, - "organization": {"type": "string", "default": ""}, - "document": { - "type": "string", - "default": "", - }, - "dataSource": { - "type": "string", - "default": "", - }, - "page": { - "type": "string", - "default": "", - }, - "receiptDate": { - "type": "string", - "default": "", - }, - "partialDate": { - "type": "string", - "default": "", - } - }, - }, - }, - "conditions": { - "type": "list", - "schema": { - "type": "dict", - "schema": { - "code": { - "type": "string", - "default": "", - }, - "status": { - "type": "string", - }, - "text": { - "type": "string" - }, - "onsetDate": { - "type": "string", - }, - "category": { - "type": "string", - "default": "", - }, - "abatementDate": { - "type": "string", - "nullable": True - }, - "document": { - "type": "string", - "default": "", - }, - "organization": { - "type": "string", - "default": "", - }, - "page": { - "type": "string", - "default": "", - }, - "receiptDate": { - "type": "string", - "default": "", - }, - "partialDate": { - "type": "string", - "default": "", - }, - "dataSource": { - "type": "string", - "default": "", - } - } - } - } - } - } - } - v = Validator(schema) - v.allow_unknown = True - - return {"is_valid": v.validate(request_body), "errors": v.errors, "request_body": v.normalized(request_body)} diff --git a/domain-rrd/service-python/logging_setup.py b/domain-rrd/service-python/logging_setup.py deleted file mode 100644 index aefe021e27..0000000000 --- a/domain-rrd/service-python/logging_setup.py +++ /dev/null @@ -1,20 +0,0 @@ -import logging - - -def set_format(): - """ - Setup logger to automatically include date for messages sent to INFO - - """ - logger = logging.getLogger() - ch = logging.StreamHandler() - logger.setLevel(logging.INFO) - - formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s", - "%Y-%m-%d %H:%M:%S") - ch.setFormatter(formatter) - ch.setLevel(logging.INFO) - - logger.addHandler(ch) - - return logger diff --git a/domain-rrd/service-python/main_consumer.py b/domain-rrd/service-python/main_consumer.py deleted file mode 100644 index e25c4b1d01..0000000000 --- a/domain-rrd/service-python/main_consumer.py +++ /dev/null @@ -1,83 +0,0 @@ -# isort: skip_file -import logging -import os -from time import sleep, time - -import pika -from lib.queues import queue_setup - -import logging_setup - -logger = logging_setup.set_format() - -CONSUMER_CONFIG = { - "host": os.environ.get("RABBITMQ_PLACEHOLDERS_HOST", "localhost"), - "username": os.environ.get("RABBITMQ_USERNAME", "guest"), - "password": os.environ.get("RABBITMQ_PASSWORD", "guest"), - "port": int(os.environ.get("RABBITMQ_PORT", 5672)), - "retry_limit": int(os.environ.get("RABBITMQ_RETRY_LIMIT", 3)), - # 3 hours - "timeout": int(os.environ.get("RABBITMQ_TIMEOUT", 60 * 60 * 3)) -} - - -class RabbitMQConsumer: - - def __init__(self, config): - self.config = config - self.connection = self._create_connection() - if self.connection: - self.setup_queues() - - def __del__(self): - if self.connection: - self.connection.close() - - def _create_connection(self): - credentials = pika.PlainCredentials(self.config["username"], self.config["password"]) - for i in range(self.config["retry_limit"]): - try: - parameters = pika.ConnectionParameters(host=self.config["host"], port=self.config["port"], credentials=credentials) - return pika.BlockingConnection(parameters) - except Exception as e: - logging.warning(e, exc_info=True) - logging.warning(f"RabbitMQ Connection Failed. Retrying in 30s ({i + 1}/{self.config['retry_limit']})") - sleep(30) - return None - - def setup_queues(self): - channel = self.connection.channel() - queue_setup(channel) - self.channel = channel - - -# This file will get copied to the docker image's root folder(src) when being built -# When run, it attempts to create a pika.BlockingConnection() with the settings in CONSUMER_CONFIG -# There are 2 retry levels for the consumer. The first being in _create_connection() which is based on retry_limit -# The other being when the app crashes which is based on timeout -# If it fails, it will try to delete any existing connection and the reference to the instantiated class -# since the retry loop will recreate it -if __name__ == "__main__": - - start_timer = None - current_timer = None - - while True: - consumer = None - try: - consumer = RabbitMQConsumer(CONSUMER_CONFIG) - if consumer.channel: - consumer.channel.start_consuming() - except Exception as e: - del consumer - if start_timer is None: - start_timer = time() - current_timer = 0 - else: - current_timer = time() - start_timer - if current_timer < CONSUMER_CONFIG["timeout"]: - logging.warning(e, exc_info=True) - logging.warning("Connection was closed. Retrying...") - continue - else: - break diff --git a/domain-rrd/service-python/requirements.txt.bak b/domain-rrd/service-python/requirements.txt.bak deleted file mode 100644 index 80e5d29fe4..0000000000 --- a/domain-rrd/service-python/requirements.txt.bak +++ /dev/null @@ -1,5 +0,0 @@ --r assessclaimdc6602/src/requirements.txt --r assessclaimdc7101/src/requirements.txt --r assessclaimcancer/src/requirements.txt --r pdfgenerator/src/requirements.txt --r featuretoggle/src/requirements.txt diff --git a/domain-rrd/service-python/svc-assessclaimcancer/README.md b/domain-rrd/service-python/svc-assessclaimcancer/README.md deleted file mode 100644 index 6c4eff4f0d..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# General Cancer Processor - -## Code sets and associated VASRD codes - -### Neck : bone cancers (DC 5012), soft tissue sarcomas of muscle, fat, or fibrous connective tissue (DC 5329), respiratory cancers (DC 6819), soft tissue sarcomas of vascular origin (DC 7123), malignant skin neoplasms (DC 7818), endocrine cancers (DC 7914), central nervous system cancers (DC 8021), and soft tissue sarcomas of neurogenic origin (DC 8540) - -### Head: bone cancers (DC 5012), soft tissue sarcomas of muscle, fat, or fibrous connective tissue (DC 5329), eye cancers (DC 6014), soft tissue sarcomas of vascular origin (DC 7123), malignant skin neoplasms (DC 7818), ear cancers (DC 6208), mouth cancers (DC 9918), and soft tissue sarcomas of neurogenic origin (DC 8540) - -### Lymphoma: leukemia (DC 7703), Hodgkin's lymphoma (DC 7709), multiple myeloma (DC 7712), non-Hodgkin's lymphoma (DC 7715), amyloidosis (DC 7717), essential thrombocytopenia and primary myelofibrosis (DC 7718), chronic myelogenous leukemia (DC 7719), solitary plasmacytoma (DC 7724), and myelodysplastic syndrome (DC 7725) - -### Breast: 7630 - -### Gynecological: 7627 - -### Male reproductive: 7528 - -### Brain: - -### GI: 7343 - -### Kidney: 7914 - -### Melanoma: 7833 - -### Pancreatic: 7914, 7343 - -### Prostate: 7528 - -### Respiratory: 6819 diff --git a/domain-rrd/service-python/svc-assessclaimcancer/__init__.py b/domain-rrd/service-python/svc-assessclaimcancer/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-assessclaimcancer/build.gradle.bak b/domain-rrd/service-python/svc-assessclaimcancer/build.gradle.bak deleted file mode 100644 index 8e44cd91bd..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/build.gradle.bak +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id 'local.python.container-service-conventions' -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/__init__.py b/domain-rrd/service-python/svc-assessclaimcancer/src/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/__init__.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/__init__.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/brain_cancer_condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/brain_cancer_condition.py deleted file mode 100644 index fbc9e71b16..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/brain_cancer_condition.py +++ /dev/null @@ -1,59 +0,0 @@ -conditions = { - "C70", - "C70.0", - "C70.9", - "C71", - "C71.0", - "C71.1", - "C71.2", - "C71.3", - "C71.4", - "C71.5", - "C71.6", - "C71.7", - "C71.8", - "C71.9", - "C72.2", - "C72.20", - "C72.21", - "C72.22", - "C72.3", - "C72.30", - "C72.31", - "C72.32", - "C72.4", - "C72.40", - "C72.41", - "C72.42", - "C72.50", - "C72.50", - "C72.59", - "C72.9", - "C79.3", - "C79.31", - "C79.32", - "C79.4", - "C79.40", - "C79.49", - "D18.02", - "D32.0", - "D32.9", - "D33.0", - "D33.1", - "D33.2", - "D33.3", - "D42.0", - "D42.9", - "D43.0", - "D43.1", - "D43.2", - "D43.3", - "D43.8", - "D43.9", - "D49.6", - "Q85.00", - "Q85.01", - "Q85.02", - "Q85.03", - "Q85.09" -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/brain_cancer_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/brain_cancer_medication.py deleted file mode 100644 index e2c3c448f1..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/brain_cancer_medication.py +++ /dev/null @@ -1,37 +0,0 @@ -medications = {"afinitor", - "alymsys", - "avastin", - "bevacizumab", - "bicnu", - "camptosar", - "carboplatin", - "carmustine", - "cisplatin", - "cyclophosphamide", - "etopophos", - "etoposide", - "everolimus", - "gleostine", - "gliadel", - "hemady", - "irinotecan", - "lomustine", - "marqibo", - "matulane", - "methotrexate", - "mvasi", - "onivyde", - "otrexup", - "paraplatin", - "procarbazine", - "rasuvo", - "reditrex", - "temodar", - "temozolomide", - "toposar", - "trexall", - "vincasar", - "vincristine", - "xatmep", - "zirabev", - "zortress"} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/breast_cancer_condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/breast_cancer_condition.py deleted file mode 100644 index 96c77368a4..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/breast_cancer_condition.py +++ /dev/null @@ -1,64 +0,0 @@ -condition_codes = {"C50", - "C50.0", - "C50.01", - "C50.011", - "C50.012", - "C50.019", - "C50.1", - "C50.11", - "C50.111", - "C50.112", - "C50.119", - "C50.2", - "C50.21", - "C50.211", - "C50.212", - "C50.219", - "C50.3", - "C50.31", - "C50.311", - "C50.312", - "C50.319", - "C50.4", - "C50.41", - "C50.411", - "C50.412", - "C50.419", - "C50.5", - "C50.51", - "C50.511", - "C50.512", - "C50.519", - "C50.6", - "C50.61", - "C50.611", - "C50.612", - "C50.619", - "C50.8", - "C50.81", - "C50.811", - "C50.812", - "C50.819", - "C50.9", - "C50.91", - "C50.911", - "C50.912", - "C50.919", - "D05", - "D05.0", - "D05.00", - "D05.01", - "D05.02", - "D05.1", - "D05.10", - "D05.11", - "D05.12", - "D05.8", - "D05.80", - "D05.81", - "D05.82", - "D05.9", - "D05.90", - "D05.91", - "D05.92", - } diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/breast_cancer_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/breast_cancer_medication.py deleted file mode 100644 index f79663afd4..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/breast_cancer_medication.py +++ /dev/null @@ -1,89 +0,0 @@ -medication_keywords = { - "abemaciclib", - "abraxane", - "adriamycin", - "adrucil", - "afinitor", - "alpelisib", - "anastrozole", - "arimidex", - "aromasin", - "atezolizumab", - "capecitabine", - "cyclophosphamide", - "deruxtecan", - "docefrez", - "docetaxel", - "doxil", - "doxorubicin", - "ellence", - "enhertu", - "epirubicin", - "eribulin", - "everolimus", - "exemestane", - "fareston", - "faslodex", - "femara", - "fluorouracil", - "fulvestrant", - "gemcitabine", - "goserelin", - "halaven", - "herceptin", - "herceptin hylecta", - "hyaluronidase", - "ibrance", - "infugem", - "ixabepilone", - "ixempra", - "kadcyla", - "keytruda", - "kisqali", - "kisqali oral product", - "lapatinib", - "letrozole", - "lipodox", - "lynparza", - "margenza", - "margetuximab", - "megace", - "megestrol", - "methotrexate", - "neratinib", - "nerlynx", - "nolvadex", - "otrexup", - "paclitaxel", - "palbociclib", - "pamidronate", - "pembrolizumab", - "perjeta", - "pertuzumab", - "phesgo", - "piqray", - "rasuvo", - "reditrex", - "ribociclib", - "sacituzumab", - "soltamox", - "talazoparib", - "talzenna", - "tamoxifen", - "taxotere", - "tecentriq", - "tepadina", - "thiotepa", - "toremifene", - "trastuzumab", - "trexall", - "trodelvy", - "tucatinib", - "tukysa", - "tykerb", - "verzenio", - "vinblastine", - "xatmep", - "xeloda", - "zoladex" -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gi_condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gi_condition.py deleted file mode 100644 index 7bb469953a..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gi_condition.py +++ /dev/null @@ -1,77 +0,0 @@ -condition_codes = { - "C15", - "C15.3", - "C15.4", - "C15.5", - "C15.8", - "C15.9", - "C16", - "C16.0", - "C16.1", - "C16.2", - "C16.3", - "C16.4", - "C16.5", - "C16.6", - "C16.8", - "C16.9", - "C17", - "C17.0", - "C17.1", - "C17.2", - "C17.3", - "C17.8", - "C17.9", - "C18", - "C18.0", - "C18.1", - "C18.2", - "C18.3", - "C18.4", - "C18.5", - "C18.6", - "C18.7", - "C18.8", - "C18.9", - "C19", - "C20", - "C21", - "C21.0", - "C21.1", - "C21.2", - "C21.8", - "C22", - "C22.0", - "C22.1", - "C22.2", - "C22.3", - "C22.4", - "C22.7", - "C22.8", - "C22.9", - "C23", - "C24", - "C24.0", - "C24.1", - "C24.8", - "C24.9", - "C78.4", - "C78.5", - "C78.7 ", - "C78.89", - "D00.1", - "D00.2", - "D01.0", - "D01.1", - "D01.2", - "D01.3", - "D01.4", - "D01.40", - "D01.49", - "D01.5", - "D37.1", - "D37.2", - "D37.4", - "D37.5", - "D37.6" -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gi_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gi_medication.py deleted file mode 100644 index ecf8597ff9..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gi_medication.py +++ /dev/null @@ -1,35 +0,0 @@ -medications = { - "aflibercept", - "atezolizumab", - "bevacizumab", - "cabozantinib", - "capecitabine", - "carboplatin", - "cetuximab", - "cisplatin", - "docetaxel", - "doxorubicin", - "encorafenib", - "epirubicin", - "gemcitabine", - "hyaluronidase", - "ipilimumab", - "irinotecan", - "larotrectinib", - "lenvatinib", - "leucovorin", - "levoleucovorin", - "mitomycin", - "mitoxantrone", - "nivolumab", - "oxaliplatin", - "paclitaxel", - "panitumumab", - "pembrolizumab", - "ramucirumab", - "regorafenib", - "sorafenib", - "tipiracil", - "trastuzumab", - "trifluridine" -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gyn_cancer_condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gyn_cancer_condition.py deleted file mode 100644 index 794d0c2c14..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gyn_cancer_condition.py +++ /dev/null @@ -1,73 +0,0 @@ -condition_dict = { - "Vulvar": [ - "C51", - "C51.0", - "C51.1", - "C51.2", - "C51.8", - "C51.9", - "D07.1", - ], - "Vaginal": [ - "C52", - "D07.2", - ], - "Cervical": [ - "C53", - "C53.0", - "C53.1", - "C53.8", - "C53.9", - "D06", - "D06.0", - "D06.1", - "D06.7", - "D06.9", - ], - "Uterine": [ - "C54", - "C54.0", - "C54.1", - "C54.2", - "C54.3", - "C54.8", - "C54.9", - "C55", - ], - "Ovarian": [ - "C56", - "C56.1", - "C56.2", - "C56.3", - "C56.9", - ], - "Other, Fallopian Tube": [ - "C57" - ], - "Fallopian Tube": [ - "C57.0", - "C57.00", - "C57.01", - "C57.02", - ], - "Other": [ - "C57.1", - "C57.10", - "C57.11", - "C57.12", - "C57.2", - "C57.20", - "C57.21", - "C57.22", - "C57.3", - "C57.4", - "C57.7", - "C57.8", - "C57.9", - "D07", - "D07.0", - "D07.3", - "D07.30", - "D07.39" - ] -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gyn_cancer_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gyn_cancer_medication.py deleted file mode 100644 index 7df5e9ae1f..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/gyn_cancer_medication.py +++ /dev/null @@ -1,38 +0,0 @@ -medications = { - "Vaginal": [ - "gardasil", - "human papillomavirus", - "l1 protein" - ], - "Cervical": [ - "bevacizumab", - "cyclophosphamide", - "gemcitabine", - "infugem", - "lynparza", - "mvasi", - "olaparib", - "pembrolizumab", - "tepadina", - "thiotepa", - "tisotumab", - "tivdak" - ], - "Uterine": [ - "adriamycin", - "docefrez", - "docetaxel", - "doxil", - "doxorubicin", - "lipodox", - "taxotere" - ], - "Cervical, Uterine": [ - "abraxane", - "adriamycin", - "doxil", - "doxorubicin", - "lipodox", - "paclitaxel" - ], -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/head_cancer_condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/head_cancer_condition.py deleted file mode 100644 index 420cc84674..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/head_cancer_condition.py +++ /dev/null @@ -1,306 +0,0 @@ -conditions_dict = { - "Bone": { - "C41.0", - "C41.1", - "C41.9", - "C79.51", - }, - "Skin": {"C30.0", - "C43-C44", - "C43.0", - "C43.1", - "C43.10", - "C43.11", - "C43.111", - "C43.112", - "C43.12", - "C43.121", - "C43.122", - "C43.2", - "C43.20", - "C43.21", - "C43.22", - "C43.3", - "C43.30", - "C43.31", - "C43.39", - "C43.4", - "C43.8", - "C43.9", - "C44", - "C44.9", - "C44.90", - "C79.2", - "C79.9", - "C80.0", - "D03", - "D03.1", - "D03.10", - "D03.11", - "D03.111", - "D03.112", - "D03.12", - "D03.121", - "D03.122", - "D03.2", - "D03.20", - "D03.21", - "D03.22", - "D03.3", - "D03.30", - "D03.39", - "D03.4", - "D03.8", - "D03.9", - "D04", - "D09", - "Z85.820", - "Z86.006", - "Z86.008", - }, - "Mouth": { - "C06", - "C00", - "C00.0", - "C00.1", - "C00.2", - "C00.3", - "C00.4", - "C00.5", - "C00.6", - "C00.8", - "C00.9", - "C01", - "C02", - "C02.0", - "C02.1", - "C02.2", - "C02.3", - "C02.4", - "C02.8", - "C02.9", - "C03", - "C03.0", - "C03.1", - "C03.9", - "C04", - "C04.0", - "C04.1", - "C04.8", - "C04.9", - "C05", - "C05.0", - "C05.1", - "C05.2", - "C05.8", - "C05.9", - "C06", - "C06.0", - "C06.0 ", - "C06.1", - "C06.2", - "C06.8", - "C06.80", - "C06.89", - "C06.9", - "C07", - "C08", - "C08.0", - "C08.1", - "C08.9", - "C09", - "C09.0", - "C09.1", - "C09.8", - "C09.9", - "C10", - "C10.0", - "C10.1", - "C10.2", - "C10.3", - "C10.4", - "C10.8", - "C10.9", - "C11", - "C11.0", - "C11.1", - "C11.2", - "C11.3", - "C11.8", - "C11.9", - "C12", - "C13", - "C13.0", - "C13.1", - "C13.2", - "C13.8", - "C13.9", - "C14", - "C14.0", - "C14.2", - "C14.8", - "C32.0", - "C32.1", - "C32.2", - "C32.3", - "C76.0", - "C77.0", - "D00", - "D00.0", - "D00.00", - "D00.00 ", - "D00.01", - "D00.02", - "D00.02 ", - "D00.03", - "D00.04", - "D00.05", - "D00.06", - "D00.07", - "D00.08", - "D03.0", - "D37", - "D37.0", - "D37.01", - "D37.02", - "D37.03", - "D37.030", - "D37.031", - "D37.032", - "D37.04", - "D37.05", - "D37.09", - }, - "Soft Tissue Sarcoma": { - "C49.0", - "C49.8", - "C49.9", - "C46.1", - }, - "Ear": { - "C30", - "C30.1", - "C30.1 ", - "C44.2", - "C44.20", - "C44.201", - "C44.202", - "C44.209", - "C44.21", - "C44.211", - "C44.212", - "C44.219", - "C44.22", - "C44.221", - "C44.222", - "C44.229", - "C44.29", - "C44.291", - "C44.292", - "C44.299", - "D02", - "D04.2", - "D04.20", - "D04.21", - "D04.22", - "D38", - }, - "Eye": - { - "C44.1", - "C44.10", - "C44.101", - "C44.102", - "C44.1021", - "C44.1022", - "C44.109", - "C44.1091", - "C44.1092", - "C44.11", - "C44.111", - "C44.112", - "C44.1121", - "C44.1122", - "C44.119", - "C44.1191", - "C44.1192", - "C44.12", - "C44.121", - "C44.122", - "C44.1221", - "C44.1222", - "C44.129", - "C44.1291", - "C44.1292", - "C44.13", - "C44.131", - "C44.132", - "C44.1321", - "C44.1322", - "C44.139", - "C44.1391", - "C44.1392", - "C44.19", - "C44.191", - "C44.192", - "C44.1921", - "C44.1922", - "C44.199", - "C44.1991", - "C44.1992", - "C69", - "C69.0", - "C69.00", - "C69.01", - "C69.02", - "C69.1", - "C69.10", - "C69.11", - "C69.12", - "C69.2", - "C69.20", - "C69.21", - "C69.22", - "C69.3", - "C69.30", - "C69.31", - "C69.32", - "C69.4", - "C69.40", - "C69.41", - "C69.42", - "C69.5", - "C69.50", - "C69.51", - "C69.52", - "C69.6", - "C69.60", - "C69.61", - "C69.62", - "C69.8", - "C69.80", - "C69.81", - "C69.82", - "C69.9", - "C69.90", - "C69.91", - "C69.92", - "D09.2 ", - "D09.20", - "D09.21", - "D09.22", - "Z85.840", - }, - "Neurogenic Sarcoma": {"C47", - "C47.0", - "C47.8", - "C47.9", - }, - "Vascular Sarcoma": { - "C46.1", - "C46.0", - "C46.2", - "C46.7", - "C46.9", - }, -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/head_cancer_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/head_cancer_medication.py deleted file mode 100644 index f3d3356a93..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/head_cancer_medication.py +++ /dev/null @@ -1,156 +0,0 @@ -medication_keywords = { - "Bone": { - "dasatinib", - "erlotinib", - "ifex", - "interferon alfa-2a", - "lapatinib", - "lipodox", - "sprycel", - "tarceva", - "tykerb" - }, - "Bone, Eye": { - "gleevec", - "imatinib", - }, - "Bone, Sarcoma (multiple types)": { - "ifosfamide", - "pazopanib", - "regorafenib", - "stivarga", - "sunitinib", - "sutent", - "votrient" - }, - "Ear, Mouth": { - "cetuximab", - "erbitux" - }, - "Eye": { - "aldara", - "braftovi", - "herpesvirus", - "imiquimod", - "imlygic", - "interleukin-2", - "mektovi", - "nilotinib", - "relatlimab", - "talimogene", - "tasigna", - "zyclara" - }, - "Eye, Ear": { - "cobimetinib", - "cotellic", - "ipilimumab", - "vemurafenib", - "yervoy", - "zelboraf" - }, - "Eye, Skin": { - "binimetinib", - "encorafenib", - "kimmtrak", - "tebentafusp", - }, - "Mouth": { - "droxia", - "hydrea", - "hydroxyurea", - "siklos" - }, - "Multiple": { - "abraxane", - "adrucil", - "capecitabine", - "carac", - "carboplatin", - "cisplatin", - "cyclophosphamide", - "dabrafenib", - "dacarbazine", - "diclofenac", - "docefrez", - "docetaxel", - "doxorubicin", - "efudex", - "entrectinib", - "epinephrine", - "etopophos", - "etoposide", - "fluoroplex", - "fluorouracil", - "gavreto", - "keytruda", - "larotrectinib", - "marqibo", - "mekinist", - "methotrexate", - "nexavar", - "nivolumab", - "opdivo", - "opdualag", - "otrexup", - "paclitaxel", - "paraplatin", - "pembrolizumab", - "pralsetinib", - "rasuvo", - "reditrex", - "retevmo", - "rozlytrek", - "selpercatinib", - "sorafenib", - "tafinlar", - "taxotere", - "temodar", - "temozolomide", - "tolak", - "toposar", - "trametinib", - "trexall", - "vincasar", - "vincristine", - "vitrakvi", - "xatmep", - "xeloda" - }, - "Sarcoma (multiple types)": { - "cytarabine", - "daunorubicin", - "ellence", - "epirubicin", - "eribulin", - "fyarro", - "gemcitabine", - "halaven", - "hyftor", - "infugem", - "mesna", - "mesnex", - "navelbine", - "rapamune", - "sirolimus", - "tazemetostat", - "tazverik", - "trabectedin", - "vinorelbine", - "yondelis" - }, - "Sarcoma (multiple types), Skin": { - "bleomycin", - "vinblastine", - }, - "Skin": { - "aldesleukin", - "proleukin", - "peginterferon", - "pegintron", - "sylatron", - "braftovi", - "ropeginterferon", - "besremi", - } -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/kidney_cancer_condtion.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/kidney_cancer_condtion.py deleted file mode 100644 index 101cd81535..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/kidney_cancer_condtion.py +++ /dev/null @@ -1,24 +0,0 @@ -conditions = { - "C64", - "C64.1", - "C64.2", - "C64.9", - "C65", - "C65.1", - "C65.2", - "C65.9", - "C79.0", - "C79.00", - "C79.01", - "C79.02", - "C7A.093", - "D41.00", - "D41.01", - "D41.02", - "D41.10", - "D41.11", - "D41.12", - "D49.511", - "D49.512", - "D49.519" -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/kidney_cancer_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/kidney_cancer_medication.py deleted file mode 100644 index b80be053cb..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/kidney_cancer_medication.py +++ /dev/null @@ -1,40 +0,0 @@ -medications = { - "afinitor", - "aldesleukin", - "alymsys", - "avastin", - "avelumab", - "axitinib", - "bavencio", - "belzutifan", - "bevacizumab", - "cabometyx", - "cabozantinib", - "cometriq", - "everolimus", - "fotivda", - "inlyta", - "interferon", - "intron a", - "keytruda", - "lenvatinib", - "lenvima", - "mvasi", - "nexavar", - "nivolumab", - "opdivo", - "opdualag", - "pazopanib", - "pembrolizumab", - "proleukin", - "sorafenib", - "sunitinib", - "sutent", - "temsirolimus", - "tivozanib", - "torisel", - "votrient", - "welireg", - "zirabev", - "zortress" -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/male_reproductive_condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/male_reproductive_condition.py deleted file mode 100644 index 278fbff3ed..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/male_reproductive_condition.py +++ /dev/null @@ -1,49 +0,0 @@ -condition_dict = { - "Penile": { - "C60", - "C60.0", - "C60.1", - "C60.2", - "C60.8", - "C60.9" - }, - "Prostate": { - "C61" - }, - "Testicular": { - "C62", - "C62.0", - "C62.00", - "C62.01", - "C62.02", - "C62.1", - "C62.10", - "C62.11", - "C62.12", - "C62.9", - "C62.90", - "C62.91", - "C62.92" - }, - "Multiple": { - "C63", - "C63.7", - "C63.8", - "C63.9" - }, - "Epididymis": { - "C63.0", - "C63.00", - "C63.01", - "C63.02" - }, - "Spermatic Cord": { - "C63.1", - "C63.10", - "C63.11", - "C63.12" - }, - "Scrotum": { - "C63.2" - } -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/male_reproductive_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/male_reproductive_medication.py deleted file mode 100644 index d69c19ae94..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/male_reproductive_medication.py +++ /dev/null @@ -1,63 +0,0 @@ -medications = { - "Multiple": { - "capecitabine", - "cisplatin", - "docetaxel", - "docetaxel anhydrous", - "imiquimod", - "xeloda" - }, - "Testicular": { - "apalutamide", - "bicalutamide", - "bleomycin", - "cabazitaxel", - "casodex", - "cosmegen", - "dactinomycin", - "erleada", - "jevtana" - }, - "Prostate": { - "abiraterone", - "abraxane", - "darolutamide", - "degarelix", - "docefrez", - "eligard", - "enzalutamide", - "etopophos", - "etoposide", - "eulexin", - "firmagon", - "fluorouracil", - "flutamide", - "goserelin", - "ifex", - "ifosfamide", - "leuprolide", - "lupron", - "lynparza", - "mitomycin", - "mitoxantrone", - "nilandron", - "nilutamide", - "nubeqa", - "olaparib", - "orgovyx", - "paclitaxel", - "provenge", - "ra-223", - "radium", - "relugolix", - "rubraca", - "rucaparib", - "sipuleucel-t", - "taxotere", - "vinblastine", - "xofigo", - "xtandi", - "yonsa", - "zytiga" - } -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/melanoma_condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/melanoma_condition.py deleted file mode 100644 index 50588efa0b..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/melanoma_condition.py +++ /dev/null @@ -1,118 +0,0 @@ - -condition_codes = { - "C00", - "C20", - "C21", - "C21.0", - "C30.0", - "C30.1", - "C31.9", - "C43-C44", - "C43.0", - "C43.1", - "C43.10", - "C43.11", - "C43.111", - "C43.112", - "C43.12", - "C43.121", - "C43.122", - "C43.2", - "C43.20", - "C43.21", - "C43.22", - "C43.3", - "C43.30", - "C43.31", - "C43.39", - "C43.4", - "C43.5", - "C43.51", - "C43.52", - "C43.59", - "C43.6", - "C43.60", - "C43.61", - "C43.62", - "C43.7", - "C43.70", - "C43.71", - "C43.72", - "C43.8", - "C43.9", - "C44", - "C44.9", - "C44.90", - "C51.9", - "C52", - "C69.00", - "C69.01", - "C69.02", - "C69.20", - "C69.21", - "C69.22", - "C69.30", - "C69.31", - "C69.32", - "C69.40", - "C69.41", - "C69.42", - "C69.90", - "C77.9", - "C78.00", - "C78.01", - "C78.02", - "C78.2", - "C78.7", - "C78.89", - "C79.00", - "C79.01", - "C79.02", - "C79.2", - "C79.51", - "C79.9", - "C80.0", - "D00", - "D01", - "D02", - "D03", - "D03.1", - "D03.10", - "D03.11", - "D03.111", - "D03.112", - "D03.12", - "D03.121", - "D03.122", - "D03.2", - "D03.20", - "D03.21", - "D03.22", - "D03.3", - "D03.30", - "D03.39", - "D03.4", - "D03.5", - "D03.51", - "D03.52", - "D03.59", - "D03.6", - "D03.60", - "D03.61", - "D03.62", - "D03.7", - "D03.70", - "D03.71", - "D03.72", - "D03.8", - "D03.9", - "D04", - "D05", - "D06", - "D07", - "D09", - "Z85.820", - "Z85.840", - "Z86.006", - "Z86.008", -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/melanoma_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/melanoma_medication.py deleted file mode 100644 index e0298961af..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/melanoma_medication.py +++ /dev/null @@ -1,50 +0,0 @@ -medications = {"Biologic response modifier": { - "aldesleukin", - "peginterferon", - "pegintron", - "proleukin", - "sylatron" -}, - "Immunotherapy": { - "besremi", - "ipilimumab", - "keytruda", - "kimmtrak", - "nelatlimab", - "nivolumab", - "opdivo", - "opdualag", - "pembrolizumab", - "relatlimab", - "ropeginterferon", - "tebentafusp", - "yervoy" - }, - "Oncolytic virus therapy": { - "herpesvirus", - "imlygic", - "laherparepvec", - "talimogene" - }, - "Systemic chemotherapy": { - "aldesleukin", - "binimetinib", - "braftovi", - "cotellic", - "dabrafenib", - "dacarbazine", - "encorafenib", - "intron", - "ipilimumab", - "mekinist", - "mektovi", - "peginterferon", - "pegintron", - "proleukin", - "sylatron", - "tafinlar", - "trametinib", - "vemurafenib", - "yervoy", - "zelboraf" - }} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/neck_condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/neck_condition.py deleted file mode 100644 index 3d80b35558..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/neck_condition.py +++ /dev/null @@ -1,129 +0,0 @@ -condition_dict = { - "Bone": { - "C41.2", - "C41.9", - "C79.51", - }, - "Central Nervous System": { - "C70", - "C70.0", - "C70.9", - "C71", - "C71.0", - "C71.1", - "C71.2", - "C71.3", - "C71.4", - "C71.5", - "C71.6", - "C71.7", - "C71.8", - "C71.9", - "C72.2", - "C72.20", - "C72.21", - "C72.22", - "C72.3", - "C72.30", - "C72.31", - "C72.32", - "C72.4", - "C72.40", - "C72.41", - "C72.42", - "C72.50", - "C72.59", - "C72.9", - "C79.3", - "C79.31", - "C79.32", - "C79.4", - "C79.40", - "C79.49", - "D18.02", - "D42.0", - "D42.9", - "D43.0", - "D43.1", - "D43.2", - "D43.3", - "D43.8", - "D43.9", - "D49.6", - "Q85.00", - "Q85.01", - "Q85.02", - "Q85.03", - "Q85.09", - }, - "Endocrine": { - "C73", - "C75", - "C75.0", - "C75.1", - "C75.2", - "C75.9", - "C7A", - "C7A.1", - "C7A.8", - "D09.3", - "D44", - "D44.0", - "D44.2", - "D44.3", - "D44.9", - "D49.7", - }, - "Neurogenic Sarcoma": { - "C47", - "C47.0", - "C47.8", - "C47.9", - }, - "Respiratory": { - "C31.9", - "C32.8", - "C32.9", - "C33", - "C34.0", - "C34.02", - "C39.0", - "D02.1", - "D38.1", - }, - "Skin": { - "C43-C44", - "C43.4", - "C43.8", - "C43.9", - "C44", - "C44.9", - "C44.90", - "C79.2", - "C79.9", - "C80.0", - "D03", - "D03.4", - "D03.8", - "D03.9", - "D04", - "D09", - "Z85.820", - "Z86.006", - "Z86.008", - }, - "Soft Tissue Sarcoma": { - "C49.0", - "C49.8", - "C49.9", - }, - "Soft Tissue Sarcoma, Vascular Sarcoma": { - "C46.1" - }, - "Vascular Sarcoma": { - "C46.0", - "C46.2", - "C46.7", - "C46.9", - } -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/neck_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/neck_medication.py deleted file mode 100644 index e336d2a170..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/neck_medication.py +++ /dev/null @@ -1,224 +0,0 @@ -medications = { - "Bone": { - "dasatinib", - "erlotinib", - "gleevec", - "ifex", - "imatinib", - "interferon", - "lapatinib", - "sprycel", - "tykerb" - }, - "Bone, Endocrine": { - "lipodox" - }, - "Bone, Respiratory": { - "erlotinib", - "tarceva" - }, - "Bone, Sarcoma (multiple types)": { - "ifosfamide", - "pazopanib", - "regorafenib", - "stivarga", - "sunitinib", - "sutent", - "votrient" - }, - "Central Nervous System": { - "alymsys", - "bevacizumab", - "bicnu", - "carmustine", - "everolimus", - "gleostine", - "gliadel", - "hemady", - "lomustine", - "matulane", - "mvasi", - "procarbazine", - "zirabev", - "zortress" - }, - "Endocrine": { - "adriamycin", - "bromocriptine", - "bynfezia", - "cabergoline", - "cabometyx", - "cabozantinib", - "caprelsa", - "cometriq", - "doxil", - "fareston", - "faslodex", - "fulvestrant", - "lanreotide", - "lenvatinib", - "lenvima", - "mycapssa", - "octreotide", - "pasireotide", - "pegvisomant", - "sandostatin", - "signifor", - "somatostatin", - "somatuline", - "somavert", - "streptozocin", - "tamoxifen", - "toremifene", - "vandetanib", - "zanosar" - }, - "Multiple": { - "abraxane", - "adrucil", - "capecitabine", - "carac", - "carboplatin", - "cisplatin", - "cyclophosphamide", - "dabrafenib", - "dacarbazine", - "docefrez", - "docetaxel", - "doxorubicin", - "efudex", - "entrectinib", - "etopophos", - "etoposide", - "fluoroplex", - "fluorouracil", - "gavreto", - "keytruda", - "larotrectinib", - "marqibo", - "mekinist", - "methotrexate", - "nexavar", - "nivolumab", - "opdivo", - "opdualag", - "otrexup", - "paclitaxel", - "paraplatin", - "pembrolizumab", - "pralsetinib", - "rasuvo", - "reditrex", - "retevmo", - "rozlytrek", - "selpercatinib", - "sorafenib", - "tafinlar", - "taxotere", - "temodar", - "temozolomide", - "tolak", - "toposar", - "trametinib", - "trexall", - "vincasar", - "vincristine", - "vitrakvi", - "xatmep", - "xeloda" - }, - "Respiratory": { - "afatinib", - "alecensa", - "alectinib", - "alunbrig", - "amivantamab", - "atezolizumab", - "brigatinib", - "capmatinib", - "ceritinib", - "crizotinib", - "cyramza", - "dacomitinib", - "deruxtecan", - "durvalumab", - "enhertu", - "exkivity", - "gefitinib", - "gilotrif", - "hycamtin", - "imfinzi", - "iressa", - "lorbrena", - "lorlatinib", - "lurbinectedin", - "mobocertinib", - "necitumumab", - "osimertinib", - "portrazza", - "ramucirumab", - "rybrevant", - "tabrecta", - "tagrisso", - "tecentriq", - "tepmetko", - "tepotinib", - "topotecan", - "trastuzumab", - "vizimpro", - "xalkori", - "zepzelca", - "zykadia" - }, - "Respiratory, Central Nervous System": { - "avastin", - "bevacizumab", - "camptosar", - "irinotecan", - "onivyde" - }, - "Sarcoma (multiple types)": { - "daunorubicin", - "ellence", - "epirubicin", - "eribulin", - "fyarro", - "gemcitabine", - "halaven", - "hyftor", - "infugem", - "mesna", - "mesnex", - "navelbine", - "rapamune", - "sirolimus", - "tazemetostat", - "tazverik", - "trabectedin", - "vinorelbine", - "yondelis" - }, - "Sarcoma (multiple types), Skin": { - "bleomycin", - "vinblastine" - }, - "Skin": { - "aldesleukin", - "besremi", - "binimetinib", - "braftovi", - "encorafenib", - "herpesvirus", - "imlygic", - "intron", - "kimmtrak", - "laherparepvec", - "mektovi", - "peginterferonpegintron", - "proleukin", - "ropeginterferon", - "sylatron", - "talimogene", - "tebentafusp" - } -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/pancreatic_condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/pancreatic_condition.py deleted file mode 100644 index 4101607e5a..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/pancreatic_condition.py +++ /dev/null @@ -1,10 +0,0 @@ -condition_codes = {"C25", - "C25.0", - "C25.1", - "C25.2", - "C25.3", - "C25.4", - "C25.7", - "C25.8", - "C25.9", - } diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/pancreatic_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/pancreatic_medication.py deleted file mode 100644 index 784c44117d..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/pancreatic_medication.py +++ /dev/null @@ -1,29 +0,0 @@ -medication_keywords = { - "abraxane", - "adrucil", - "afinitor", - "bynfezia", - "capecitabine", - "docefreztaxotere", - "docetaxel", - "erlotinib", - "everolimus", - "fluorouracil", - "gemcitabine", - "infugem", - "irinotecan", - "lanreotide", - "lynparza", - "mitomycin", - "mycapssasandostatin", - "octreotide", - "olaparib", - "onivyde", - "oxaliplatin", - "paclitaxel", - "sunitinib", - "sutent", - "tarceva", - "xelodacisplatin", - "zortress" -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/prostate_cancer_condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/prostate_cancer_condition.py deleted file mode 100644 index c0856c6342..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/prostate_cancer_condition.py +++ /dev/null @@ -1 +0,0 @@ -condition_codes = {"C61"} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/prostate_cancer_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/prostate_cancer_medication.py deleted file mode 100644 index 6c6151254b..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/prostate_cancer_medication.py +++ /dev/null @@ -1,48 +0,0 @@ -medication_keywords = { - "abiraterone", - "abraxane", - "capecitabine", - "cisplatin", - "darolutamide", - "degarelix", - "docefrez", - "docetaxel", - "eligard", - "enzalutamide", - "etopophos", - "etoposide", - "eulexin", - "firmagon", - "fluorouracil", - "flutamide", - "goserelin", - "ifex", - "ifosfamide", - "imiquimod", - "leuprolide", - "lupron", - "lynparza", - "mitomycin", - "mitoxantrone", - "nilandron", - "nilutamide", - "nubeqa", - "olaparib", - "orgovyx", - "paclitaxel", - "provenge", - "ra-223", - "radium chloride", - "relugolix", - "rubraca", - "rucaparib", - "sipuleucel", - "taxotere", - "vinblastine", - "xeloda", - "xofigo", - "xtandi", - "yonsa", - "zoladex", - "zytiga" - } diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/respiratory_cancer_condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/respiratory_cancer_condition.py deleted file mode 100644 index 4b41d5531a..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/respiratory_cancer_condition.py +++ /dev/null @@ -1,76 +0,0 @@ -condition_dict = { - "Bronchus": { - "C34.0", - "C34.02" - }, - "Larynx": { - "C32.8", - "C32.9" - }, - "Lung": { - "C38.1", - "C38.2", - "C38.3", - "C38.4", - "C38.8", - "C39.9", - "C45.0", - "C46.50", - "C46.51", - "C46.52", - "C76.1", - "C78.00", - "C78.00", - "C78.01", - "C78.01", - "C78.02", - "C78.02", - "C78.1", - "C78.2", - "C78.30", - "C78.39", - "D02.3", - "D02.4", - "D38.2", - "D38.3", - "D38.4", - "D38.5", - "D38.6", - "D49.1", - "J91.0" - }, - "Lung, Bronchus": { - "C34.1", - "C34.10", - "C34.11", - "C34.12", - "C34.2", - "C34.3", - "C34.30", - "C34.31", - "C34.32", - "C34.8", - "C34.80", - "C34.81", - "C34.82", - "C34.9", - "C34.90", - "C34.91", - "C34.92", - "C7A.090", - "D02.20", - "D02.21", - "D02.22" - }, - "Lung, Bronchus, Trachea": { - "D38.1" - }, - "Multiple": { - "C39.0", - "C39.9" - }, - "Trachea": { - "C33", - "D02.1" - } -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/respiratory_cancer_medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/respiratory_cancer_medication.py deleted file mode 100644 index 507cd4556b..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/codesets/respiratory_cancer_medication.py +++ /dev/null @@ -1,113 +0,0 @@ -medications = { - "Lung": { - "otrexup", - "reditrex", - "trexall", - "xatmep" - }, - "Lung (non-small cell)": { - "afatinib", - "afatinib dimaleate", - "alecensa", - "alectinib", - "alunbrig", - "alunbrig initiation pack", - "amivantamab", - "amivantamab-vmjw", - "avastin", - "bevacizumab", - "brigatinib", - "camptosar", - "capmatinib", - "capmatinib hydrochloride", - "ceritinib", - "crizotinib", - "cyramza", - "dabrafenib", - "dabrafenib mesylate", - "dacomitinib", - "enhertu", - "entrectinib", - "erlotinib", - "etopophos", - "etoposide", - "etoposide phosphate", - "exkivity", - "fam-trastuzumab deruxtecan-nxki", - "gavreto", - "gefitinib", - "gilotrif", - "hycamtin", - "injection", - "iressa", - "irinotecan", - "irinotecan hydrochloride", - "irinotecan hydrochloride liposome", - "irinotecan liposomal", - "larotrectinib", - "larotrectinib sulfate", - "lorbrena", - "lorlatinib", - "lung (non small cell), pharynx", - "lurbinectedin", - "mekinist", - "mobocertinib", - "mobocertinib succinate", - "necitumumab", - "onivyde", - "osimertinib", - "osimertinib mesylate", - "portrazza", - "pralsetinib", - "ramucirumab", - "retevmo", - "rozlytrek", - "rybrevant", - "selpercatinib", - "tabrecta", - "tafinlar", - "tagrisso", - "tarceva", - "tepmetko", - "tepotinib", - "tepotinib hydrochloride", - "toposar", - "topotecan", - "topotecan hydrochloride", - "trametinib", - "trametinib dimethyl sulfoxide", - "trastuzumab", - "vitrakvi", - "vizimpro", - "xalkori", - "zepzelca", - "zykadia" - }, - "Lung (small cell)": { - "atezolizumab", - "durvalumab", - "imfinzi", - "tecentriq" - }, - "Multiple": { - "abraxane", - "capecitabine", - "carboplatin", - "cisplatin", - "docetaxel", - "docetaxel anhydrous", - "keytruda", - "methotrexate", - "methotrexate auto-injector", - "methotrexate auto-injector [otrexup]", - "methotrexate sodium", - "nivolumab", - "opdivo", - "paclitaxel", - "paclitaxel poliglumex", - "paclitaxel protein-bound", - "paraplatin", - "pembrolizumab", - "xeloda" - } -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/condition.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/condition.py deleted file mode 100644 index 76e02d5139..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/condition.py +++ /dev/null @@ -1,159 +0,0 @@ -from datetime import datetime - -from dateutil.relativedelta import relativedelta - -from .codesets import (brain_cancer_condition, breast_cancer_condition, - gi_condition, gyn_cancer_condition, - head_cancer_condition, kidney_cancer_condtion, - male_reproductive_condition, melanoma_condition, - neck_condition, pancreatic_condition, - prostate_cancer_condition, respiratory_cancer_condition) - -conditions_codeset_map = {"head": head_cancer_condition.conditions_dict, - "neck": neck_condition.condition_dict, - "male_reproductive": male_reproductive_condition.condition_dict, - "gyn": gyn_cancer_condition.condition_dict, - "prostate": prostate_cancer_condition.condition_codes, - "melanoma": melanoma_condition.condition_codes, - "pancreatic": pancreatic_condition.condition_codes, - "breast": breast_cancer_condition.condition_codes, - "gi": gi_condition.condition_codes, - "kidney": kidney_cancer_condtion.conditions, - "brain": brain_cancer_condition.conditions, - "respiratory": respiratory_cancer_condition.condition_dict} - - -# pancreatic, prostate, male reproductive, breast, gyn, gi, melanoma, kidney: condition and medication 6 months -# BRAIN: 2 years - - -# head: six months -# prior to the date of the claim for soft tissue sarcomas, ear cancers, eye cancers, mouth cancers, and malignant -# skin neoplasms, or within one year prior to the date of the claim for bone cancers, six months prior to the date of -# the claim) for soft tissue sarcomas, ear cancers, eye cancers, and mouth cancers, within one year prior to the date -# of the claim for bone cancers; or Veteran received a medication labeled as “systemic chemotherapy” within six -# months prior to the date of the claim for malignant skin neoplasms - - -# NECK: Veteran's initial cancer diagnosis date (captured in the “Condition.onset[dateTime]” element) is within six -# months prior to the date of the claim for soft tissue sarcomas, respiratory cancers, endocrine cancers, -# and malignant skin neoplasms, within one year prior to the date of the claim for bone cancers, or within two years -# prior to the date of the claim for central nervous system cancers. Veteran received a matched medication within six -# months prior to the date of the claim (i.e., “MedicationRequest.dosageInstruction.[x].timing.repeat.boundsPeriod” -# within six months prior to the date of the claim) for soft tissue sarcomas, respiratory cancers, and endocrine -# cancers, within one year prior to the date of the claim for bone cancers, or within two years prior to the date of -# the claim for central nervous system cancers; or Veteran received a medication labeled as “systemic chemotherapy” -# within six months prior to the date of the claim for malignant skin neoplasms - -def categorize_condition(condition_code, condition_dict): - """ - Return the category that a medication belongs to. If it does not belong to any, return an empty list. - - :param condition_dict: dictionary of specific cancer type and codes - :param condition_code: code belonging to veterans medical record - :return: list - """ - condition_category = str() - for category_id in list(condition_dict.keys()): - for cancer_condition_code in condition_dict[category_id]: - if condition_code == cancer_condition_code: - condition_category = category_id - break - return condition_category - - -def date_util(relevant_conditions, date_of_claim, months): - """ - Compare date of cancer condition to the date of claim to determine if diagnosis is recent. - - :param relevant_conditions: list of relevant conditions - :param date_of_claim: date of claim - :param months: time constraint - :return: True if the conditions meet ddate requirements, otherwise False - """ - date_spec = False - for condition in relevant_conditions: - if datetime.strptime(condition["onsetDate"], "%Y-%m-%d").date() >= date_of_claim - relativedelta( - months=months): - date_spec = True - - return date_spec - - -def date_util_multiple_types(relevant_conditions, date_of_claim): - """ - Compare date of cancer condition to the date of claim to determine if diagnosis is recent. For head and - neck cancers, the type of cancers vary the date specifications. - - :param relevant_conditions: list of relevant conditions - :param date_of_claim: date of claim - :return: True if the conditions meet ddate requirements, otherwise False - """ - date_spec = False - for condition in relevant_conditions: - if condition["suggestedCategory"] == "Bone": - if datetime.strptime(condition["onsetDate"], "%Y-%m-%d").date() >= date_of_claim - relativedelta( - months=12): - date_spec = True - if condition["suggestedCategory"] == "Central Nervous System": - if datetime.strptime(condition["onsetDate"], "%Y-%m-%d").date() >= date_of_claim - relativedelta( - months=24): - date_spec = True - else: - if datetime.strptime(condition["onsetDate"], "%Y-%m-%d").date() >= date_of_claim - relativedelta( - months=6): - date_spec = True - - return date_spec - - -def active_cancer_condition(request_body, cancer_type): - """ - Determine if there is an active cancer diagnosis - - :param cancer_type: general area of cancer that is being adjudicated - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - - relevant_conditions = [] - response = {} - conditions_meet_date_requirements = False - date_of_claim = request_body["dateOfClaim"] - date_of_claim_date = datetime.strptime(date_of_claim, "%Y-%m-%d").date() - - condition_codes = conditions_codeset_map[cancer_type] - - if type(condition_codes) == dict: - for condition in request_body["evidence"]["conditions"]: - - condition_code = condition["code"] - condition_category = categorize_condition(condition_code, condition_codes) - if condition_category: - condition["suggestedCategory"] = condition_category - relevant_conditions.append(condition) - - if type(condition_codes) == set: - for condition in request_body["evidence"]["conditions"]: - condition_code = condition["code"] - for cancer_condition_code in condition_codes: - if cancer_condition_code == condition_code: - relevant_conditions.append(condition) - - if cancer_type in ["pancreatic", "prostate", "male_reproductive", "breast", "gyn", "gi", "melanoma", "kidney"]: - conditions_meet_date_requirements = date_util(relevant_conditions, date_of_claim_date, months=6) - - if cancer_type == "brain": - conditions_meet_date_requirements = date_util(relevant_conditions, date_of_claim_date, months=24) - - if cancer_type in ["head", "neck"]: - conditions_meet_date_requirements = date_util_multiple_types(relevant_conditions, date_of_claim_date) - - response.update({"conditions": relevant_conditions, - "conditionsMeetDateRequirements": conditions_meet_date_requirements, - "conditionsCount": len(request_body["evidence"]["conditions"]), - "relevantConditionsCount": len(relevant_conditions)}) - - return response diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/main.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/main.py deleted file mode 100644 index a1d195cf7f..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/main.py +++ /dev/null @@ -1,56 +0,0 @@ -import logging -from datetime import date -from typing import Dict - -import data_model - -from . import condition, medication - - -def assess_cancer(event: Dict): - """ - Take a request that includes asthma related data, and return a filtered response - - :param event: request body - :type event: dict - :return: response body - :rtype: dict - """ - validation_results = data_model.validate_request_body(event) - response_body = {} - cancer_type = "respiratory" - if "dateOfClaim" not in event: - event["dateOfClaim"] = str(date.today()) - - if validation_results["is_valid"]: - medications = medication.medication_match(event, cancer_type) - conditions = condition.active_cancer_condition(event, cancer_type) - sufficient = None - - if conditions["relevantConditionsCount"] > 0: - if any({medications["medicationMeetsDateRequirements"], conditions["conditionsMeetDateRequirements"]}): - sufficient = True # Proceed with fast track - else: - sufficient = False # Order an exam - - response_body.update( - { - "evidence": { - "medications": medications["medications"], - "conditions": conditions["conditions"] - }, - "evidenceSummary": { - "relevantMedCount": medications["relevantMedCount"], - "totalMedCount": medications["totalMedCount"], - "conditionsCount": conditions["conditionsCount"], - "relevantConditionsCount": conditions["relevantConditionsCount"] - }, - "sufficientForFastTracking": sufficient, - } - ) - logging.info("Message processed successfully") - else: - logging.info(f"Message failed to process due to: {validation_results['errors']}") - response_body["errorMessage"] = "error validating request message data" - - return response_body diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/medication.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/medication.py deleted file mode 100644 index cb915078ae..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/medication.py +++ /dev/null @@ -1,140 +0,0 @@ -from datetime import datetime - -from dateutil.relativedelta import relativedelta - -from .codesets import (brain_cancer_medication, breast_cancer_medication, - gi_medication, gyn_cancer_medication, - head_cancer_medication, kidney_cancer_medication, - male_reproductive_medication, melanoma_medication, - neck_medication, pancreatic_medication, - prostate_cancer_medication, - respiratory_cancer_medication) - -medication_codeset_map = {"head": head_cancer_medication.medication_keywords, - "neck": neck_medication.medications, - "male_reproductive": male_reproductive_medication.medications, - "gyn": gyn_cancer_medication.medications, - "prostate": prostate_cancer_medication.medication_keywords, - "melanoma": melanoma_medication.medications, - "pancreatic": pancreatic_medication.medication_keywords, - "breast": breast_cancer_medication.medication_keywords, - "gi": gi_medication.medications, - "kidney": kidney_cancer_medication.medications, - "brain": brain_cancer_medication.medications, - "respiratory": respiratory_cancer_medication.medications} - - -def categorize_med(medication_display, medication_dict): - """ - Return the category that a medication belongs to. If it does not belong to any, return an empty list. - - :param medication_dict: - :param medication_display: medication text - :return: list - """ - medication_category = str() - for category_id in list(medication_dict.keys()): - for medication in medication_dict[category_id]: - if medication.lower() in medication_display.lower(): - medication_category = category_id - break - return medication_category - - -def date_util(relevant_medications, date_of_claim, months): - """ - Compare date of cancer condition to the date of claim to determine if diagnosis is recent. - - :param relevant_medications: list of relevant conditions - :param date_of_claim: date of claim - :param months: time constraint - :return: True if the conditions meet ddate requirements, otherwise False - """ - date_spec = False - for medication in relevant_medications: - if datetime.strptime(medication["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date() >= date_of_claim - relativedelta( - months=months): - date_spec = True - - return date_spec - - -def date_util_multiple_types(relevant_medications, date_of_claim): - """ - Compare date of cancer condition to the date of claim to determine if diagnosis is recent. For head and - neck cancers, the type of cancers vary the date specifications. - - :param relevant_medications: list of relevant conditions - :param date_of_claim: date of claim - :return: True if the conditions meet ddate requirements, otherwise False - """ - date_spec = False - for medication in relevant_medications: - if "Bone" in medication["suggestedCategory"]: - if datetime.strptime(medication["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date() >= date_of_claim - relativedelta( - months=12): - date_spec = True - if "Central Nervous System" in medication["suggestedCategory"]: - if datetime.strptime(medication["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date() >= date_of_claim - relativedelta( - months=24): - date_spec = True - else: - if datetime.strptime(medication["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date() >= date_of_claim - relativedelta( - months=6): - date_spec = True - - return date_spec - - -def medication_match(request_body, cancer_type): - """ - Determine if there is the veteran requires continuous medication for cancer - - :param cancer_type: - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - response = {} - relevant_medications = [] - medication_meets_date_requirements = False - date_of_claim = request_body["dateOfClaim"] - date_of_claim_date = datetime.strptime(date_of_claim, "%Y-%m-%d").date() - - medication_keywords = medication_codeset_map[cancer_type] - - if type(medication_keywords) == dict: - for medication in request_body["evidence"]["medications"]: - medication_display = medication["description"] - medication_category = categorize_med(medication_display, medication_keywords) - if medication_category: - medication["conditionRelated"] = True - medication["suggestedCategory"] = medication_category - relevant_medications.append(medication) - - if type(medication_keywords) == set: - for medication in request_body["evidence"]["medications"]: - medication_display = medication["description"] - for med in [x.lower() for x in medication_keywords]: - if med in medication_display.lower(): - medication["conditionRelated"] = True - relevant_medications.append(medication) - break - - if cancer_type in ["pancreatic", "prostate", "male_reproductive", "breast", "gyn", "gi", "melanoma", "kidney"]: - medication_meets_date_requirements = date_util(relevant_medications, date_of_claim_date, months=6) - if cancer_type in ["neck", "head"]: - medication_meets_date_requirements = date_util_multiple_types(relevant_medications, date_of_claim_date) - - relevant_medications = sorted( - relevant_medications, - key=lambda i: datetime.strptime(i["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date(), - reverse=True, - ) - response.update({ - "medications": relevant_medications, - "medicationMeetsDateRequirements": medication_meets_date_requirements, - "relevantMedCount": len(relevant_medications), - "totalMedCount": len(request_body["evidence"]["medications"])}) - return response diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/queues.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/queues.py deleted file mode 100644 index 7b77b31125..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/queues.py +++ /dev/null @@ -1,45 +0,0 @@ -import json -import logging - -import pika - -from . import main -from .settings import queue_config - -EXCHANGE = queue_config["exchange_name"] -SERVICE_QUEUE = queue_config["service_queue_name"] - - -def on_request_callback(channel, method, properties, body): - binding_key = method.routing_key - message = json.loads(body.decode("utf-8")) - logging.info(f" [x] {binding_key}: Received message.") - try: - response = main.assess_cancer(message) - except Exception as e: - logging.error(e, exc_info=True) - response = {"status": "ERROR", "evidence": {}, "evidenceSummary": {}} - - channel.basic_publish( - exchange=EXCHANGE, - routing_key=properties.reply_to, - properties=pika.BasicProperties(correlation_id=properties.correlation_id), - body=json.dumps(response), - ) - logging.info(f" [x] {binding_key}: Message sent.") - - -def queue_setup(channel): - channel.exchange_declare( - exchange=EXCHANGE, exchange_type="direct", durable=True, auto_delete=True - ) - channel.queue_declare(queue=SERVICE_QUEUE, durable=True, auto_delete=True) - channel.queue_bind(queue=SERVICE_QUEUE, exchange=EXCHANGE) - - channel.basic_qos(prefetch_count=250) - channel.basic_consume( - queue=SERVICE_QUEUE, on_message_callback=on_request_callback, auto_ack=True - ) - logging.info( - f" [*] Waiting for data for queue: {SERVICE_QUEUE}. To exit press CTRL+C" - ) diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/settings.py b/domain-rrd/service-python/svc-assessclaimcancer/src/lib/settings.py deleted file mode 100644 index b45832c7dd..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/lib/settings.py +++ /dev/null @@ -1,4 +0,0 @@ -queue_config = { - "exchange_name": "health-assess-exchange", - "service_queue_name": "health-sufficiency-assess.cancer", -} diff --git a/domain-rrd/service-python/svc-assessclaimcancer/src/requirements.txt.bak b/domain-rrd/service-python/svc-assessclaimcancer/src/requirements.txt.bak deleted file mode 100644 index 1df81b0f1e..0000000000 --- a/domain-rrd/service-python/svc-assessclaimcancer/src/requirements.txt.bak +++ /dev/null @@ -1,3 +0,0 @@ -cerberus==1.3.4; -pika==1.3.1 -python-dateutil==2.8.2; diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/__init__.py b/domain-rrd/service-python/svc-assessclaimdc6510/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/build.gradle.bak b/domain-rrd/service-python/svc-assessclaimdc6510/build.gradle.bak deleted file mode 100644 index 8e44cd91bd..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6510/build.gradle.bak +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id 'local.python.container-service-conventions' -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/__init__.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/__init__.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/codesets/__init__.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/codesets/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/codesets/condition_codesets.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/codesets/condition_codesets.py deleted file mode 100644 index 8c0d99893f..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/codesets/condition_codesets.py +++ /dev/null @@ -1,27 +0,0 @@ -rhinosinusitis = { - "J32.9", - "J32.9" -} -sinusitis = { - "J32", - "J32.0", - "J32.1", - "J32.2", - "J32.3", - "J32.4", - "J32.8", - "J32.9", - "J32.9", - "J32.9", - "J32.9", - "J32.9", - "J32.9", - "J32.9", - "J32.9", -} - -osteomyelitis = { - "H05.029", - "M27.2", - "M86.68", -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/codesets/medication_codesets.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/codesets/medication_codesets.py deleted file mode 100644 index d6099afa87..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/codesets/medication_codesets.py +++ /dev/null @@ -1,17 +0,0 @@ -antibiotics = { - "Augmentin", - "Bactrim", - "Levaquin", - "SMX", - "Septra", - "Sulfatrim", - "TRI-PAK", - "Z-PAK", - "Zithromax", - "amoxicillin", - "azithromycin", - "clavulanate", - "levoFLOXacin", - "sulfamethoxazole", - "trimethoprim", -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/codesets/procedure_codesets.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/codesets/procedure_codesets.py deleted file mode 100644 index f1a0de78d0..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/codesets/procedure_codesets.py +++ /dev/null @@ -1,71 +0,0 @@ -radical_surgery = { - "00160", - "00162", - "31030", - "31032", - "31051", - "31200", - "31201", - "31205", - "31225", - "31230", - "31253", - "31254", - "31255", - "31257", - "31259", - "61580", - "61581", - "61583", - "1005781", - "1005785", - "1031038" -} -surgery = { - "30140", - "30250", - "30801", - "31020", - "31050", - "31070", - "31075", - "31080", - "31081", - "31085", - "31086", - "31087", - "31090", - "31233", - "31235", - "31238", - "31239", - "31256", - "31287", - "31288", - "31291", - "31292", - "31294", - "31295", - "31297", - "31299", - "1002813", - "1005758", - "1005759", - "1005763", - "1005763", - "1005770", - "1005780", - "1005788", - "1005792", - "1005805", - "1014605", - "1018141", - "1035648", - "1005744", - "30130", - "30802", - "31237", - "31240", - "31296", - "0406T" -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/condition.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/condition.py deleted file mode 100644 index e02e6bd7aa..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/condition.py +++ /dev/null @@ -1,47 +0,0 @@ -from datetime import datetime - -from dateutil.relativedelta import relativedelta - -from .codesets import condition_codesets - - -def conditions_calculation(request_body): - """ - Determine if there is the veteran requires continuous medication for hypertension - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - response = {} - relevant_conditions = [] - - veterans_conditions = request_body["evidence"]["conditions"] - total_conditions_count = len(veterans_conditions) - date_of_claim = datetime.strptime(request_body["dateOfClaim"], "%Y-%m-%d").date() - constant_sinusitis = False - osteomyelitis = False - - for condition in veterans_conditions: - if condition["status"].lower() in ["active", "recurrence", "relapse"]: - condition_code = condition["code"] - if condition_code in condition_codesets.sinusitis or condition_code in condition_codesets.rhinosinusitis: - relevant_conditions.append(condition) - if datetime.strptime(condition["onsetDate"], "%Y-%m-%d").date() <= date_of_claim - relativedelta( - months=3): - constant_sinusitis = True - if condition_code in condition_codesets.osteomyelitis: - relevant_conditions.append(condition) - osteomyelitis = True - - response.update( - { - "conditions": relevant_conditions, - "relevantConditionsCount": len(relevant_conditions), - "totalConditionsCount": total_conditions_count, - "constantSinusitis": constant_sinusitis, - "osteomyelitis": osteomyelitis - } - ) - - return response diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/main.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/main.py deleted file mode 100644 index 7e0cb387a0..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/main.py +++ /dev/null @@ -1,62 +0,0 @@ -import logging -from datetime import date -from typing import Dict - -import data_model - -from . import condition, medication, procedure - - -def assess_sinusitis(event: Dict): - """ - Take a request that includes hypertension related data, and return a response - - :param event: request body - :type event: dict - :return: response body - :rtype: dict - """ - validation_results = data_model.validate_request_body(event) - - response_body = {} - if "dateOfClaim" not in event: - event["dateOfClaim"] = str(date.today()) - - if validation_results["is_valid"]: - active_medications = medication.medication_required(event) - conditions = condition.conditions_calculation(event) - procedures = procedure.procedures_calculation(event) - - sufficient = None - if len(conditions["conditions"]) >= 1: - if procedures["multipleSurgery"] or conditions["constantSinusitis"] or \ - procedures["radicalSurgery"] or conditions["osteomyelitis"]: - sufficient = True - else: - sufficient = False - response_body.update( - { - "evidence": { - "medications": active_medications["medications"], - "conditions": conditions["conditions"], - "procedures": procedures["procedures"] - }, - "evidenceSummary": { - "relevantMedCount": active_medications["relevantMedCount"], - "totalMedCount": active_medications["totalMedCount"], - "relevantConditionsCount": conditions["relevantConditionsCount"], - "totalConditionsCount": conditions["totalConditionsCount"], - "relevantProceduresCount": procedures["relevantProceduresCount"], - "totalProceduresCount": procedures["totalProceduresCount"], - }, - "sufficientForFastTracking": sufficient, - "claimSubmissionId": event['claimSubmissionId'] - } - ) - logging.info(f"claimSubmissionId: {event['claimSubmissionId']}, message processed successfully") - else: - logging.info(f"claimSubmissionId: {event['claimSubmissionId']}, message failed to process due to: {validation_results['errors']}") - response_body["errorMessage"] = "error validating request message data" - response_body["claimSubmissionId"] = event['claimSubmissionId'] - - return response_body diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/medication.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/medication.py deleted file mode 100644 index 9d09c5657c..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/medication.py +++ /dev/null @@ -1,49 +0,0 @@ -from datetime import datetime - -from .codesets import medication_codesets - - -def medication_required(request_body): - """ - Determine if there is the veteran requires continuous medication for hypertension - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - response = {} - relevant_medications = [] - other_medications = [] - - veterans_medication = request_body["evidence"]["medications"] - for medication in veterans_medication: - if medication["status"].lower() == "active": - flagged = False - medication_display = medication["description"] - for keyword in medication_codesets.antibiotics: - if keyword in medication_display.lower(): - medication["conditionRelated"] = True - relevant_medications.append(medication) - flagged = True - break - if not flagged: - medication["conditionRelated"] = False - other_medications.append(medication) - - relevant_medications = sorted( - relevant_medications, - key=lambda i: datetime.strptime(i["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date(), - reverse=True, - ) - other_medications = sorted( - other_medications, - key=lambda i: datetime.strptime(i["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date(), - reverse=True, - ) - - response["relevantMedCount"] = len(relevant_medications) - relevant_medications.extend(other_medications) - response["totalMedCount"] = len(relevant_medications) - response["medications"] = relevant_medications - - return response diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/procedure.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/procedure.py deleted file mode 100644 index f6c1ee6e29..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/procedure.py +++ /dev/null @@ -1,50 +0,0 @@ -from datetime import datetime - -from .codesets import procedure_codesets - - -def procedures_calculation(request_body): - """ - Determine if there is the veteran requires continuous medication for hypertension - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - response = {} - relevant_procedures = [] - radical_procedures = [] - radical_surgery_procedure = False - multiple_surgery = False - - veterans_procedures = request_body["evidence"]["procedures"] - procedures_count = len(veterans_procedures) - for procedure in veterans_procedures: - if procedure["status"].lower() in ["in-progress", "on-hold", "stopped", "completed"]: - procedure_code = procedure["code"] - if procedure_code in procedure_codesets.surgery: - relevant_procedures.append(procedure) - elif procedure_code in procedure_codesets.radical_surgery: - radical_surgery_procedure = True - radical_procedures.append(procedure) - - if len(relevant_procedures) >= 2: - multiple_surgery = True - - relevant_procedures.extend(radical_procedures) - - relevant_procedures = sorted( - relevant_procedures, - key=lambda i: datetime.strptime(i["performedDate"], "%Y-%m-%d").date(), - reverse=True, - ) - - response.update({ - "procedures": relevant_procedures, - "relevantProceduresCount": len(relevant_procedures), - "totalProceduresCount": procedures_count, - "radicalSurgery": radical_surgery_procedure, - "multipleSurgery": multiple_surgery - }) - - return response diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/queues.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/queues.py deleted file mode 100644 index 982f2625b3..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/queues.py +++ /dev/null @@ -1,45 +0,0 @@ -import json -import logging - -import pika - -from . import main -from .settings import queue_config - -EXCHANGE = queue_config["exchange_name"] -SERVICE_QUEUE = queue_config["service_queue_name"] - - -def on_request_callback(channel, method, properties, body): - binding_key = method.routing_key - message = json.loads(body.decode("utf-8")) - logging.info(f"claimSubmissionId: {message['claimSubmissionId']}, health data received by {binding_key} processor") - try: - response = main.assess_sinusitis(message) - except Exception as e: - logging.error(e, exc_info=True) - response = {"evidence": None, "evidenceSummary": None, "errorMessage": str(e), "claimSubmissionId": message['claimSubmissionId']} - - channel.basic_publish( - exchange=EXCHANGE, - routing_key=properties.reply_to, - properties=pika.BasicProperties(correlation_id=properties.correlation_id), - body=json.dumps(response), - ) - logging.info(f"claimSubmissionId: {response['claimSubmissionId']}, evaluation sent by {binding_key} processor") - - -def queue_setup(channel): - channel.exchange_declare( - exchange=EXCHANGE, exchange_type="direct", durable=True, auto_delete=True - ) - channel.queue_declare(queue=SERVICE_QUEUE, durable=True, auto_delete=True) - channel.queue_bind(queue=SERVICE_QUEUE, exchange=EXCHANGE) - - channel.basic_qos(prefetch_count=250) - channel.basic_consume( - queue=SERVICE_QUEUE, on_message_callback=on_request_callback, auto_ack=True - ) - logging.info( - f" [*] Waiting for data for queue: {SERVICE_QUEUE}. To exit press CTRL+C" - ) diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/settings.py b/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/settings.py deleted file mode 100644 index 22bd48942d..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6510/src/lib/settings.py +++ /dev/null @@ -1,4 +0,0 @@ -queue_config = { - "exchange_name": "health-assess-exchange", - "service_queue_name": "health-sufficiency-assess.sinusitis", -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6510/src/requirements.txt.bak b/domain-rrd/service-python/svc-assessclaimdc6510/src/requirements.txt.bak deleted file mode 100644 index 569b8b8922..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6510/src/requirements.txt.bak +++ /dev/null @@ -1,6 +0,0 @@ -cerberus==1.3.4; python_version >= "2.7" -pika==1.2.1 -python-dateutil==2.8.2; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0") -python-dotenv==0.20.0 -python-util==1.2.1 -six==1.16.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" diff --git a/domain-rrd/service-python/svc-assessclaimdc6522/build.gradle.bak b/domain-rrd/service-python/svc-assessclaimdc6522/build.gradle.bak deleted file mode 100644 index 8e44cd91bd..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6522/build.gradle.bak +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id 'local.python.container-service-conventions' -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/codesets/rhinitis_conditions.py b/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/codesets/rhinitis_conditions.py deleted file mode 100644 index f198275eac..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/codesets/rhinitis_conditions.py +++ /dev/null @@ -1,19 +0,0 @@ -rhinitis_conditions_list = { - "J30.0", - "J30.1", - "J30.2", - "J30.5", - "J30.81", - "J30.89", - "J30.89", - "J30.9", - "J34.81", - "J45.909", - "J00", -} - -nasal_polyps = {"J33.9"} - -rhinoscleroma = {"A48.8"} - -granulomatous_rhinitis = {"J31.0"} diff --git a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/codesets/rhinitis_medication.py b/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/codesets/rhinitis_medication.py deleted file mode 100644 index 1a75784145..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/codesets/rhinitis_medication.py +++ /dev/null @@ -1,98 +0,0 @@ -rhinitis_med = { - "Antihistamine / Corticosteroid": [ - "fluticasone", - "Dymista", - ], - "Antihistamine / Decongestant": [ - "pseudoephedrine", - "Sudafed", - "A-Phedrin", - "Allegra-D", - "Aphedrid", - "Bromfed DM", - "Cheratussin DAC", - "Claritin-D", - "Genaphed", - "Histafed", - "Nucofed", - "P-V-Tussin", - "Q-Fed", - "Semprex-D", - "Sudogest", - "Vi-Sudo", - "ZyrTEC-D", - "Clarinex-D", - "Contac Cold", - "Alavert D", - "Wal-Phed", - "Ambifed-G CD", - "Ambifed CD", - "Tekral", - "Mar-cof BP", - "Aller-Tec D", - "Wal Zyr D", - "Cetiri-D", - "Biotussin", - "Wal-Act", - "Wal-itin D", - "Lortuss EX", - "Wal-Fex D", - "M-End Max D", - "Stahist AD", - "Statuss Green" - "Zephrex-D", - "Nexafed", - "Allerclear", - "Zodryl DEC", - "Zodryl DAC", - "Hycofenix", - "Wal-Dryl-D Allergy", - ], - "Antihistimine": [ - "diphenhydrAMINE", - "azelastine", - "cetirizine", - "loratadine", - "ZyrTEC", - "fexofenadine", - "Benadryl", - "Claritin", - "Astelin", - "desloratadine", - "Clarinex", - "Allegra", - "levocetirizine", - "Xyzal", - ], - "Bronchodilator": [ - "ipratropium", - "Atrovent", - ], - "Corticosteroid": [ - "beclomethasone", - "triamcinolone", - "budesonide", - "flunisolide", - "fluticasone", - "Flonase", - "mometasone", - "Beconase", - "Nasacort", - "Nasonex", - "Rhinocort", - "Qvar", - "ciclesonide", - "Omnaris", - "Veramyst", - "Aerospan", - "Qnasl", - ], - "Leukotriene Receptor Antagonists": [ - "montelukast", - "Singulair", - ], - "Mast cell stablizer": [ - "cromolyn", - "Nasalcrom", - ] -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/codesets/rhinitis_procedures.py b/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/codesets/rhinitis_procedures.py deleted file mode 100644 index 7097dcbb04..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/codesets/rhinitis_procedures.py +++ /dev/null @@ -1,9 +0,0 @@ -procedures = { - "95115", - "95117", - "95120", - "95125", - "95144", - "95165", - "95199" -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/conditions.py b/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/conditions.py deleted file mode 100644 index 57aa01cd49..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/conditions.py +++ /dev/null @@ -1,47 +0,0 @@ - -from .codesets import rhinitis_conditions - - -def conditions_calculation(request_body): - """ - Determine if there is the veteran requires continuous medication for hypertension - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - response = {} - relevant_conditions = [] - - veterans_conditions = request_body["evidence"]["conditions"] - total_conditions_count = len(veterans_conditions) - diagnostic_codes = [] - nasal_polyps = False - - for condition in veterans_conditions: - if condition["status"].lower() in ["active", "recurrence", "relapse"]: - condition_code = condition["code"] - if condition_code in rhinitis_conditions.rhinitis_conditions_list: - relevant_conditions.append(condition) - diagnostic_codes.append("6522") - elif condition_code in rhinitis_conditions.granulomatous_rhinitis: - relevant_conditions.append(condition) - diagnostic_codes.append("6524") - elif condition_code in rhinitis_conditions.rhinoscleroma: - relevant_conditions.append(condition) - diagnostic_codes.append("6523") - elif condition_code in rhinitis_conditions.nasal_polyps: - nasal_polyps = True - relevant_conditions.append(condition) - - response.update( - { - "conditions": relevant_conditions, - "relevantConditionsCount": len(relevant_conditions), - "totalConditionsCount": total_conditions_count, - "diagnosticCodes": diagnostic_codes, - "nasalPolyps": nasal_polyps - } - ) - - return response diff --git a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/main.py b/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/main.py deleted file mode 100644 index fed548950d..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/main.py +++ /dev/null @@ -1,57 +0,0 @@ -import logging -from typing import Dict - -import data_model - -from . import conditions, medication, procedure - - -def assess_rhinitis(event: Dict): - """ - Take a request that includes asthma related data, and return a filtered response - - :param event: request body - :type event: dict - :return: response body - :rtype: dict - """ - validation_results = data_model.validate_request_body(event) - response_body = {} - - if validation_results["is_valid"]: - active_medications = medication.medication_required(event) - relevant_conditions = conditions.conditions_calculation(event) - procedures = procedure.procedures_calculation(event) - - sufficient = None - if len(relevant_conditions["conditions"]) >= 1: - if "6523" in relevant_conditions["diagnosticCodes"] or relevant_conditions["nasalPolyps"]: - sufficient = True - else: - sufficient = False - response_body.update( - { - "evidence": { - "medications": active_medications["medications"], - "conditions": relevant_conditions["conditions"], - "procedures": procedures["procedures"] - }, - "evidenceSummary": { - "relevantMedCount": active_medications["relevantMedCount"], - "totalMedCount": active_medications["totalMedCount"], - "relevantConditionsCount": relevant_conditions["relevantConditionsCount"], - "totalConditionsCount": relevant_conditions["totalConditionsCount"], - "diagnosticCodes": relevant_conditions["diagnosticCodes"], - "relevantProceduresCount": procedures["relevantProceduresCount"], - "totalProceduresCount": procedures["totalProceduresCount"], - }, - "sufficientForFastTracking": sufficient, - } - ) - logging.info(f"claimSubmissionId: {event['claimSubmissionId']}, message processed successfully") - else: - logging.info(f"claimSubmissionId: {event['claimSubmissionId']}, message failed to process due to: {validation_results['errors']}") - response_body["errorMessage"] = "error validating request message data" - response_body["claimSubmissionId"] = event['claimSubmissionId'] - - return response_body diff --git a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/medication.py b/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/medication.py deleted file mode 100644 index 5ff7654858..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/medication.py +++ /dev/null @@ -1,66 +0,0 @@ -from datetime import datetime - -from .codesets import rhinitis_medication - - -def categorize_med(medication_display): - """ - Return the category that a medication belongs to. If it does not belong to any, return an empty list. - :param medication_display: medication text - :return: list - """ - medication_dict = rhinitis_medication.rhinitis_med - medication_category = str() - for category_id in list(medication_dict.keys()): - if medication_category: - break - for medication in medication_dict[category_id]: - if medication.lower() in medication_display.lower(): - medication_category = category_id - break - return medication_category - - -def medication_required(request_body): - """ - Determine if there is the veteran requires continuous medication for hypertension - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - response = {} - relevant_medications = [] - other_medications = [] - - veterans_medication = request_body["evidence"]["medications"] - for medication in veterans_medication: - if medication["status"].lower() in ["active", "on-hold", "completed", "stopped", "unknown"]: - medication["conditionRelated"] = False - medication_display = medication["description"] - category = categorize_med(medication_display) - if category: - medication["suggestedCategory"] = category - medication["conditionRelated"] = True - relevant_medications.append(medication) - else: - other_medications.append(medication) - - relevant_medications = sorted( - relevant_medications, - key=lambda i: datetime.strptime(i["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date(), - reverse=True, - ) - - other_medications = sorted( - other_medications, - key=lambda i: datetime.strptime(i["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date(), - reverse=True, - ) - - response["relevantMedCount"] = len(relevant_medications) - relevant_medications.extend(other_medications) - response["totalMedCount"] = len(relevant_medications) - response["medications"] = relevant_medications - - return response diff --git a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/procedure.py b/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/procedure.py deleted file mode 100644 index 571f049d03..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/procedure.py +++ /dev/null @@ -1,37 +0,0 @@ -from datetime import datetime - -from .codesets import rhinitis_procedures - - -def procedures_calculation(request_body): - """ - Determine if there is the veteran requires continuous medication for hypertension - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - response = {} - relevant_procedures = [] - - veterans_procedures = request_body["evidence"]["procedures"] - procedures_count = len(veterans_procedures) - for procedure in veterans_procedures: - if procedure["status"].lower() in ["in-progress", "on-hold", "stopped", "completed"]: - procedure_code = procedure["code"] - if procedure_code in rhinitis_procedures.procedures: - relevant_procedures.append(procedure) - - relevant_procedures = sorted( - relevant_procedures, - key=lambda i: datetime.strptime(i["performedDate"], "%Y-%m-%d").date(), - reverse=True, - ) - - response.update({ - "procedures": relevant_procedures, - "relevantProceduresCount": len(relevant_procedures), - "totalProceduresCount": procedures_count, - }) - - return response diff --git a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/queues.py b/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/queues.py deleted file mode 100644 index 63123edb27..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/queues.py +++ /dev/null @@ -1,45 +0,0 @@ -import json -import logging - -import pika - -from . import main -from .settings import queue_config - -EXCHANGE = queue_config["exchange_name"] -SERVICE_QUEUE = queue_config["service_queue_name"] - - -def on_request_callback(channel, method, properties, body): - binding_key = method.routing_key - message = json.loads(body.decode("utf-8")) - logging.info(f"claimSubmissionId: {message['claimSubmissionId']}, health data received by {binding_key} processor") - try: - response = main.assess_rhinitis(message) - except Exception as e: - logging.error(e, exc_info=True) - response = {"evidence": None, "evidenceSummary": None, "errorMessage": str(e), "claimSubmissionId": message['claimSubmissionId']} - - channel.basic_publish( - exchange=EXCHANGE, - routing_key=properties.reply_to, - properties=pika.BasicProperties(correlation_id=properties.correlation_id), - body=json.dumps(response), - ) - logging.info(f"claimSubmissionId: {response['claimSubmissionId']}, evaluation sent by {binding_key} processor") - - -def queue_setup(channel): - channel.exchange_declare( - exchange=EXCHANGE, exchange_type="direct", durable=True, auto_delete=True - ) - channel.queue_declare(queue=SERVICE_QUEUE, durable=True, auto_delete=True) - channel.queue_bind(queue=SERVICE_QUEUE, exchange=EXCHANGE) - - channel.basic_qos(prefetch_count=250) - channel.basic_consume( - queue=SERVICE_QUEUE, on_message_callback=on_request_callback, auto_ack=True - ) - logging.info( - f" [*] Waiting for data for queue: {SERVICE_QUEUE}. To exit press CTRL+C" - ) diff --git a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/settings.py b/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/settings.py deleted file mode 100644 index 66316091c5..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6522/src/lib/settings.py +++ /dev/null @@ -1,4 +0,0 @@ -queue_config = { - "exchange_name": "health-assess-exchange", - "service_queue_name": "health-sufficiency-assess.rhinitis", -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6522/src/requirements.txt.bak b/domain-rrd/service-python/svc-assessclaimdc6522/src/requirements.txt.bak deleted file mode 100644 index 1df81b0f1e..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6522/src/requirements.txt.bak +++ /dev/null @@ -1,3 +0,0 @@ -cerberus==1.3.4; -pika==1.3.1 -python-dateutil==2.8.2; diff --git a/domain-rrd/service-python/svc-assessclaimdc6602/build.gradle.bak b/domain-rrd/service-python/svc-assessclaimdc6602/build.gradle.bak deleted file mode 100644 index 8e44cd91bd..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602/build.gradle.bak +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id 'local.python.container-service-conventions' -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/main.py b/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/main.py deleted file mode 100644 index eab930148f..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/main.py +++ /dev/null @@ -1,42 +0,0 @@ -import logging -from typing import Dict - -import data_model - -from . import medication - - -def assess_asthma(event: Dict): - """ - Take a request that includes asthma related data, and return a filtered response - - :param event: request body - :type event: dict - :return: response body - :rtype: dict - """ - validation_results = data_model.validate_request_body(event) - response_body = {} - - if validation_results["is_valid"]: - active_medications = medication.medication_required(event) - - response_body.update( - { - "evidence": { - "medications": active_medications["medications"], - }, - "evidenceSummary": { - "relevantMedCount": active_medications["relevantMedCount"], - "totalMedCount": active_medications["totalMedCount"], - }, - "claimSubmissionId": event['claimSubmissionId'] - } - ) - logging.info(f"claimSubmissionId: {event['claimSubmissionId']}, message processed successfully") - else: - logging.info(f"claimSubmissionId: {event['claimSubmissionId']}, message failed to process due to: {validation_results['errors']}") - response_body["errorMessage"] = "error validating request message data" - response_body["claimSubmissionId"] = event['claimSubmissionId'] - - return response_body diff --git a/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/medication.py b/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/medication.py deleted file mode 100644 index 358ea09f5a..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/medication.py +++ /dev/null @@ -1,75 +0,0 @@ -from datetime import datetime - -asthma_medications = { - "Aerochamber", - "Albuterol", - "Beclomethasone", - "Benralizumab", - "Budesonide", - "Ciclesonide", - "Fluticasone", - "Levalbuterol", - "Mepolizumab", - "Methylprednisolone", - "Mometasone", - "Montelukast", - "Omalizumab", - "Prednisone", - "Reslizumab", - "Salmeterol", - "Theophylline", - "Zafirlukast", - "Zileuton", - "Asthma", - "Breath", - "Inhal", - "Puff", - "SOB", -} - - -def medication_required(request_body): - """ - Determine if there is the veteran requires continuous medication for hypertension - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - response = {} - relevant_medications = [] - other_medications = [] - - veterans_medication = request_body["evidence"]["medications"] - for medication in veterans_medication: - if medication["status"].lower() == "active": - flagged = False - medication_display = medication["description"] - for keyword in [x.lower() for x in asthma_medications]: - if keyword in medication_display.lower(): - medication["asthmaRelevant"] = "true" - relevant_medications.append(medication) - flagged = True - break - if not flagged: - medication["asthmaRelevant"] = "false" - other_medications.append(medication) - - relevant_medications = sorted( - relevant_medications, - key=lambda i: datetime.strptime(i["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date(), - reverse=True, - ) - - other_medications = sorted( - other_medications, - key=lambda i: datetime.strptime(i["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date(), - reverse=True, - ) - - response["relevantMedCount"] = len(relevant_medications) - relevant_medications.extend(other_medications) - response["totalMedCount"] = len(relevant_medications) - response["medications"] = relevant_medications - - return response diff --git a/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/queues.py b/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/queues.py deleted file mode 100644 index 4d0a559a9d..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/queues.py +++ /dev/null @@ -1,45 +0,0 @@ -import json -import logging - -import pika - -from . import main -from .settings import queue_config - -EXCHANGE = queue_config["exchange_name"] -SERVICE_QUEUE = queue_config["service_queue_name"] - - -def on_request_callback(channel, method, properties, body): - binding_key = method.routing_key - message = json.loads(body.decode("utf-8")) - logging.info(f"claimSubmissionId: {message['claimSubmissionId']}, health data received by {binding_key} processor") - try: - response = main.assess_asthma(message) - except Exception as e: - logging.error(e, exc_info=True) - response = {"evidence": None, "evidenceSummary": None, "errorMessage": str(e), "claimSubmissionId": message['claimSubmissionId']} - - channel.basic_publish( - exchange=EXCHANGE, - routing_key=properties.reply_to, - properties=pika.BasicProperties(correlation_id=properties.correlation_id), - body=json.dumps(response), - ) - logging.info(f"claimSubmissionId: {response['claimSubmissionId']}, evaluation sent by {binding_key} processor") - - -def queue_setup(channel): - channel.exchange_declare( - exchange=EXCHANGE, exchange_type="direct", durable=True, auto_delete=True - ) - channel.queue_declare(queue=SERVICE_QUEUE, durable=True, auto_delete=True) - channel.queue_bind(queue=SERVICE_QUEUE, exchange=EXCHANGE) - - channel.basic_qos(prefetch_count=250) - channel.basic_consume( - queue=SERVICE_QUEUE, on_message_callback=on_request_callback, auto_ack=True - ) - logging.info( - f" [*] Waiting for data for queue: {SERVICE_QUEUE}. To exit press CTRL+C" - ) diff --git a/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/settings.py b/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/settings.py deleted file mode 100644 index 7677f73227..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602/src/lib/settings.py +++ /dev/null @@ -1,4 +0,0 @@ -queue_config = { - "exchange_name": "health-assess-exchange", - "service_queue_name": "health-assess.asthma", -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6602/src/requirements.txt.bak b/domain-rrd/service-python/svc-assessclaimdc6602/src/requirements.txt.bak deleted file mode 100644 index 1df81b0f1e..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602/src/requirements.txt.bak +++ /dev/null @@ -1,3 +0,0 @@ -cerberus==1.3.4; -pika==1.3.1 -python-dateutil==2.8.2; diff --git a/domain-rrd/service-python/svc-assessclaimdc6602v2/build.gradle.bak b/domain-rrd/service-python/svc-assessclaimdc6602v2/build.gradle.bak deleted file mode 100644 index 8e44cd91bd..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602v2/build.gradle.bak +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id 'local.python.container-service-conventions' -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/codesets/condition_codesets.py b/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/codesets/condition_codesets.py deleted file mode 100644 index c49197decd..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/codesets/condition_codesets.py +++ /dev/null @@ -1,31 +0,0 @@ -asthma_conditions = { - "J44.1", - "J44.9", - "J45.2", - "J45.20", - "J45.21", - "J45.22", - "J45.901", - "J45.902", - "J45.909", - "J45.990", - "J45.991", - "J45.998", -} - -persistent_asthma = { - "J82.83", - "J45.3", - "J45.30", - "J45.31", - "J45.32", - "J45.4", - "J45.40", - "J45.41", - "J45.42", - "J45.5", - "J45.50", - "J45.51", - "J45.52", - "J82.83", -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/codesets/medication_codesets.py b/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/codesets/medication_codesets.py deleted file mode 100644 index 5db4ef0da3..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/codesets/medication_codesets.py +++ /dev/null @@ -1,98 +0,0 @@ -med_dict = { - "Anti-Inflammatory/Bronchodilator/Corticosteroid/Immuno-Suppressive": { - "advair", - "airduo", - "wixela", - "flovent", - "qvar redihaler", - "symbicort", - "trelegy ellipta", - "fluticasone", - "mometasone", - "propel", - "ryaltris", - "flonase sensimist", - }, - "Anti-Inflammatory/Corticosteroid/Immuno-Suppressive": { - "medrol", - "millipred", - "rayos", - "orapred", - "pediapred", - "veripred", - "aerospan", - "alvesco", - "asmanex", - "breo ellipta", - "dulera", - "arnuity", - "pulmicort", - "methylprednisolone", - "prednisone", - "prednisolone", - "flunisolide", - "budesonide", - "beclomethasone", - "qnasl", - "beconase", - }, - "Anti-Inflammatory/Immuno-Suppressive": { - "cinqair", - }, - "Anti-Inflammatory/Bronchodilator": { - "serevent diskus", - "singulair", - "salmeterol", - "vilanterol", - "formoterol", - "breyna", - "perforomist", - "montelukast", - "tiotropium", - "vilanterol", - "zileuton", - "formoterol fumarate", - "tiotropium bromide" - }, - "Bronchodilator/Used in Respiratory Failure": { - "adrenalin", - "metaproterenol", - "epinephrine", - "primatene", - "albuterol", - "levalbuterol", - }, - "Corticosteroid/Immuno-Suppressive": { - "deltasone", - "armonair", - "ciclesonide", - "omnaris", - "zetonna", - }, - "Bronchodilator": { - "epipen", - "auvi-q", - "symjepi", - "ventolin hfa", - "proventil hfa", - "proair", - "accuneb", - "xopenex", - "spiriva respimat", - "umeclidinium", - }, - "Anti-Inflammatory": { - "accolate", - "dupixent", - "fasenra", - "nucala", - "xolair", - "zyflo", - "zafirlukast", - "reslizumab", - "dupilumab", - "benralizumab", - "mepolizumab", - "omalizumab", - }, -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/condition.py b/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/condition.py deleted file mode 100644 index fbc479ea5a..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/condition.py +++ /dev/null @@ -1,69 +0,0 @@ -from datetime import datetime - -from dateutil.relativedelta import relativedelta -from utils import extract_date, format_date - -from .codesets import condition_codesets - - -def sort_conditions(conditions): - """ - Sort medications by 'recordedDate' date. - :param conditions: List of conditions - :return: Sorted list - """ - - conditions = sorted( - conditions, - key=lambda i: datetime.strptime(i["recordedDate"], "%Y-%m-%d").date(), - reverse=True, - ) - - return conditions - - -def conditions_calculation(request_body): - """ - Determine if there is the veteran has a hypertension diagnosis - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - response = {} - condition_with_date = [] - condition_without_date = [] - conditions_two_years = [] - lh_relevant_condition_count = 0 - - veterans_conditions = request_body["evidence"]["conditions"] - date_of_claim_date = extract_date(request_body["claimSubmissionDateTime"]) - - for condition in veterans_conditions: - condition_code = condition["code"] - # Only LH data has ICD codes, so no MAS data will pass the following condition - if condition_code in condition_codesets.asthma_conditions or \ - condition_code in condition_codesets.persistent_asthma: - condition["relevant"] = True - lh_relevant_condition_count += 1 - else: - condition["relevant"] = False - - try: - condition_date = datetime.strptime(condition["recordedDate"], "%Y-%m-%d").date() - condition["dateFormatted"] = format_date(condition_date) - condition_with_date.append(condition) - if condition_date >= date_of_claim_date - relativedelta(years=2): - conditions_two_years.append(condition) - except (ValueError, KeyError): - condition["dateFormatted"] = "" - condition_without_date.append(condition) - - response.update({ - "conditions": sort_conditions(condition_with_date) + condition_without_date, - "twoYearsConditions": sort_conditions(conditions_two_years), - "totalConditionsCount": len(veterans_conditions), - "relevantConditionsLighthouseCount": lh_relevant_condition_count, - } - ) - return response diff --git a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/main.py b/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/main.py deleted file mode 100644 index 8e32b3963f..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/main.py +++ /dev/null @@ -1,51 +0,0 @@ -import logging -from typing import Dict - -import data_model -import utils - -from . import condition, medication - - -def assess_sufficiency_asthma(event: Dict): - """ - Take a request that includes asthma related data, and return a suffficiency decision - :param event: request body - :type event: dict - :return: response body - :rtype: dict - """ - validation_results = data_model.validate_request_body(event) - response_body = {} - - if validation_results["is_valid"]: - medications = medication.filter_categorize_mas_medication(event) - conditions = condition.conditions_calculation(event) - - response_body.update( - { - "evidence": { - "medications": medications["medications"], - "conditions": conditions["conditions"], - "procedures": event["evidence"]["procedures"], - "documentsWithoutAnnotationsChecked": utils.docs_without_annotations_ids(event) - }, - "evidenceSummary": { - "totalMedCount": medications["allMedicationsCount"], - "schedularMedicationOneYearCount": medications["schedularMedicationOneYearCount"], - "proceduresCount": len(event["evidence"]["procedures"]), - "totalConditionsCount": conditions["totalConditionsCount"], - "relevantConditionsLighthouseCount": conditions["relevantConditionsLighthouseCount"] - }, - "claimSubmissionDateTime": event["claimSubmissionDateTime"], - "disabilityActionType": event["disabilityActionType"], - "claimSubmissionId": event['claimSubmissionId'] - } - ) - logging.info(f"claimSubmissionId: {event['claimSubmissionId']}, message processed successfully") - else: - logging.info(f"claimSubmissionId: {event['claimSubmissionId']}, message failed to process due to: {validation_results['errors']}") - response_body["errorMessage"] = "error validating request message data" - response_body["claimSubmissionId"] = event['claimSubmissionId'] - - return response_body diff --git a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/medication.py b/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/medication.py deleted file mode 100644 index b655fbdeab..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/medication.py +++ /dev/null @@ -1,86 +0,0 @@ -from datetime import datetime - -from dateutil.relativedelta import relativedelta -from utils import extract_date, format_date - -from .codesets import medication_codesets - - -def sort_med(med_list): - - med_list = sorted( - med_list, - key=lambda i: datetime.strptime(i["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date(), - reverse=True, - ) - return med_list - - -def classify_med(medication_display): - """ - Return the class that a medication belongs to. If it does not belong to any, return an empty list. - :param medication_display: medication text - :return: list - """ - medication_dict = medication_codesets.med_dict - medication_category = str() - for category_id in list(medication_dict.keys()): - if medication_category: - break - for medication in medication_dict[category_id]: - if medication in medication_display.lower(): - medication_category = category_id - break - return medication_category - - -def categorize_med(medication_display): - """ - Return the category that a medication belongs to. If it does not belong to any, return an empty list. - - :param medication_display: medication text - :return: list - """ - medication_dict = medication_codesets.med_dict - medication_category = str() - for category_id in list(medication_dict.keys()): - if medication_category: - break - for medication in medication_dict[category_id]: - if medication in medication_display.lower(): - medication_category = category_id - break - return medication_category - - -def filter_categorize_mas_medication(request_body): - """Filter MAS medication data""" - medication_with_date = [] - medication_without_date = [] - medication_one_year = [] - schedular_med_one_year = 0 - date_of_claim_date = extract_date(request_body["claimSubmissionDateTime"]) - - for medication in request_body["evidence"]["medications"]: - drug_class = classify_med(medication["description"]) - medication["classification"] = drug_class - try: - date = datetime.strptime(medication["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date() - medication["dateFormatted"] = format_date(date) - medication_with_date.append(medication) - if date >= date_of_claim_date - relativedelta(years=1): - medication_one_year.append(medication) - if drug_class: - schedular_med_one_year += 1 - except (ValueError, KeyError): - medication["dateFormatted"] = '' - medication_without_date.append(medication) - - response = {"oneYearMedication": sort_med(medication_one_year), - "medications": sort_med(medication_with_date) + medication_without_date, - "allMedicationsCount": len(request_body["evidence"]["medications"]), - "schedularMedicationOneYearCount": schedular_med_one_year, - "oneYearMedicationsCount": len(medication_one_year) - } - - return response diff --git a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/queues.py b/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/queues.py deleted file mode 100644 index 4d0a559a9d..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/queues.py +++ /dev/null @@ -1,45 +0,0 @@ -import json -import logging - -import pika - -from . import main -from .settings import queue_config - -EXCHANGE = queue_config["exchange_name"] -SERVICE_QUEUE = queue_config["service_queue_name"] - - -def on_request_callback(channel, method, properties, body): - binding_key = method.routing_key - message = json.loads(body.decode("utf-8")) - logging.info(f"claimSubmissionId: {message['claimSubmissionId']}, health data received by {binding_key} processor") - try: - response = main.assess_asthma(message) - except Exception as e: - logging.error(e, exc_info=True) - response = {"evidence": None, "evidenceSummary": None, "errorMessage": str(e), "claimSubmissionId": message['claimSubmissionId']} - - channel.basic_publish( - exchange=EXCHANGE, - routing_key=properties.reply_to, - properties=pika.BasicProperties(correlation_id=properties.correlation_id), - body=json.dumps(response), - ) - logging.info(f"claimSubmissionId: {response['claimSubmissionId']}, evaluation sent by {binding_key} processor") - - -def queue_setup(channel): - channel.exchange_declare( - exchange=EXCHANGE, exchange_type="direct", durable=True, auto_delete=True - ) - channel.queue_declare(queue=SERVICE_QUEUE, durable=True, auto_delete=True) - channel.queue_bind(queue=SERVICE_QUEUE, exchange=EXCHANGE) - - channel.basic_qos(prefetch_count=250) - channel.basic_consume( - queue=SERVICE_QUEUE, on_message_callback=on_request_callback, auto_ack=True - ) - logging.info( - f" [*] Waiting for data for queue: {SERVICE_QUEUE}. To exit press CTRL+C" - ) diff --git a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/settings.py b/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/settings.py deleted file mode 100644 index b837c7e02d..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/lib/settings.py +++ /dev/null @@ -1,4 +0,0 @@ -queue_config = { - "exchange_name": "health-assess-exchange", - "service_queue_name": "health-sufficiency-assess.asthma", -} diff --git a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/requirements.txt.bak b/domain-rrd/service-python/svc-assessclaimdc6602v2/src/requirements.txt.bak deleted file mode 100644 index 51341e0fb9..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc6602v2/src/requirements.txt.bak +++ /dev/null @@ -1,3 +0,0 @@ -cerberus==1.3.4; -pika==1.3.0 -python-dateutil==2.8.2; diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/README.md b/domain-rrd/service-python/svc-assessclaimdc7101/README.md deleted file mode 100644 index 02f8da5836..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc7101/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Claims Processor for Diagnostic Code 7101 (Hypertensive vascular disease) - -## Tools -[Cerberus](https://docs.python-cerberus.org/en/stable/index.html)\ -[RabbitMQ](https://www.rabbitmq.com/) - - -## RabbitMQ configuration -The application connects to RabbitMQ with the binding key `7101`. Claims are sent to the `health-assess-exchange` and -are routed by VASRD code. - -### Event object validation -Incoming messages are validated by Cerberus to avoid container shutdown from unexpected exceptions. - -## VRO version 1.0 -Filters and sorts health data from Lighthouse before sending it to the PDF generator. - -## VRO version 2.0 - -Accepts aggregated Lighthouse and MAS medical data and returns both medical evidence for the PDF generator and a decision -on claim evidence sufficiency. - -### Hypertension - -The `assessclaimdc7101` folder contains all logic for hypertension. This service builds two queues, `health-assess.7101` -and `health-sufficiency-assess.7101`, the first of which is used in version 1.0 and the second is used in version 2.0. diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/__init__.py b/domain-rrd/service-python/svc-assessclaimdc7101/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/build.gradle.bak b/domain-rrd/service-python/svc-assessclaimdc7101/build.gradle.bak deleted file mode 100644 index 8e44cd91bd..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc7101/build.gradle.bak +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id 'local.python.container-service-conventions' -} diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/src/__init__.py b/domain-rrd/service-python/svc-assessclaimdc7101/src/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/bp_calculator.py b/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/bp_calculator.py deleted file mode 100644 index ff7e57bd0e..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/bp_calculator.py +++ /dev/null @@ -1,97 +0,0 @@ -from datetime import datetime - -from dateutil.relativedelta import relativedelta -from utils import extract_date, format_date - - -def sort_bp(bp_readings): - """ - Sort bp readings by date. - - :param bp_readings: List of bp readings - :return: Sorted list - """ - - bp_readings = sorted( - bp_readings, - key=lambda i: datetime.strptime(i["date"], "%Y-%m-%d").date(), - reverse=True, - ) - return bp_readings - - -def deduplicate(bp_readings): - """ - Return bp readings with any lighthouse duplicates removed. A duplicate is identified by having the same diastolic - value, systolic value and date. HDR data has organization set to VAMC Other Output Reports. - :param bp_readings: full list of BP readings - :return: deduplicated list - """ - deduplicated_readings = [] - for reading in bp_readings: - duplicate = False - if reading["dataSource"] == "LH": - for bp_comp in bp_readings: - if reading["diastolic"]["value"] == bp_comp["diastolic"]["value"] \ - and reading["systolic"]["value"] == bp_comp["systolic"]["value"] \ - and reading["date"] == bp_comp["date"] \ - and bp_comp["organization"] == "VAMC Other Output Reports": - duplicate = True - break - if not duplicate: - deduplicated_readings.append(reading) - return deduplicated_readings - - -def bp_reader(request_body): - """ - Iterate through all the BP readings received by data sources and determine their recency relative to the date - of claim. Flag high BP readings. - - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - - bp_reading_in_past_year = [] - bp_readings_in_past_two_years = [] - elevated_bp_in_past_two_years = [] - sortable_bp = [] - not_sortable_bp = [] - partial_bp_two_years = [] - date_of_claim_date = extract_date(request_body["claimSubmissionDateTime"]) - bp_readings = request_body["evidence"]["bp_readings"] - - for reading in bp_readings: - try: - bp_reading_date = datetime.strptime(reading["date"], "%Y-%m-%d").date() - reading["dateFormatted"] = format_date(bp_reading_date) - sortable_bp.append(reading) - except ValueError: - reading["dateFormatted"] = '' - not_sortable_bp.append(reading) - continue # If there is no date associated - - if reading["systolic"]["value"] == 0 or reading["diastolic"]["value"] == 0: - if bp_reading_date >= date_of_claim_date - relativedelta(years=2): - partial_bp_two_years.append(reading) # to be displayed in PDF - continue - - if bp_reading_date >= date_of_claim_date - relativedelta(years=1): - bp_reading_in_past_year.append(reading) - if bp_reading_date >= date_of_claim_date - relativedelta(years=2): - bp_readings_in_past_two_years.append(reading) - if reading["systolic"]["value"] >= 160 and reading["diastolic"]["value"] >= 100: - elevated_bp_in_past_two_years.append(reading) - - result = {"twoYearsBp": sort_bp(bp_readings_in_past_two_years + partial_bp_two_years), - "oneYearBp": sort_bp(bp_reading_in_past_year), - "allBp": sort_bp(sortable_bp) + not_sortable_bp, - "twoYearsBpCount": len(bp_readings_in_past_two_years), - "oneYearBpCount": len(bp_reading_in_past_year), - "twoYearsElevatedBpCount": len(elevated_bp_in_past_two_years), - "totalBpCount": len(bp_readings) - } - - return result diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/codesets/__init__.py b/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/codesets/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/codesets/hypertension_conditions.py b/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/codesets/hypertension_conditions.py deleted file mode 100644 index 154add8de6..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/codesets/hypertension_conditions.py +++ /dev/null @@ -1,7 +0,0 @@ -conditions = [ - "I10", - "I10.", - "401.0", - "401.1", - "401.9" -] diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/conditions.py b/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/conditions.py deleted file mode 100644 index 36cad28a47..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/conditions.py +++ /dev/null @@ -1,69 +0,0 @@ -from datetime import datetime - -from dateutil.relativedelta import relativedelta -from utils import extract_date, format_date - -from .codesets import hypertension_conditions - - -def sort_conditions(conditions): - """ - Sort medications by 'recordedDate' date. - - :param conditions: List of conditions - :return: Sorted list - """ - - conditions = sorted( - conditions, - key=lambda i: datetime.strptime(i["recordedDate"], "%Y-%m-%d").date(), - reverse=True, - ) - - return conditions - - -def conditions_calculation(request_body): - """ - Determine if there is the veteran has a hypertension diagnosis - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - response = {} - condition_with_date = [] - condition_without_date = [] - conditions_two_years = [] - lh_relevant_condition_count = 0 - - veterans_conditions = request_body["evidence"]["conditions"] - date_of_claim_date = extract_date(request_body["claimSubmissionDateTime"]) - - for condition in veterans_conditions: - condition_code = condition["code"] - # Only LH data has ICD codes, so no MAS data will pass the following condition - if condition_code in hypertension_conditions.conditions: - condition["relevant"] = True - lh_relevant_condition_count += 1 - else: - condition["relevant"] = False - - try: - condition_date = datetime.strptime(condition["recordedDate"], "%Y-%m-%d").date() - condition["dateFormatted"] = format_date(condition_date) - condition_with_date.append(condition) - if condition_date >= date_of_claim_date - relativedelta(years=2): - conditions_two_years.append(condition) - except (ValueError, KeyError): - condition["dateFormatted"] = "" - condition_without_date.append(condition) - - response.update({ - "conditions": sort_conditions(condition_with_date) + condition_without_date, - "twoYearsConditions": sort_conditions(conditions_two_years), - "totalConditionsCount": len(veterans_conditions), - "relevantConditionsLighthouseCount": lh_relevant_condition_count, - } - ) - return response diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/main.py b/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/main.py deleted file mode 100644 index f008afc4dc..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/main.py +++ /dev/null @@ -1,132 +0,0 @@ -import logging -from datetime import date -from typing import Dict - -import data_model -import utils - -from . import bp_calculator, conditions, medications - - -def assess_hypertension(event: Dict): - """ - Take a request that includes hypertension related data, and return a response - - :param event: request body - :type event: dict - :return: response body - :rtype: dict - """ - - validation_results = data_model.validate_request_body(event) - response_body = {} - - if "claimSubmissionDateTime" not in event: - event["claimSubmissionDateTime"] = str(f"{date.today()}T00:00:00Z") - - if validation_results["is_valid"]: - relevant_medication = medications.medication_required( - event - ) - bp_readings = bp_calculator.bp_reader(event) - response_body.update( - { - "evidence": { - "medications": relevant_medication["medications"], - "bp_readings": bp_readings["oneYearBp"], - }, - "evidenceSummary": { - "totalBpCount": bp_readings["totalBpCount"], - "recentBpCount": bp_readings["oneYearBpCount"], - "medicationsCount": relevant_medication["medicationsCount"], - }, - "claimSubmissionId": event['claimSubmissionId'] - } - ) - logging.info(f"claimSubmissionId: {event['claimSubmissionId']}, message processed successfully") - else: - logging.info( - f"claimSubmissionId: {event['claimSubmissionId']}, message failed to process due to: {validation_results['errors']}") - response_body["errorMessage"] = "error validating request message data" - response_body["claimSubmissionId"] = event['claimSubmissionId'] - - return response_body - - -def assess_sufficiency(event: Dict): - """ - Take a request that includes hypertension related data, and return a response - - :param event: request body - :type event: dict - :return: response body - :rtype: dict - """ - validation_results = data_model.validate_request_body(event) - event = validation_results["request_body"] - response_body = {} - - if "claimSubmissionDateTime" not in event: - event["claimSubmissionDateTime"] = str(f"{date.today()}T04:00:00Z") - - if validation_results["is_valid"] and "disabilityActionType" in event: - all_bp_length = len(event["evidence"]["bp_readings"]) - event["evidence"]["bp_readings"] = bp_calculator.deduplicate(event["evidence"]["bp_readings"]) - bp_calculation = bp_calculator.bp_reader(event) - relevant_conditions = conditions.conditions_calculation(event) - relevant_medications = medications.filter_mas_medication(event) - bp_display = bp_calculation["twoYearsBp"] - conditions_display = relevant_conditions["twoYearsConditions"] - medication_display = relevant_medications["twoYearsMedications"] - - sufficient = None - if event["disabilityActionType"] == "INCREASE": - if bp_calculation["oneYearBpCount"] >= 3: - sufficient = True - else: - sufficient = False - if event["disabilityActionType"] == "NEW": - bp_display = bp_calculation["allBp"] # Include all bp readings to display - conditions_display = relevant_conditions["conditions"] - medication_display = relevant_medications["allMedications"] - if relevant_conditions["relevantConditionsLighthouseCount"] >= 1: - if bp_calculation["twoYearsBpCount"] >= 3: - sufficient = True - else: - sufficient = False - if bp_calculation["twoYearsElevatedBpCount"] >= 1 and bp_calculation["twoYearsBpCount"] >= 3: - sufficient = True - - response_body.update( - { - "evidence": { - "bp_readings": bp_display, - "conditions": conditions_display, - "medications": medication_display, - "documentsWithoutAnnotationsChecked": utils.docs_without_annotations_ids(event) - }, - "evidenceSummary": { - "totalBpCount": bp_calculation["totalBpCount"], - "twoYearsBpCount": bp_calculation["twoYearsBpCount"], - "oneYearBpCount": bp_calculation["oneYearBpCount"], - "twoYearsElevatedBpCount": bp_calculation["twoYearsElevatedBpCount"], - "relevantConditionsLighthouseCount": relevant_conditions["relevantConditionsLighthouseCount"], - "totalConditionsCount": relevant_conditions["totalConditionsCount"], - "allMedicationsCount": relevant_medications["allMedicationsCount"], - "twoYearsMedicationsCount": relevant_medications["twoYearsMedicationsCount"], - "lighthouseDuplicateBpCount": all_bp_length - bp_calculation["totalBpCount"] - }, - "sufficientForFastTracking": sufficient, - "claimSubmissionDateTime": event["claimSubmissionDateTime"], - "disabilityActionType": event["disabilityActionType"], - "claimSubmissionId": event['claimSubmissionId'] - }) - logging.info(f"claimSubmissionId: {event['claimSubmissionId']}, sufficientForFastTracking: {sufficient}, " - f"evidenceSummary: {response_body['evidenceSummary']}") - else: - logging.info( - f"claimSubmissionId: {event['claimSubmissionId']}, message failed to process due to: {validation_results['errors']}") - response_body["errorMessage"] = "error validating request message data" - response_body["claimSubmissionId"] = event['claimSubmissionId'] - - return response_body diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/medications.py b/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/medications.py deleted file mode 100644 index af26decb48..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/medications.py +++ /dev/null @@ -1,70 +0,0 @@ -from datetime import datetime - -from dateutil.relativedelta import relativedelta -from utils import extract_date, format_date - - -def sort_med(medication_list): - """ - Sort medications by 'authoredOn' date. - - :param medication_list: List of medication - :return: Sorted list - """ - - medication_list = sorted( - medication_list, - key=lambda i: datetime.strptime(i["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date(), - reverse=True, - ) - - return medication_list - - -def medication_required(request_body): - """ - Determine if there is the veteran requires medication for hypertension - :param request_body: request body - :type request_body: dict - :return: response body indicating success or failure with additional attributes - :rtype: dict - """ - response = {} - relevant_medications = [] - - veterans_medication = request_body["evidence"]["medications"] - for medication in veterans_medication: - if medication["status"].lower() == "active": - relevant_medications.append(medication) - - response["medications"] = sort_med(relevant_medications) - response["medicationsCount"] = len(relevant_medications) - return response - - -def filter_mas_medication(request_body): - """Filter MAS medication data""" - medication_with_date = [] - medication_without_date = [] - medication_two_years = [] - date_of_claim_date = extract_date(request_body["claimSubmissionDateTime"]) - - for medication in request_body["evidence"]["medications"]: - if medication["dataSource"] == "MAS": - try: - date = datetime.strptime(medication["authoredOn"], "%Y-%m-%dT%H:%M:%SZ").date() - medication["dateFormatted"] = format_date(date) - medication_with_date.append(medication) - if date >= date_of_claim_date - relativedelta(years=2): - medication_two_years.append(medication) - except (ValueError, KeyError): - medication["dateFormatted"] = '' - medication_without_date.append(medication) - - response = {"twoYearsMedications": sort_med(medication_two_years), - "allMedications": sort_med(medication_with_date) + medication_without_date, - "allMedicationsCount": len(request_body["evidence"]["medications"]), - "twoYearsMedicationsCount": len(medication_two_years) - } - - return response diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/queues.py b/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/queues.py deleted file mode 100644 index a094739f60..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/queues.py +++ /dev/null @@ -1,83 +0,0 @@ -import json -import logging - -import pika - -from . import main -from .settings import queue_config - -EXCHANGE = queue_config["exchange_name"] -SERVICE_QUEUE = queue_config["service_queue_name"] -SUFFICIENT_QUEUE = queue_config["sufficient_queue_name"] - - -def pdf_evidence_request_callback(channel, method, properties, body): - - binding_key = method.routing_key - message = json.loads(body.decode("utf-8")) - logging.info(f"claimSubmissionId: {message['claimSubmissionId']}, health data received by {binding_key} processor") - - try: - response = main.assess_hypertension(message) - except Exception as e: - logging.error(e, exc_info=True) - response = {"evidence": None, "evidenceSummary": None, "errorMessage": str(e), "claimSubmissionId": message['claimSubmissionId']} - - channel.basic_publish( - exchange=EXCHANGE, - routing_key=properties.reply_to, - properties=pika.BasicProperties(correlation_id=properties.correlation_id), - body=json.dumps(response), - ) - logging.info(f"claimSubmissionId: {response['claimSubmissionId']}, evaluation sent by {binding_key} processor") - - -def sufficiency_request_callback(channel, method, properties, body): - - binding_key = method.routing_key - message = json.loads(body.decode("utf-8")) - logging.info(f"claimSubmissionId: {message['claimSubmissionId']}, health data received by {binding_key} processor") - - try: - response = main.assess_sufficiency(message) - except Exception as e: - logging.error(e, exc_info=True) - response = {"evidence": None, "evidenceSummary": None, "errorMessage": str(e), "claimSubmissionId": message['claimSubmissionId']} - - channel.basic_publish( - exchange=EXCHANGE, - routing_key=properties.reply_to, - properties=pika.BasicProperties(correlation_id=properties.correlation_id), - body=json.dumps(response), - ) - logging.info(f"claimSubmissionId: {response['claimSubmissionId']}, evaluation sent by {binding_key} processor") - - -def queue_setup(channel): - - channel.exchange_declare( - exchange=EXCHANGE, exchange_type="direct", durable=True, auto_delete=True - ) - - # Sufficiency test queue - channel.queue_declare(queue=SUFFICIENT_QUEUE, durable=True, auto_delete=True) - channel.queue_bind(queue=SUFFICIENT_QUEUE, exchange=EXCHANGE) - channel.basic_qos(prefetch_count=250) - channel.basic_consume( - queue=SUFFICIENT_QUEUE, on_message_callback=sufficiency_request_callback, auto_ack=True - ) - - # PDF Service queue - channel.queue_declare(queue=SERVICE_QUEUE, durable=True, auto_delete=True) - channel.queue_bind(queue=SERVICE_QUEUE, exchange=EXCHANGE) - channel.basic_qos(prefetch_count=250) - channel.basic_consume( - queue=SERVICE_QUEUE, on_message_callback=pdf_evidence_request_callback, auto_ack=True - ) - - logging.info( - f" [*] Waiting for data for queue: {SERVICE_QUEUE}. To exit press CTRL+C" - ) - logging.info( - f" [*] Waiting for data for queue: {SUFFICIENT_QUEUE}. To exit press CTRL+C" - ) diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/settings.py b/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/settings.py deleted file mode 100644 index 568a2219a6..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc7101/src/lib/settings.py +++ /dev/null @@ -1,5 +0,0 @@ -queue_config = { - "exchange_name": "health-assess-exchange", - "service_queue_name": "health-assess.hypertension", - "sufficient_queue_name": "health-sufficiency-assess.hypertension" -} diff --git a/domain-rrd/service-python/svc-assessclaimdc7101/src/requirements.txt.bak b/domain-rrd/service-python/svc-assessclaimdc7101/src/requirements.txt.bak deleted file mode 100644 index 1df81b0f1e..0000000000 --- a/domain-rrd/service-python/svc-assessclaimdc7101/src/requirements.txt.bak +++ /dev/null @@ -1,3 +0,0 @@ -cerberus==1.3.4; -pika==1.3.1 -python-dateutil==2.8.2; diff --git a/domain-rrd/service-python/svc-featuretoggle/__init__.py b/domain-rrd/service-python/svc-featuretoggle/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-featuretoggle/build.gradle.bak b/domain-rrd/service-python/svc-featuretoggle/build.gradle.bak deleted file mode 100644 index 8e44cd91bd..0000000000 --- a/domain-rrd/service-python/svc-featuretoggle/build.gradle.bak +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id 'local.python.container-service-conventions' -} diff --git a/domain-rrd/service-python/svc-featuretoggle/src/__init__.py b/domain-rrd/service-python/svc-featuretoggle/src/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-featuretoggle/src/lib/__init__.py b/domain-rrd/service-python/svc-featuretoggle/src/lib/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-featuretoggle/src/lib/features.yml b/domain-rrd/service-python/svc-featuretoggle/src/lib/features.yml deleted file mode 100644 index 126201ece8..0000000000 --- a/domain-rrd/service-python/svc-featuretoggle/src/lib/features.yml +++ /dev/null @@ -1,13 +0,0 @@ -# Feature flags -# -# name: -# description: string describing what the flag is for -# enabled: boolean -# env?: list of enabled environments -features: - foo: - description: an example feature flag - enabled: true - bar: - description: another example feature flag - enabled: false diff --git a/domain-rrd/service-python/svc-featuretoggle/src/lib/main.py b/domain-rrd/service-python/svc-featuretoggle/src/lib/main.py deleted file mode 100644 index 87470e4186..0000000000 --- a/domain-rrd/service-python/svc-featuretoggle/src/lib/main.py +++ /dev/null @@ -1,20 +0,0 @@ -import logging - -from . import utils - - -def report_feature_toggles(): - """ - Take a request and return a response that includes feature toggle data - - :return: response body - :rtype: dict - """ - - response_body = { - "features": utils.create_features_list() - } - - logging.info("Message processed successfully") - - return response_body diff --git a/domain-rrd/service-python/svc-featuretoggle/src/lib/queues.py b/domain-rrd/service-python/svc-featuretoggle/src/lib/queues.py deleted file mode 100644 index bf156bfc17..0000000000 --- a/domain-rrd/service-python/svc-featuretoggle/src/lib/queues.py +++ /dev/null @@ -1,53 +0,0 @@ -import json -import logging -from datetime import datetime - -import pytz - -from . import main, utils -from .redis_client import RedisClient -from .settings import queue_config, redis_config - -EXCHANGE = queue_config["exchange_name"] -TOGGLE_QUEUE = queue_config["toggle_queue_name"] - - -def feature_toggle_request_callback(channel, method, properties, body): - - redis_client = RedisClient(redis_config) - binding_key = method.routing_key - logging.info(f" [x] {binding_key}: Received message.") - - try: - response = main.report_feature_toggles() - redis_client.publish("features", items=utils.create_features_list()) - redis_client.publish("features_timestamp", pytz.utc.localize(datetime.now())) - except Exception as e: - logging.error(e, exc_info=True) - response = {"status": "ERROR", "features": {}} - - channel.basic_publish( - exchange=EXCHANGE, - routing_key=properties.reply_to, - body=json.dumps(response), - ) - logging.info(f" [x] {binding_key}: Message sent.") - - -def queue_setup(channel): - - channel.exchange_declare( - exchange=EXCHANGE, exchange_type="direct", durable=True, auto_delete=True - ) - - # Feature toggle queue - channel.queue_declare(queue=TOGGLE_QUEUE, durable=True, auto_delete=True) - channel.queue_bind(queue=TOGGLE_QUEUE, exchange=EXCHANGE) - channel.basic_qos(prefetch_count=250) - channel.basic_consume( - queue=TOGGLE_QUEUE, on_message_callback=feature_toggle_request_callback, auto_ack=True - ) - - logging.info( - f" [*] Waiting for data for queue: {TOGGLE_QUEUE}. To exit press CTRL+C" - ) diff --git a/domain-rrd/service-python/svc-featuretoggle/src/lib/redis_client.py b/domain-rrd/service-python/svc-featuretoggle/src/lib/redis_client.py deleted file mode 100644 index 07df257466..0000000000 --- a/domain-rrd/service-python/svc-featuretoggle/src/lib/redis_client.py +++ /dev/null @@ -1,43 +0,0 @@ -import logging -from time import sleep - -import redis - -logging.basicConfig(level=logging.INFO) - - -class RedisClient: - - def __init__(self, config): - self.config = config - self.client = self._create_client() - - def _create_client(self): - for i in range(self.config["retry_limit"]): - try: - client = redis.Redis(host=self.config["host"], port=self.config["port"], password=self.config["password"]) - logging.warning(f"Redis Connected: {client}") - return client - except Exception: - logging.warning(f"Redis Connection Failed. Retrying in 15s ({i + 1}/{self.config['retry_limit']})") - sleep(15) - - def exists(self, key): - return self.client.exists(key) - - def save_data(self, key, value): - self.client.set(key, value) - self.client.expire(key, self.config["expiration"]) - - def get_data(self, key): - return self.client.get(key) - - def save_hash_data(self, name, key=None, value=None, mapping=None, items=None): - self.client.hset(name, key, value, mapping, items) - self.client.expire(name, self.config["expiration"]) - - def get_hash_data(self, name, key): - return self.client.hget(name, key) - - def publish(self, channel, message): - return self.client.publish(channel, message) diff --git a/domain-rrd/service-python/svc-featuretoggle/src/lib/settings.py b/domain-rrd/service-python/svc-featuretoggle/src/lib/settings.py deleted file mode 100644 index b2ed00e2fc..0000000000 --- a/domain-rrd/service-python/svc-featuretoggle/src/lib/settings.py +++ /dev/null @@ -1,15 +0,0 @@ -import os - -queue_config = { - "exchange_name": "feature-toggle-exchange", - "toggle_queue_name": "feature-toggle-queue" -} - -redis_config = { - "host": os.environ.get("REDIS_PLACEHOLDERS_HOST", "localhost"), - "port": 6379, - "password": os.environ.get("REDIS_PASSWORD", "not-redis-password"), - "retry_limit": 3, - # 3 hours - "expiration": 60 * 60 * 3 -} diff --git a/domain-rrd/service-python/svc-featuretoggle/src/lib/utils.py b/domain-rrd/service-python/svc-featuretoggle/src/lib/utils.py deleted file mode 100644 index 8d7f7574ea..0000000000 --- a/domain-rrd/service-python/svc-featuretoggle/src/lib/utils.py +++ /dev/null @@ -1,21 +0,0 @@ -import yaml - - -def create_features_list(): - """ - Parse a yaml file into a usable feature flags with boolean values - - :return: feature flag list - :rtype: list - """ - - stream = open('features.yml', 'r') - data = yaml.load(stream) - - features = [] - - for k, v in data['features'].items(): - temp = [k, data['features'][k]['enabled']] - features.append(temp) - - return features diff --git a/domain-rrd/service-python/svc-featuretoggle/src/requirements.txt.bak b/domain-rrd/service-python/svc-featuretoggle/src/requirements.txt.bak deleted file mode 100644 index 64790dabcc..0000000000 --- a/domain-rrd/service-python/svc-featuretoggle/src/requirements.txt.bak +++ /dev/null @@ -1,6 +0,0 @@ -cerberus==1.3.4 -pika==1.3.1 -python-dateutil==2.8.2 -pytz==2023.3 -pyyaml==6.0 -redis==4.5.4 diff --git a/domain-rrd/service-python/svc-pdfgenerator/README.md b/domain-rrd/service-python/svc-pdfgenerator/README.md deleted file mode 100644 index 3b46a1c13e..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/README.md +++ /dev/null @@ -1,122 +0,0 @@ -# PDF Generator - -## Tools - -- Python 3.9+ -- [wkhtmltopdf](https://wkhtmltopdf.org/) - - -## Endpoints and Request Data - -- [Request PDF Generation - POST http://localhost:8080/v1/evidence-pdf](http://localhost:8080/v1/evidence-pdf) -- [Fetch Generated PDF - GET http://localhost:8080/v1/evidence-pdf/{claimSubmissionID}](http://localhost:8080/v1/evidence-pdf) - -Both functions work off the same endpoint. The main difference being that the `POST` has a JSON request body while the `GET` uses the URL(`claimSubmissionID`) to find the corresponding PDF. - -- [Immediate PDF - GET http://localhost:8080/v1/immediate-pdf](http://localhost:8080/v1/immediate-pdf) - -This endpoint is a combined version of the `generate-pdf` and`fetch-pdf`. Pass it the `POST` request body and it will respond with the PDF associated with the `claimSubmissionID` - -## How it works - -### Queues - -On `service-python` startup, the consumer will attempt to create a `generate-pdf`, `fetch-pdf`, and `generate-fetch-pdf` queue on a `pdf-generator` exchange. - -#### Generating the PDF (1/2) -Any messages passed to the `generate-pdf` queue will use the `diagnosticCode`, `pdfTemplate` and `pdfLibrary`(optional) to select the appropriate template and generate the PDF. `diagnosticCode` is used to translate this into a human readable diagnostic type based on the mapping in `config/settings.py` in the `codes` variable. - -Using `pdfTemplate` like `v1` along with this diagnostic type like `hypertension` for example, it will pull up the appropriate template and template variables in the `templates` and `template_variables` folder respectively. For example, `"diagnosticCode"=7101` and `"pdfTemplate"="v1"`will fetch `templates/hypertension-v1.html` and `template_variables/hypertension-v1.json`. - -The generator will first load the `hypertension-v1.json` file which is prefilled with default values for the available variables within the template and attempt to replace them with what is provided in the message. If it cannot replace the data based on what's provided in the request, it will keep the default that is defined in the JSON file. - -After the HTML template is generated with the replaced variables, it used `wkhtmltopdf` by default or the library selected by `pdfLibrary` to create a PDF based on the HTML file. - -#### Saving the PDF (2/2) - -Once the PDF has been generated, the consumer will create a key value pair in Redis to store it due to it containing PII information. The `key` being `claimSubmissionId` while the `value` is a base64 encoded string representation of the PDF. - -The consumer will return a response similar to: -``` -{ - "claimSubmissionId: "1", - "status": "COMPLETE" -} -``` - -#### Fetch PDF Process - -When the consumer recieves a message in the `fetch-pdf` queue, it will use the provided `claimSubmissionId` to look it up on Redis. - -If the PDF still hasn't been generated, you will recieve a response similar to: -``` -{ - "claimSubmissionId: "1", - "status": "IN_PROGRESS" -} -``` - -but if the PDF is available then the response will be a downloable file - -## Adding a new Diagnostic Code - -1. Edit the `codes` dictionary in `config/settings.py` by adding a new key, value pair for your code. - - Example: - ``` - codes = { - "0000": "cancer", - "0001": "diabetes" //new code with human readable diagnosis - } - ``` -2. Create a HTML version of the PDF you want to generate and save it in the `templates` folder along with a version number - - Take a look at [Jinja 2 Template Documentation](https://jinja.palletsprojects.com/en/3.1.x/templates/) for a better idea of what you can do within the template files - - Every template file needs a version number. By default, the system looks for `v1` if one is not selected based from the request - - The file name should match the name you used in Step 1. Following that example, it should be called `diabetes-v1.html` -3. Create a JSON file in `template_variables` that will contain default values for the HTML file in case they are not provided in the RabbitMQ message - - The file name should match the name you used in Step 1 and 2. Following that example, it should be called `diabetes-v1.json` - -## Helper Functions - -Some diagnostic codes might need specific changes that don't need to affect other templates and instead of adding it to the assessment logic, we can use a helper function. - -When generating a PDF, it will look for a helper function following this naming convention `pdf_helper_0000` where `0000` would be the code we want to use. If it does not find it, it move on and then applies a `pdf_helper_all` that gets applied to every single template. Usually these are edits like turning date string into proper date time objects, etc. - -## Library Specifics (WKHTMLTOPDF / WeasyPrint) - -### WKHTMLTOPDF -#### Table of Contents - -ToCs are not part of the normal HTML template the gets generated fo the PDF. They need to be created through a different process and then added to the other HTML template - -The PDF generator will check if there is a ToC file already created for the `diagnosticCode` that gets passed. If not found, it will generate the PDF without a ToC so you don't have to worry about having a empty section or page - -#### Add a ToC for a new code: - -1. Create a directory in `templates` where the name will be the human readable name used in the `codes` variable in `settings.py` -2. Within this folder, create a `toc.xsl` file. Most ToCs will follow the same format so you can just copy one from any other folder. If you needed to create one from scratch, in the commandline run the following: `wkhtmltopdf --dump-default-toc-xsl` and copy the contents of the output to a new `toc.xsl` file as stated above - -#### Notes - -1. By default a ToC is generated by finding all `` related tags so you need to modify them if you want them ignored. - 1. To ignore a heading, it must start with `‌` like this example: `

‌Test PDF Heading

`. The `toc.xsl` file has logic in place to skip over any headings that start with this special character. -2. The ToC page is fully customizable just like any HTML page -3. Built using Webkit 2.2 (~2012) so many newer HTML features are unavailable or need to be added through other ways like custom plain CSS -4. This library renders at 96DPI but the value can be altered through the meta tags. We need to verify that the Figma design or other design software matches the proper DPI settings by making sure the resolution matches the paper size. Use the following links for proper conversions: https://a-size.com/legal-size-paper/ and https://www.papersizes.org/a-sizes-in-pixels.htm as well as https://pixelsconverter.com/inches-to-pixels - - -### WeasyPrint -#### Table of Contents - -Work in Progress - -#### Notes - -1. This library does not accept Javascript. At the moment, we would need to come up with a workaround by prerendering in a secondary library or just using WKHTMLTOPDF for Javascript specific portions. -2. This library renders at 96DPI and the value cannot be changed. We need to verify that the Figma design or other design software matches the proper DPI settings by making sure the resolution matches the paper size. Use the following links for proper conversions: https://a-size.com/legal-size-paper/ and https://www.papersizes.org/a-sizes-in-pixels.htm as well as https://pixelsconverter.com/inches-to-pixels - -## Testing and Development - -Currently there are 2 ways to develop/test the PDF service: - -1. Run `./gradlew build check docker` to start all containers and run a full test. This can be used for the testing any updates that are made to the endpoints through Swagger but it takes longer due to having to load all the other containers -2. Run `python pdfgenerator/src/lib/local_pdf_test.py` from the `service-python` directory. This file calls the PDF generator while bypassing all the related RabbitMQ and Redis code. You can alter the `diagnosis_name` and `message` to simulate an endpoint request and to quickly debug any template or PDF issues. The `diagnosis_name` should be the full name including version number like `hypertension-v1` diff --git a/domain-rrd/service-python/svc-pdfgenerator/__init__.py b/domain-rrd/service-python/svc-pdfgenerator/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-pdfgenerator/build.gradle.bak b/domain-rrd/service-python/svc-pdfgenerator/build.gradle.bak deleted file mode 100644 index faa7b95c92..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/build.gradle.bak +++ /dev/null @@ -1,8 +0,0 @@ -plugins { - id 'local.python.container-service-conventions' -} - -docker { - // buildArgs is immutable so we have to set additional args this way - buildArgs(["BASE_IMAGE" : "surnet/alpine-python-wkhtmltopdf:3.11.1-0.12.6-small"] << buildArgs) -} diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/__init__.py b/domain-rrd/service-python/svc-pdfgenerator/src/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/__init__.py b/domain-rrd/service-python/svc-pdfgenerator/src/lib/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/helper_functions.py b/domain-rrd/service-python/svc-pdfgenerator/src/lib/helper_functions.py deleted file mode 100644 index 829612debe..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/helper_functions.py +++ /dev/null @@ -1,83 +0,0 @@ -import os -from datetime import datetime - -import pytz -from dateutil import parser -from dateutil.relativedelta import relativedelta - - -def set_empty_readings(value): - if value == 0: - string_value = "-" - else: - string_value = str(int(value)) - return string_value - - -def pdf_helper_hypertension(data): - for reading in data["evidence"]["bp_readings"]: - reading["systolic"]["value"] = set_empty_readings(reading["systolic"]["value"]) - reading["diastolic"]["value"] = set_empty_readings(reading["diastolic"]["value"]) - return data - - -def pdf_helper_all(data: dict) -> dict: - """Adds/modifies the data for all PDFs like adding the timestamp - :param data: PDF data that will be used in the template - :type data: dict - :return: The modified PDF data - :rtype: dict - """ - - data["timestamp"] = pytz.utc.localize(datetime.now()) - # Find out if the PDF is being generated locally(VENV, script, etc.) or through Docker. Depending on which, set the appropriate base path for fonts, images, etc. - run_mode = os.environ.get("DOCKER", "local") - if run_mode == "docker": - data["base_path"] = "/app/public" - else: - current_dir = os.path.abspath(os.path.dirname(__file__)) - data["base_path"] = os.path.join(current_dir, "..", "public") - # Starting date from when the data is fetched. Mainly to be used to display a range Ex: (start_date) to (timestamp) - data["start_date"] = datetime.now() - relativedelta(years=1) - data["timestamp"] = pytz.utc.localize(datetime.now()) - if "evidence" in data: - data["evidence"] = data["evidence"] - if "veteranInfo" in data and data["veteranInfo"]["birthdate"] != "": - birth_date = data["veteranInfo"]["birthdate"].replace("Z", "") - data["veteranInfo"]["birthdate"] = parser.parse(birth_date) - - if "version" in data and data["version"] == "v1": - for medication_info in data["evidence"]["medications"]: - medication_info["authoredOn"] = parser.parse(medication_info["authoredOn"]) - - return data - - -def toc_helper_all(toc_file_path, data) -> str: # pragma: no cover - """Modifies the ToC before it is attached to the PDF - - :param toc_file_path: File path for the base_toc.xsl - :type toc_file_path: str - :param data: PDF data that will be used in the template - :type data: dict - :return: The file path for the modified ToC - :rtype: str - """ - file_data = None - - with open(toc_file_path, 'r') as file: - file_data = file.read() - - # Fill in the base path for fonts, images, etc. - file_data = file_data.replace("{{base_path}}", data['base_path']) - # Fill in the veteran's info like name, dob, identifier, etc. - file_data = file_data.replace("{{name}}", f"{data['veteranInfo']['first']} {data['veteranInfo']['middle']} {data['veteranInfo']['last']}") - file_data = file_data.replace("{{file}}", data['veteranFileId']) - # Fill in the date the ToC/PDF was generated - file_data = file_data.replace("{{date}}", f"{pytz.utc.localize(datetime.now()).strftime('%b. %d, %Y')}") - - generated_toc_path = toc_file_path.replace("base_toc", f"{data['claimSubmissionId']}_toc") - - with open(generated_toc_path, 'w') as file: - file.write(file_data) - return generated_toc_path diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/pdf_generator.py b/domain-rrd/service-python/svc-pdfgenerator/src/lib/pdf_generator.py deleted file mode 100644 index 2436f85337..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/pdf_generator.py +++ /dev/null @@ -1,51 +0,0 @@ -import json -import logging -import os - -import pdfkit -from jinja2 import Environment, PackageLoader, select_autoescape - -from .helper_functions import * # noqa: F403 - -lib_dir = os.path.dirname(__file__) - - -class PDFGenerator: - - def __init__(self, options): - self.options = options - - def generate_template_variables(self, template_name: str, pdf_data: dict) -> dict: - placeholder_variables = json.load(open(os.path.join(lib_dir, f"template_variables/{template_name}.json"))) - filled_variables = {key: pdf_data.get(key, placeholder_variables[key]) for key in placeholder_variables} - if template_name == "default": - filled_variables = {"default_data": pdf_data} - # Run the helper function for the specific code if it exists - try: - eval(f"pdf_helper_{filled_variables['document_type']}(filled_variables)") - except: # noqa: E722, E261 - logging.info("No helper function found") - # Call a helper function that gets run for all codes - filled_variables = pdf_helper_all(filled_variables) # noqa: F405, E261 - return filled_variables - - def generate_template_file(self, template_name: str, template_variables: dict, test_mode=False, loader="pdfgenerator.src.lib") -> str: - loader_path = loader if test_mode else "lib" - jinja_env = Environment( - loader=PackageLoader(loader_path), - autoescape=select_autoescape() - ) - template = jinja_env.get_template(f"{template_name}.html") - generated_html = template.render(**template_variables) - - return generated_html - - def generate_pdf_from_string(self, template_name: str, html: str, data, output=False) -> bytes or bool: - base_toc_file_path = os.path.join(lib_dir, f"templates/{template_name}/base_toc.xsl") - if os.path.isfile(base_toc_file_path): - # Call a helper function that make adjustments to toc before creating - generated_toc_file_path = toc_helper_all(base_toc_file_path, data) # noqa: F405, E261 - toc = {'xsl-style-sheet': generated_toc_file_path} - return pdfkit.from_string(html, output, options=self.options, toc=toc, verbose=False) - else: - return pdfkit.from_string(html, output, options=self.options, verbose=False) diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/queues.py b/domain-rrd/service-python/svc-pdfgenerator/src/lib/queues.py deleted file mode 100644 index 033bd1036d..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/queues.py +++ /dev/null @@ -1,115 +0,0 @@ -import base64 -import json -import logging - -import pika - -from .pdf_generator import PDFGenerator -from .redis_client import RedisClient -from .settings import codes, pdf_options, queue_config, redis_config - -EXCHANGE = queue_config["exchange_name"] -GENERATE_QUEUE = queue_config["generate_queue_name"] -FETCH_QUEUE = queue_config["fetch_queue_name"] -GENERATE_FETCH_QUEUE = queue_config["generate_fetch_queue_name"] - - -def on_generate_callback(channel, method, properties, body): - """Gets called when messages arrive in the GENERATE_QUEUE - :param channel: Object to make further modifications like adding queues, publishing, etc. - :type channel: pika.channel.Channel - :param method: Details on how the data was passed to the queue - :type method: pika.spec.Basic.Deliver - :param properties: Additional data used for replying and correlating messages - :type properties: pika.spec.BasicProperties - :param body: Request data that's passed to the PDF for generation - :type body: bytes - """ - - try: - redis_client = RedisClient(redis_config) - pdf_generator = PDFGenerator(pdf_options) - - message = json.loads(body) - claim_id = message["claimSubmissionId"] - diagnosis_code = message["diagnosticCode"] - message["veteran_info"] = message["veteranInfo"] - pdf_template = message['pdfTemplate'] - try: - template_name = codes[diagnosis_code] + "-" + pdf_template - diagnosis_name = codes[diagnosis_code] - except KeyError: - template_name = "default" - diagnosis_name = "default" - variables = pdf_generator.generate_template_variables(template_name, message) - template = pdf_generator.generate_template_file(template_name, variables) - pdf = pdf_generator.generate_pdf_from_string(template_name, template, variables) - redis_client.save_hash_data(f"{claim_id}-pdf", mapping={"contents": base64.b64encode(pdf).decode("ascii"), "diagnosis": diagnosis_name}) - logging.info(f"Claim {claim_id}: Saved PDF") - # Check if the routing key is for a generate or generate and fetch - if method.routing_key == "generate-pdf": - response = {"claimSubmissionId": claim_id, "status": "COMPLETE"} - else: - pdf = redis_client.get_hash_data(f"{claim_id}-pdf", "contents") - diagnosis_name = redis_client.get_hash_data(f"{claim_id}-pdf", "diagnosis") - logging.info("Fetched PDF") - response = {"claimSubmissionId": claim_id, "status": "COMPLETE", "diagnosis": str(diagnosis_name.decode("ascii")), "pdfData": str(pdf.decode("ascii"))} - except Exception as e: - logging.error(e, exc_info=True) - response = {"claimSubmissionId": claim_id, "status": "ERROR", "reason": str(e)} - channel.basic_publish(exchange=EXCHANGE, routing_key=properties.reply_to, properties=pika.BasicProperties(correlation_id=properties.correlation_id), body=json.dumps(response)) - - -def on_fetch_callback(channel, method, properties, body): - """Gets called when messages arrive in the FETCH_QUEUE - :param channel: Object to make further modifications like adding queues, publishing, etc. - :type channel: pika.channel.Channel - :param method: Details on how the data was passed to the queue - :type method: pika.spec.Basic.Deliver - :param properties: Additional data used for replying and correlating messages - :type properties: pika.spec.BasicProperties - :param body: Request data that's passed to the PDF for generation - :type body: bytes - """ - - try: - redis_client = RedisClient(redis_config) - binding_key = method.routing_key - claim_id = str(body, 'UTF-8') - logging.info(f" [x] {binding_key}: Received Claim Submission ID: {claim_id}") - if redis_client.exists(f"{claim_id}-pdf"): - pdf = redis_client.get_hash_data(f"{claim_id}-pdf", "contents") - diagnosis_name = redis_client.get_hash_data(f"{claim_id}-pdf", "diagnosis") - logging.info("Fetched PDF") - response = {"claimSubmissionId": claim_id, "status": "COMPLETE", "diagnosis": str(diagnosis_name.decode("ascii")), "pdfData": str(pdf.decode("ascii"))} - else: - logging.info("Claim ID not found") - response = {"claimSubmissionId": claim_id, "status": "NOT_FOUND", "diagnosis": "", "pdfData": ""} - except Exception as e: - logging.error(e, exc_info=True) - response = {"claimSubmissionId": claim_id, "status": "ERROR", "diagnosis": "", "pdfData": "", "reason": str(e)} - channel.basic_publish(exchange=EXCHANGE, routing_key=properties.reply_to, properties=pika.BasicProperties(correlation_id=properties.correlation_id), body=json.dumps(response)) - - -def queue_setup(channel): - """Gets called wby the main_consumer to setup all the available queues and their callbacks - :param channel: Object to make further modifications like adding queues, publishing, etc. - :type channel: pika.channel.Channel - """ - - channel.exchange_declare(exchange=EXCHANGE, exchange_type="direct", durable=True, auto_delete=True) - # Generate PDF Queue - channel.queue_declare(queue=GENERATE_QUEUE, durable=True, auto_delete=True) - channel.queue_bind(queue=GENERATE_QUEUE, exchange=EXCHANGE) - channel.basic_consume(queue=GENERATE_QUEUE, on_message_callback=on_generate_callback, auto_ack=True) - # Fetch PDF Queue - channel.queue_declare(queue=FETCH_QUEUE, durable=True, auto_delete=True) - channel.queue_bind(queue=FETCH_QUEUE, exchange=EXCHANGE) - channel.basic_consume(queue=FETCH_QUEUE, on_message_callback=on_fetch_callback, auto_ack=True) - # Generate Fetch PDF Queue - channel.queue_declare(queue=GENERATE_FETCH_QUEUE, durable=True, auto_delete=True) - channel.queue_bind(queue=GENERATE_FETCH_QUEUE, exchange=EXCHANGE) - channel.basic_consume(queue=GENERATE_FETCH_QUEUE, on_message_callback=on_generate_callback, auto_ack=True) - logging.info(f" [*] Waiting for data for queue: {GENERATE_QUEUE}. To exit press CTRL+C") - logging.info(f" [*] Waiting for data for queue: {FETCH_QUEUE}. To exit press CTRL+C") - logging.info(f" [*] Waiting for data for queue: {GENERATE_FETCH_QUEUE}. To exit press CTRL+C") diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/redis_client.py b/domain-rrd/service-python/svc-pdfgenerator/src/lib/redis_client.py deleted file mode 100644 index c0a2126335..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/redis_client.py +++ /dev/null @@ -1,38 +0,0 @@ -import logging -from time import sleep - -import redis - - -class RedisClient: - - def __init__(self, config): - self.config = config - self.client = self._create_client() - - def _create_client(self): - for i in range(self.config["retry_limit"]): - try: - client = redis.Redis(host=self.config["host"], port=self.config["port"], password=self.config["password"]) - logging.warning(f"Redis Connected: {client}") - return client - except Exception: - logging.warning(f"Redis Connection Failed. Retrying in 15s ({i + 1}/{self.config['retry_limit']})") - sleep(15) - - def exists(self, key): - return self.client.exists(key) - - def save_data(self, key, value): - self.client.set(key, value) - self.client.expire(key, self.config["expiration"]) - - def get_data(self, key): - return self.client.get(key) - - def save_hash_data(self, name, key=None, value=None, mapping=None, items=None): - self.client.hset(name, key, value, mapping, items) - self.client.expire(name, self.config["expiration"]) - - def get_hash_data(self, name, key): - return self.client.hget(name, key) diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/settings.py b/domain-rrd/service-python/svc-pdfgenerator/src/lib/settings.py deleted file mode 100644 index ef30aeb6f1..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/settings.py +++ /dev/null @@ -1,29 +0,0 @@ -import os - -pdf_options = { - "encoding": "UTF-8", - "print-media-type": None, - "enable-local-file-access": None, - "disable-smart-shrinking": None, -} - -redis_config = { - "host": os.environ.get("REDIS_PLACEHOLDERS_HOST", "localhost"), - "port": 6379, - "password": os.environ.get("REDIS_PASSWORD", "not-redis-password"), - "retry_limit": 3, - # 3 hours - "expiration": 60 * 60 * 3 -} - -queue_config = { - "exchange_name": "pdf-generator", - "generate_queue_name": "generate-pdf", - "fetch_queue_name": "fetch-pdf", - "generate_fetch_queue_name": "generate-fetch-pdf", -} - -codes = { - "6602": "asthma", - "7101": "hypertension", -} diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/asthma-v1.json b/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/asthma-v1.json deleted file mode 100644 index b30969cec6..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/asthma-v1.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "code": "6602", - "version": "v1", - "document_type": "asthma", - "veteranInfo": { - "first": "", - "middle": "", - "last": "", - "suffix": "", - "birthdate": "1935-06-15T00:00:00+00:00" - }, - "evidence": { - "bp_readings": [], - "medications": [] - } -} diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/default.json b/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/default.json deleted file mode 100644 index e146b54e1f..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/default.json +++ /dev/null @@ -1 +0,0 @@ -{"default_data": {}} diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/hypertension-v1.json b/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/hypertension-v1.json deleted file mode 100644 index d65ce78eae..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/hypertension-v1.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "code": "7101", - "version": "v1", - "document_type": "hypertension", - "veteranInfo": { - "first": "", - "middle": "", - "last": "", - "suffix": "", - "birthdate": "1936-06-15T00:00:00+00:00" - }, - "evidence": { - "bp_readings": [], - "medications": [] - } -} diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/hypertension-v2.json b/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/hypertension-v2.json deleted file mode 100644 index dbbf093f68..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/template_variables/hypertension-v2.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "claimSubmissionId": "1234", - "version": "v2", - "code": "7101", - "document_type": "hypertension", - "conditions": [], - "veteranFileId": "0000", - "veteranInfo": { - "first": "Test", - "middle": "", - "last": "User", - "suffix": "", - "birthdate": "1935-06-15T00:00:00+00:00" - }, - "evidence": { - "bp_readings": [], - "conditions": [], - "medications": [], - "procedures": [], - "serviceLocations": [], - "documentsWithoutAnnotationsChecked": [] - } -} diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/asthma-v1.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/asthma-v1.html deleted file mode 100644 index 83aec31fc9..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/asthma-v1.html +++ /dev/null @@ -1,6 +0,0 @@ -{% include "shared/intro.html" %} -{% block body %} - {% include "shared/medications.html" %} - {% include "asthma-v1/rating_schedule.html" %} - {% include "asthma-v1/about.html" %} -{% endblock %} diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/asthma-v1/about.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/asthma-v1/about.html deleted file mode 100644 index 43a6bc14bf..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/asthma-v1/about.html +++ /dev/null @@ -1,44 +0,0 @@ -

- Some medical data are not included in this PDF. Please check for additional readings and sources. -

-

- This summary does not check all sources of medical information for Veterans that are necessary for you to - rate this claim accurately. You will need to check these sources manually to gather all available evidence. -

-

- Clinical notes. - This data may not match all the medical evidence in CAPRI. For example, it may not find medical data entered into clinical notes. -

-

- Data outside of VAMC CAPRI or VistA. This report does not check the following sources: -

    -
  • Private medical data
  • -
  • VAMC data for clinics using CERNER EHR
  • -
  • Department of Defense/JVL medical data
  • -
  • Documents in the Veteran's VBMS eFolder
  • -
-

-

-
-

-

How we identify asthma medications

-

- The automated routine for identifying medications that may have been prescribed for asthma relies on keyword filtering. - A prescription is marked for asthma if it matches either of these filters: -

    -
  • The medication name is on a list of medications frequently prescribed for asthma.
  • -
  • The dosage instructions contain a keyword, such as “asthma,” “breathing,” “inhale,” “inhalation,” or “puff.”
  • -
-

-

-
-

-

About this Document

-

- The Health Evidence Rapid Ready for Decision system retrieves and summarizes VHA medical records related to - claims for increase submitted on va.gov. VSRs and RVSRs can develop and rate this claim without ordering an - exam if there is sufficient existing evidence to rate a claim to - Title 38 C.F.R. § 4. This is not new guidance, - but rather a way to operationalize existing statutory rules in 38 U.S.C. § 5103A(d). -

diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/asthma-v1/rating_schedule.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/asthma-v1/rating_schedule.html deleted file mode 100644 index 53322bdde9..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/asthma-v1/rating_schedule.html +++ /dev/null @@ -1,62 +0,0 @@ -
-

Asthma Rating Schedule

- - - - - - - - - - - - - - - - - -
100% - FEV-1 less than 40-percent predicted, or; -
- FEV-1/FVC less than 40 percent, or; -
- more than one attack per week with episodes of respiratory failure, or; -
- requires daily use of systemic (oral or parenteral) high dose corticosteroids -
- or immuno-suppressive medications -
60% - FEV-1 of 40- to 55-percent predicted, or; -
- FEV-1/FVC of 40 to 55 percent, or; -
- at least monthly visits to a physician for required care of exacerbations, or; -
- intermittent (at least three per year) courses of systemic (oral or parenteral) corticosteroids -
30% - FEV-1 of 56- to 70-percent predicted, or; -
- FEV-1/FVC of 56 to 70 percent, or; -
- daily inhalational or oral bronchodilator therapy, or; -
- inhalational anti-inflammatory medication -
10% - EV-1 of 71- to 80-percent predicted, or; -
- FEV-1/FVC of 71 to 80 percent, or; -
- intermittent inhalational or oral bronchodilator therapy -
-

- Note: - In the absence of clinical findings of asthma at time of examination, a verified history of asthmatic attacks must be of record. - View rating schedule -

-
-

-
-

diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/default.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/default.html deleted file mode 100644 index fb7d953588..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/default.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - {% for key, values in default_data.items() %} -

{{key}}

- - {{ values |tojson }} - - {% endfor %} -

JSON Data

- - {{ default_data |tojson }} - - {% block body %}{% endblock %} - - - - diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1.html deleted file mode 100644 index 85819b1439..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1.html +++ /dev/null @@ -1,7 +0,0 @@ -{% include "shared/intro.html" %} -{% block body %} - {% include "hypertension-v1/blood_pressure_readings.html" %} - {% include "hypertension-v1/rating_schedule.html" %} - {% include "shared/medications.html" %} - {% include "hypertension-v1/about.html" %} -{% endblock %} diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1/about.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1/about.html deleted file mode 100644 index 04537c56ba..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1/about.html +++ /dev/null @@ -1,33 +0,0 @@ -

About this Document

-

- The Hypertension Rapid Ready for Decision system retrieves and summarizes - VHA medical records related to hypertension claims for increase submitted on va.gov. - VSRs and RVSRs can develop and rate this claim without ordering an exam if there is - sufficient existing evidence to show predominance according to DC 7101 (Hypertension) Rating Criteria - This is not new guidance, but rather a way to operationalize existing statutory rules - in 38 U.S.C § 5103a(d). -

-

- Some medical data are not included in this PDF. Please check for additional readings and sources. -

-

- This summary does not check all sources of medical information for Veterans that - are necessary for you to rate this claim accurately. - You will need to check these sources manually to gather all available evidence. -

-

- Clinical notes. - This data may not match all the medical evidence in CAPRI. For example, it may not find blood - pressure readings entered into clinical notes. -

-

- Data outside of VAMC CAPRI or VistA. This report does not check the following sources: -

    -
  • Private medical records
  • -
  • VAMC data for clinics using CERNER EHR
  • -
  • Department of Defense/JVL medical data
  • -
  • Documents in the Veteran's VBMS eFolder
  • -
-

diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1/blood_pressure_readings.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1/blood_pressure_readings.html deleted file mode 100644 index 3e821cd1d2..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1/blood_pressure_readings.html +++ /dev/null @@ -1,24 +0,0 @@ -

- {% if evidence.bp_readings and evidence.bp_readings|length > 0 %} -

One Year of Blood Pressure History

- {% else %} -

No blood pressure records found

- {% endif %} -

-VHA records searched from {{ start_date.strftime('%m/%d/%Y') }} to {{ timestamp.strftime('%m/%d/%Y') }} -
-All VAMC locations using VistA/CAPRI were checked -{% if evidence.bp_readings and evidence.bp_readings|length > 0 %} -

Blood pressure is shown as systolic/diastolic.

-{% endif %} -{% if evidence.bp_readings %} - {% for measurement in evidence.bp_readings %} -

- Blood pressure: {{ measurement.systolic.value }}/{{ measurement.diastolic.value }} -
- Taken on: {{ measurement.date }} -
- Location: {{ measurement.organization or "Unknown" }} -

- {% endfor %} -{% endif %} diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1/rating_schedule.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1/rating_schedule.html deleted file mode 100644 index cfe7a69bf8..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v1/rating_schedule.html +++ /dev/null @@ -1,28 +0,0 @@ -

Hypertension Rating Schedule

- - - - - - - - - - - - - - - - - -
10% - Systolic pressure predominantly 160 or more; or diastolic pressure predominantly 100 or more; - or minimum evaluation for an individual with a history of diastolic pressure predominantly - 100 or more who requires continuous medication for control -
20%Systolic pressure predominantly 200 or more; or diastolic pressure predominantly 110 or more
40%Diastolic pressure 120 or more
60%Diastolic pressure 130 or more
-

- View rating schedule -

-
diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v2-breakpoint.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v2-breakpoint.html deleted file mode 100644 index 1102621f81..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v2-breakpoint.html +++ /dev/null @@ -1,490 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - {{pdf_title}} - - - - - - - {% if conditions.disabilityActionType == "NEW" %} - -
-
-

Evidence for service connection

-

Claimed as: {{ conditions.name }}
Relevant diagnosis code: Hypertension (7101)

-
-
-
-
-

- Agent Orange Exposure Verified corporate flash was found.
- The Veteran is claiming a condition that may be presumptive based on their service.
- The PACT Act was signed into law on Aug. 10, 2022, and made hypertension presumptive for Agent Orange exposure. -

-
-
-
-
-

Relevant military service locations

-
-
-
-
- - - - - - - - - - - - {% for location in evidence.serviceLocations %} - - - - - - - - {% endfor %} - {% if evidence.serviceLocations |length == 0 %} - - - - {% endif %} - -
Key termsDocumentVBMS receipt datePage number(s)Document ID
{{ location.location }}{{ location.document }}{{ location.receiptDate }}{{ location.page }}{{ location.documentId }}
No service locations found through automated review.
-
-
- -
-
-

Condition history

-

The VistA EHR search found the following diagnosis information in VHA records as of {{ timestamp.strftime('%b. %d, %Y') }}.

-
-
-
-
- - - - - - - - - {% for condition in evidence.conditions |selectattr("dataSource", "equalto", "LH") |selectattr("relevant") |list %} - - - - - {% endfor %} - {% if evidence.conditions |selectattr("dataSource", "equalto", "LH") |selectattr("relevant") |list |length == 0 %} - - - - {% endif %} - -
Encounter diagnosis*Recorded date
{{ condition.text}}{% if condition.dateFormatted == "" and condition.partialDate == "" %}No associated date{% elif condition.dateFormatted == "" and condition.partialDate != "" %}Non-confident date {{condition.partialDate}}{% else %}{{ condition.dateFormatted }}{% endif %}
No encounter diagnoses found through automated review.
-

*An encounter diagnosis is a point-in-time diagnosis (for example, from a physician or nurse) made during a specific - interaction with the patient, such as during an appointment or in-patient treatment. It may be a preliminary assessment.

-
-
- {% endif %} - -
-
-

Condition: Hypertension

-

Schedular evidence for hypertension – blood pressure readings

-

The automated search found the following blood pressure readings in VistA EHR and the eFolder scan as of {{ timestamp.strftime('%b. %d, %Y') }}. Some blood pressure readings may appear more than once from different sources, always check for duplicate readings.

-
-
-
-
- - - - - - - - - - - - - {% for bp_reading in evidence.bp_readings %} - - - - - - - - - {% endfor %} - {% if evidence.bp_readings |length == 0 %} - - - - {% endif %} - -
Blood pressureObservation dateSourceVBMS receipt datePage number(s) / Event ID(s)Document ID
{{ bp_reading.systolic.value }}/{{ bp_reading.diastolic.value }}{% if bp_reading.dateFormatted == ""%}No associated date{% else %}{{ bp_reading.dateFormatted }}{% endif %}{% if not bp_reading.organization and bp_reading.dataSource == "MAS" %}n.a.{% elif not bp_reading.organization and bp_reading.dataSource == "LH" %} VAMC record {% elif bp_reading.organization and bp_reading.dataSource == "LH" %} VAMC record - {{ bp_reading.organization }}{% else %}{{ bp_reading.organization }}{% endif %}{% if bp_reading.receiptDate == "" %}n.a.{% else %}{{ bp_reading.receiptDate }}{% endif %}{% if bp_reading.page == "" %}n.a.{% else %}{{ bp_reading.page }}{% endif %} - {% if bp_reading.dataSource == "MAS" %} - {% if bp_reading.organization == "VAMC Other Output Reports" and bp_reading.document == "" %} - Pending upload to VBMS eFolder - {% elif bp_reading.document == "" %} - Pending upload to VBMS eFolder - {% else %} - {{ bp_reading.document }} - {% endif %} - {% else %} - {% if bp_reading.document == "" %} - n.a. - data pulled directly from VistA - {% else %} - {{ bp_reading.document }} - {% endif %} - {% endif %} -
No blood pressure readings found through automated review.
-
-
- -
-
-

Schedular evidence for hypertension

-
-
-
-
- - - - - - - - - - - - - {% for medication in evidence.medications %} - - - - - - - - - {% endfor %} - {% if evidence.medications |length == 0 %} - - - - {% endif %} - -
Key termsObservation dateSourceVBMS receipt datePage number(s) / Event ID(s)Document ID
{{ medication.description }}{% if medication.dateFormatted == "" and medication.partialDate == "" %}No associated date{% elif medication.dateFormatted == "" and medication.partialDate != "" %}Non-confident date {{medication.partialDate}}{% else %}{{ medication.dateFormatted }}{% endif %}{% if not medication.organization and medication.dataSource == "MAS" %}n.a.{% elif not medication.organization and medication.dataSource == "LH" %} VAMC record {% elif medication.organization and medication.dataSource == "LH" %} VAMC record - {{ medication.organization }}{% else %}{{ medication.organization }}{% endif %}{% if medication.receiptDate == ""%}n.a.{% else %}{{ medication.receiptDate }}{% endif %}{% if medication.page == ""%}n.a.{% else %}{{ medication.page }}{% endif %} - {% if medication.dataSource == "MAS" %} - {% if medication.organization == "VAMC Other Output Reports" and medication.document == "" %} - Pending upload to VBMS eFolder - {% elif medication.document == "" %} - Pending upload to VBMS eFolder - {% else %} - {{ medication.document }} - {% endif %} - {% else %} - {% if medication.document == "" %} - n.a. - data pulled directly from VistA - {% else %} - {{ medication.document }} - {% endif %} - {% endif %} -
No keywords found through automated review.
-
-
- -
-
-

Other medical evidence for hypertension

-
-
-
-
- - - - - - - - - - - - - {% for condition in evidence.conditions |selectattr("dataSource", "equalto", "MAS") |list %} - - - - - - - - - {% endfor %} - {% if evidence.conditions |selectattr("dataSource", "equalto", "MAS") |list |length == 0 %} - - - - {% endif %} - -
Key termsObservation dateSourceVBMS receipt datePage number(s) / Event ID(s)Document ID
{{ condition.text }}{% if condition.dateFormatted == "" and condition.partialDate == "" %}No associated date{% elif condition.dateFormatted == "" and condition.partialDate != "" %}Non-confident date {{condition.partialDate}}{% else %}{{ condition.dateFormatted }}{% endif %}{% if condition.organization == ""%}n.a.{% else %}{{ condition.organization }}{% endif %}{% if condition.receiptDate == ""%}n.a.{% else %}{{ condition.receiptDate }}{% endif %}{% if condition.page == ""%}n.a.{% else %}{{ condition.page }}{% endif %} - {% if condition.organization == "VAMC Other Output Reports" and condition.document == "" %} - Pending upload to VBMS eFolder - {% elif condition.document == "" %} - Pending upload to VBMS eFolder - {% else %} - {{ condition.document }} - {% endif %} -
No keywords found through automated review.
-
-
- - -
-
-

Relevant documents unavailable for automated review

-
-
-
-
- - - - - - - - - - {% for review in evidence.documentsWithoutAnnotationsChecked %} - - - - - - {% endfor %} - {% if evidence.documentsWithoutAnnotationsChecked |length == 0 %} - - - - {% endif %} - -
DocumentVBMS receipt dateDocument ID
n.a.n.a.{{ review }}
The automated review scanned all relevant documents.
-
-
-
- -
-
-

About this document

-

The Evidence Review Summary retrieves and summarizes VistA electronic health records and scanned eFolder documents submitted through va.gov and the Centralized Mail Portal. VSRs and RVSRs can develop and rate this claim without ordering an exam if there is sufficient existing evidence to do so per existing statutory rules in 38 U.S.C § 5103A(d).

-

This document summarizes data gathered from two sources:

-
    -
  • VistA Electronic Health Records (EHRs): This document includes digital medical information from VistA. This data will exclude some readings, such as blood pressure readings entered into clinical notes.
  • -
  • eFolder document scan: Certain documents within the Veteran’s eFolder are digitally scanned and relevant search terms and summarized in this document. Only data in the eFolder on the date of the claim are included, although some documents uploaded on the date of claim may not be included.
  • -
-

Always check for additional data. The following data are only included if they were in the eFolder on the date of claim:

-
    -
  • Medical records at a military or non-governmental facility
  • -
  • Medical records from a VA medical facility using Cerner EHR
  • -
-

Always check for duplicate data entries in this document; some data points may appear more than once. The VistA EHR and eFolder scan both contain VAMC medical records, and may find the same information in both places.

-
-
- - {% block body %}{% endblock %} - - - - - diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v2.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v2.html deleted file mode 100644 index 94f344a98e..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v2.html +++ /dev/null @@ -1,471 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - {{pdf_title}} - - - - - - - {% if conditions.disabilityActionType == "NEW" %} - -
-
-

Evidence for service connection

-

Claimed as: {{ conditions.name }}
Relevant diagnosis code: Hypertension (7101)

-
-
-
-
-

- Agent Orange Exposure Verified corporate flash was found.
- The Veteran is claiming a condition that may be presumptive based on their service.
- The PACT Act was signed into law on Aug. 10, 2022, and made hypertension presumptive for Agent Orange exposure. -

-
-
-
-
-

Relevant military service locations

-
-
-
-
- - - - - - - - - - - - {% for location in evidence.serviceLocations %} - - - - - - - - {% endfor %} - {% if evidence.serviceLocations |length == 0 %} - - - - {% endif %} - -
Key termsDocumentVBMS receipt datePage number(s)Document ID
{{ location.location }}{{ location.document }}{{ location.receiptDate }}{{ location.page }}{{ location.documentId }}
No service locations found through automated review.
-
-
-
- -
-
-

Condition history

-

The VistA EHR search found the following diagnosis information in VHA records as of {{ timestamp.strftime('%b. %d, %Y') }}.

-
-
-
-
- - - - - - - - - {% for condition in evidence.conditions |selectattr("dataSource", "equalto", "LH") |selectattr("relevant") |list %} - - - - - {% endfor %} - {% if evidence.conditions |selectattr("dataSource", "equalto", "LH") |selectattr("relevant") |list |length == 0 %} - - - - {% endif %} - -
Encounter diagnosis*Recorded date
{{ condition.text}}{% if condition.dateFormatted == "" and condition.partialDate == "" %}No associated date{% elif condition.dateFormatted == "" and condition.partialDate != "" %}Non-confident date {{condition.partialDate}}{% else %}{{ condition.dateFormatted }}{% endif %}
No encounter diagnoses found through automated review.
-

*An encounter diagnosis is a point-in-time diagnosis (for example, from a physician or nurse) made during a specific - interaction with the patient, such as during an appointment or in-patient treatment. It may be a preliminary assessment.

-
-
-
- {% endif %} - -
-
-

Condition: Hypertension

-

Schedular evidence for hypertension – blood pressure readings

-

The automated search found the following blood pressure readings in VistA EHR and the eFolder scan as of {{ timestamp.strftime('%b. %d, %Y') }}. Some blood pressure readings may appear more than once from different sources, always check for duplicate readings.

-
-
-
-
- - - - - - - - - - - - - {% for bp_reading in evidence.bp_readings %} - - - - - - - - - {% endfor %} - {% if evidence.bp_readings |length == 0 %} - - - - {% endif %} - -
Blood pressureObservation dateSourceVBMS receipt datePage number(s) / Event ID(s)Document ID
{{ bp_reading.systolic.value }}/{{ bp_reading.diastolic.value }}{% if bp_reading.dateFormatted == ""%}No associated date{% else %}{{ bp_reading.dateFormatted }}{% endif %}{% if not bp_reading.organization and bp_reading.dataSource == "MAS" %}n.a.{% elif not bp_reading.organization and bp_reading.dataSource == "LH" %} VAMC record {% elif bp_reading.organization and bp_reading.dataSource == "LH" %} VAMC record - {{ bp_reading.organization }}{% else %}{{ bp_reading.organization }}{% endif %}{% if bp_reading.receiptDate == "" %}n.a.{% else %}{{ bp_reading.receiptDate }}{% endif %}{% if bp_reading.page == "" %}n.a.{% else %}{{ bp_reading.page }}{% endif %} - {% if bp_reading.dataSource == "MAS" %} - {% if bp_reading.organization == "VAMC Other Output Reports" and bp_reading.document == "" %} - Pending upload to VBMS eFolder - {% elif bp_reading.document == "" %} - Pending upload to VBMS eFolder - {% else %} - {{ bp_reading.document }} - {% endif %} - {% else %} - {% if bp_reading.document == "" %} - n.a. - data pulled directly from VistA - {% else %} - {{ bp_reading.document }} - {% endif %} - {% endif %} -
No blood pressure readings found through automated review.
-
-
-
- -
-
-

Schedular evidence for hypertension

-
-
-
-
- - - - - - - - - - - - - {% for medication in evidence.medications %} - - - - - - - - - {% endfor %} - {% if evidence.medications |length == 0 %} - - - - {% endif %} - -
Key termsObservation dateSourceVBMS receipt datePage number(s) / Event ID(s)Document ID
{{ medication.description }}{% if medication.dateFormatted == "" and medication.partialDate == "" %}No associated date{% elif medication.dateFormatted == "" and medication.partialDate != "" %}Non-confident date {{medication.partialDate}}{% else %}{{ medication.dateFormatted }}{% endif %}{% if not medication.organization and medication.dataSource == "MAS" %}n.a.{% elif not medication.organization and medication.dataSource == "LH" %} VAMC record {% elif medication.organization and medication.dataSource == "LH" %} VAMC record - {{ medication.organization }}{% else %}{{ medication.organization }}{% endif %}{% if medication.receiptDate == ""%}n.a.{% else %}{{ medication.receiptDate }}{% endif %}{% if medication.page == ""%}n.a.{% else %}{{ medication.page }}{% endif %} - {% if medication.dataSource == "MAS" %} - {% if medication.organization == "VAMC Other Output Reports" and medication.document == "" %} - Pending upload to VBMS eFolder - {% elif medication.document == "" %} - Pending upload to VBMS eFolder - {% else %} - {{ medication.document }} - {% endif %} - {% else %} - {% if medication.document == "" %} - n.a. - data pulled directly from VistA - {% else %} - {{ medication.document }} - {% endif %} - {% endif %} -
No keywords found through automated review.
-
-
-
- -
-
-

Other medical evidence for hypertension

-
-
-
-
- - - - - - - - - - - - - {% for condition in evidence.conditions |selectattr("dataSource", "equalto", "MAS") |list %} - - - - - - - - - {% endfor %} - {% if evidence.conditions |selectattr("dataSource", "equalto", "MAS") |list |length == 0 %} - - - - {% endif %} - -
Key termsObservation dateSourceVBMS receipt datePage number(s) / Event ID(s)Document ID
{{ condition.text }}{% if condition.dateFormatted == "" and condition.partialDate == "" %}No associated date{% elif condition.dateFormatted == "" and condition.partialDate != "" %}Non-confident date {{condition.partialDate}}{% else %}{{ condition.dateFormatted }}{% endif %}{% if condition.organization == ""%}n.a.{% else %}{{ condition.organization }}{% endif %}{% if condition.receiptDate == ""%}n.a.{% else %}{{ condition.receiptDate }}{% endif %}{% if condition.page == ""%}n.a.{% else %}{{ condition.page }}{% endif %} - {% if condition.organization == "VAMC Other Output Reports" and condition.document == "" %} - Pending upload to VBMS eFolder - {% elif condition.document == "" %} - Pending upload to VBMS eFolder - {% else %} - {{ condition.document }} - {% endif %} -
No keywords found through automated review.
-
-
- - -
-
-

Relevant documents unavailable for automated review

-
-
-
-
- - - - - - - - - - {% for review in evidence.documentsWithoutAnnotationsChecked %} - - - - - - {% endfor %} - {% if evidence.documentsWithoutAnnotationsChecked |length == 0 %} - - - - {% endif %} - -
DocumentVBMS receipt dateDocument ID
n.a.n.a.{{ review }}
The automated review scanned all relevant documents.
-
-
-
- -
-
-

About this document

-

The Evidence Review Summary retrieves and summarizes VistA electronic health records and scanned eFolder documents submitted through va.gov and the Centralized Mail Portal. VSRs and RVSRs can develop and rate this claim without ordering an exam if there is sufficient existing evidence to do so per existing statutory rules in 38 U.S.C § 5103A(d).

-

This document summarizes data gathered from two sources:

-
    -
  • VistA Electronic Health Records (EHRs): This document includes digital medical information from VistA. This data will exclude some readings, such as blood pressure readings entered into clinical notes.
  • -
  • eFolder document scan: Certain documents within the Veteran’s eFolder are digitally scanned and relevant search terms and summarized in this document. Only data in the eFolder on the date of the claim are included, although some documents uploaded on the date of claim may not be included.
  • -
-

Always check for additional data. The following data are only included if they were in the eFolder on the date of claim:

-
    -
  • Medical records at a military or non-governmental facility
  • -
  • Medical records from a VA medical facility using Cerner EHR
  • -
-

Always check for duplicate data entries in this document; some data points may appear more than once. The VistA EHR and eFolder scan both contain VAMC medical records, and may find the same information in both places.

-
-
- - {% block body %}{% endblock %} - - - - diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v2/base_toc.xsl b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v2/base_toc.xsl deleted file mode 100644 index c9bc054b37..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/hypertension-v2/base_toc.xsl +++ /dev/null @@ -1,261 +0,0 @@ - - - - - - - - - - - - - - -
-
-
-

Evidence Review Summary

-
- - - - - - - - - - - - - -
Veteran's name{{name}}
VA file number{{file}}
Date of evidence review{{date}}
-
-
-
-

- Claims Processors: This document summarizes data from VHA locations that use VistA/CAPRI, as well as scanned text from relevant documents in the Veteran’s eFolder on the date of claim. -

-

- Notice(s): Some relevant data may be missing and some of the same data may appear twice. Learn more in the - - section. -

-
-
-
-
-

Table of contents

-
    - - - -
-
-
- - - -
- - - - -
  • - - - -
      - added to prevent self-closing tags in QtXmlPatterns - -
    -
  • -
    - - - - - - - - - - - - - -
    -
    diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/shared/intro.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/shared/intro.html deleted file mode 100644 index e9554d801c..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/shared/intro.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - {{pdf_title}} - - - - - - -

    {{document_type|capitalize}} Rapid Ready for Decision | Claim for Increase

    -

    VHA {{document_type|capitalize}} Data Summary

    - Generated automatically on {{timestamp.strftime('%m/%d/%Y')}} at {{timestamp.strftime('%H:%M %p %Z')}} -

    - -

    {{veteranInfo.first}} {{veteranInfo.middle}} {{veteranInfo.last}} {{veteranInfo.suffix}}

    - -

    DOB: {{veteranInfo.birthdate.strftime('%m/%d/%Y')}}

    - {% block body %}{% endblock %} - - - - - diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/shared/medications.html b/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/shared/medications.html deleted file mode 100644 index 9439921bb0..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/lib/templates/shared/medications.html +++ /dev/null @@ -1,66 +0,0 @@ -

    -

    Active Prescriptions

    - VHA records searched for medication prescriptions active as of {{timestamp.strftime('%m/%d/%Y')}}
    - All VAMC locations using VistA/CAPRI were checked
    -

    - -{% if document_type == "asthma" %} - - -
    - Important! Medications that may have been prescribed for asthma are marked - with arrows.
    - Claims adjudicators should check the patient's medical records to see what the medication was - prescribed for.
    - See "How we identify asthma prescriptions" at the end of this document for more details. -
    -{% endif %} - -{% if evidence.medications and evidence.medications|length > 0 %} - {% for medicine in evidence.medications %} -
    -

    - {% if medicine.asthmaRelevant %} - - {{medicine.description}} -
    - {% else %} - {{medicine.description}}
    - {% endif %} - {% if medicine.notes %} - {% for note in medicine.notes %} - {{note}} - {% endfor %}
    - {% endif %} - {% if medicine.dosageInstructions %} - {% for dosage in medicine.dosageInstructions %} - {{dosage}} - {% endfor %}
    - {% endif %} - - Prescribed on: - {% if medicine.authoredOn %} - {{medicine.authoredOn.strftime('%m/%d/%Y')}} at {{medicine.authoredOn.strftime('%H:%M %p %Z')}} - {% endif %} - -          - Duration: - {% if medicine.duration %} - {{medicine.duration}} - {% endif %} - -          - Refills: - {% if medicine.refills %} - {{medicine.refills}} - {% endif %}
    - - Route: - {% if medicine.route %} - {{medicine.route}} - {% endif %} -

    - {% endfor %} -{% else %} -
    No active medications were found in the last year
    -{% endif %} diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/local_pdf_test.py b/domain-rrd/service-python/svc-pdfgenerator/src/local_pdf_test.py deleted file mode 100644 index c62d14c18a..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/local_pdf_test.py +++ /dev/null @@ -1,15 +0,0 @@ -from lib.pdf_generator import PDFGenerator -from lib.settings import pdf_options - -if __name__ == '__main__': - diagnosis_name = "hypertension-v2" - message = {} - pdf_generator = PDFGenerator(pdf_options) - variables = pdf_generator.generate_template_variables(diagnosis_name, message) - # print("Variables: ", variables) - template = pdf_generator.generate_template_file(diagnosis_name, variables, test_mode=True, loader="lib") - # print("Template: ", template) - with open("test.html", "w") as file: - file.write(template) - pdf = pdf_generator.generate_pdf_from_string(diagnosis_name, template, variables, 'test.pdf') - # print("PDF: ", pdf) diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/css/bootstrap.min.css b/domain-rrd/service-python/svc-pdfgenerator/src/public/css/bootstrap.min.css deleted file mode 100644 index 2d4170023a..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/public/css/bootstrap.min.css +++ /dev/null @@ -1,7 +0,0 @@ -@charset "UTF-8";/*! - * Bootstrap v5.0.2 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors - * Copyright 2011-2021 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0))}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-font-sans-serif);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:#6c757d}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{width:100%;padding-right:var(--bs-gutter-x,.75rem);padding-left:var(--bs-gutter-x,.75rem);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(var(--bs-gutter-y) * -1);margin-right:calc(var(--bs-gutter-x) * -.5);margin-left:calc(var(--bs-gutter-x) * -.5)}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.6666666667%}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.6666666667%}}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-bg:transparent;--bs-table-accent-bg:transparent;--bs-table-striped-color:#212529;--bs-table-striped-bg:rgba(0, 0, 0, 0.05);--bs-table-active-color:#212529;--bs-table-active-bg:rgba(0, 0, 0, 0.1);--bs-table-hover-color:#212529;--bs-table-hover-bg:rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#212529;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:last-child)>:last-child>*{border-bottom-color:currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-striped>tbody>tr:nth-of-type(odd){--bs-table-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg:#cfe2ff;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:#000;border-color:#bacbe6}.table-secondary{--bs-table-bg:#e2e3e5;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:#000;border-color:#cbccce}.table-success{--bs-table-bg:#d1e7dd;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:#000;border-color:#bcd0c7}.table-info{--bs-table-bg:#cff4fc;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:#000;border-color:#badce3}.table-warning{--bs-table-bg:#fff3cd;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg:#f8d7da;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:#000;border-color:#dfc2c4}.table-light{--bs-table-bg:#f8f9fa;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg:#212529;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:#fff;border-color:#373b3e}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + (.5rem + 2px));padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + (1rem + 2px));padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + (.75rem + 2px))}textarea.form-control-sm{min-height:calc(1.5em + (.5rem + 2px))}textarea.form-control-lg{min-height:calc(1.5em + (1rem + 2px))}.form-control-color{max-width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(25,135,84,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#198754;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:#198754}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:#198754}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:#198754}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group .form-control.is-valid,.input-group .form-select.is-valid,.was-validated .input-group .form-control:valid,.was-validated .input-group .form-select:valid{z-index:1}.input-group .form-control.is-valid:focus,.input-group .form-select.is-valid:focus,.was-validated .input-group .form-control:valid:focus,.was-validated .input-group .form-select:valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:#dc3545}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:#dc3545}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:#dc3545}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group .form-control.is-invalid,.input-group .form-select.is-invalid,.was-validated .input-group .form-control:invalid,.was-validated .input-group .form-select:invalid{z-index:2}.input-group .form-control.is-invalid:focus,.input-group .form-select.is-invalid:focus,.was-validated .input-group .form-control:invalid:focus,.was-validated .input-group .form-select:invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-primary{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-primary:hover{color:#fff;background-color:#0b5ed7;border-color:#0a58ca}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#0b5ed7;border-color:#0a58ca;box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-check:active+.btn-primary,.btn-check:checked+.btn-primary,.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0a58ca;border-color:#0a53be}.btn-check:active+.btn-primary:focus,.btn-check:checked+.btn-primary:focus,.btn-primary.active:focus,.btn-primary:active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5c636a;border-color:#565e64}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#5c636a;border-color:#565e64;box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-check:active+.btn-secondary,.btn-check:checked+.btn-secondary,.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#565e64;border-color:#51585e}.btn-check:active+.btn-secondary:focus,.btn-check:checked+.btn-secondary:focus,.btn-secondary.active:focus,.btn-secondary:active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:active+.btn-success,.btn-check:checked+.btn-success,.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:active+.btn-success:focus,.btn-check:checked+.btn-success:focus,.btn-success.active:focus,.btn-success:active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:active+.btn-info,.btn-check:checked+.btn-info,.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:active+.btn-info:focus,.btn-check:checked+.btn-info:focus,.btn-info.active:focus,.btn-info:active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info.disabled,.btn-info:disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:active+.btn-warning,.btn-check:checked+.btn-warning,.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:active+.btn-warning:focus,.btn-check:checked+.btn-warning:focus,.btn-warning.active:focus,.btn-warning:active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:active+.btn-danger,.btn-check:checked+.btn-danger,.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:active+.btn-danger:focus,.btn-check:checked+.btn-danger:focus,.btn-danger.active:focus,.btn-danger:active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:active+.btn-light,.btn-check:checked+.btn-light,.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:active+.btn-light:focus,.btn-check:checked+.btn-light:focus,.btn-light.active:focus,.btn-light:active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light.disabled,.btn-light:disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:active+.btn-dark,.btn-check:checked+.btn-dark,.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:active+.btn-dark:focus,.btn-check:checked+.btn-dark:focus,.btn-dark.active:focus,.btn-dark:active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-primary{color:#0d6efd;border-color:#0d6efd}.btn-outline-primary:hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-check:active+.btn-outline-primary,.btn-check:checked+.btn-outline-primary,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show,.btn-outline-primary:active{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:active+.btn-outline-primary:focus,.btn-check:checked+.btn-outline-primary:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus,.btn-outline-primary:active:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#0d6efd;background-color:transparent}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-check:active+.btn-outline-secondary,.btn-check:checked+.btn-outline-secondary,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show,.btn-outline-secondary:active{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:active+.btn-outline-secondary:focus,.btn-check:checked+.btn-outline-secondary:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus,.btn-outline-secondary:active:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-success{color:#198754;border-color:#198754}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:active+.btn-outline-success,.btn-check:checked+.btn-outline-success,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show,.btn-outline-success:active{color:#fff;background-color:#198754;border-color:#198754}.btn-check:active+.btn-outline-success:focus,.btn-check:checked+.btn-outline-success:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus,.btn-outline-success:active:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#198754;background-color:transparent}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:active+.btn-outline-info,.btn-check:checked+.btn-outline-info,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show,.btn-outline-info:active{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:active+.btn-outline-info:focus,.btn-check:checked+.btn-outline-info:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus,.btn-outline-info:active:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#0dcaf0;background-color:transparent}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:active+.btn-outline-warning,.btn-check:checked+.btn-outline-warning,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show,.btn-outline-warning:active{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:active+.btn-outline-warning:focus,.btn-check:checked+.btn-outline-warning:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus,.btn-outline-warning:active:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:active+.btn-outline-danger,.btn-check:checked+.btn-outline-danger,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show,.btn-outline-danger:active{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:active+.btn-outline-danger:focus,.btn-check:checked+.btn-outline-danger:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus,.btn-outline-danger:active:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:active+.btn-outline-light,.btn-check:checked+.btn-outline-light,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show,.btn-outline-light:active{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:active+.btn-outline-light:focus,.btn-check:checked+.btn-outline-light:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus,.btn-outline-light:active:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#212529;border-color:#212529}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:active+.btn-outline-dark,.btn-check:checked+.btn-outline-dark,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show,.btn-outline-dark:active{color:#fff;background-color:#212529;border-color:#212529}.btn-check:active+.btn-outline-dark:focus,.btn-check:checked+.btn-outline-dark:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus,.btn-outline-dark:active:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#212529;background-color:transparent}.btn-link{font-weight:400;color:#0d6efd;text-decoration:underline}.btn-link:hover{color:#0a58ca}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropend,.dropstart,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0d6efd}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:focus,.dropdown-menu-dark .dropdown-item:hover{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#0d6efd}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#0d6efd;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:#0a58ca}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:0 0;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:0 0;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#0d6efd}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem;transition:box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.55)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.55);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.55)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.55)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.55);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.55)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.5rem;margin-bottom:-.5rem;margin-left:-.5rem;border-bottom:0}.card-header-pills{margin-right:-.5rem;margin-left:-.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#212529;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#0c63e4;background-color:#e7f1ff;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button{border-radius:0}.breadcrumb{display:flex;flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#0d6efd;text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#0a58ca;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#0a58ca;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{color:#41464b;background-color:#e2e3e5;border-color:#d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@-webkit-keyframes progress-bar-stripes{0%{background-position-x:1rem}}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#0d6efd;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);opacity:1}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast:not(.showing):not(.show){opacity:0}.toast.hide{display:none}.toast-container{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-header .btn-close{margin-right:-.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1060;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-.5rem -.5rem -.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;flex-shrink:0;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[data-popper-placement^=right],.bs-tooltip-end{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[data-popper-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[data-popper-placement^=left],.bs-tooltip-start{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@-webkit-keyframes spinner-border{to{transform:rotate(360deg)}}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1050;display:flex;flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-.5rem;margin-right:-.5rem;margin-bottom:-.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.clearfix::after{display:block;clear:both;content:""}.link-primary{color:#0d6efd}.link-primary:focus,.link-primary:hover{color:#0a58ca}.link-secondary{color:#6c757d}.link-secondary:focus,.link-secondary:hover{color:#565e64}.link-success{color:#198754}.link-success:focus,.link-success:hover{color:#146c43}.link-info{color:#0dcaf0}.link-info:focus,.link-info:hover{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:focus,.link-warning:hover{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:focus,.link-danger:hover{color:#b02a37}.link-light{color:#f8f9fa}.link-light:focus,.link-light:hover{color:#f9fafb}.link-dark{color:#212529}.link-dark:focus,.link-dark:hover{color:#1a1e21}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:calc(3 / 4 * 100%)}.ratio-16x9{--bs-aspect-ratio:calc(9 / 16 * 100%)}.ratio-21x9{--bs-aspect-ratio:calc(9 / 21 * 100%)}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:1px solid #dee2e6!important}.border-0{border:0!important}.border-top{border-top:1px solid #dee2e6!important}.border-top-0{border-top:0!important}.border-end{border-right:1px solid #dee2e6!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:1px solid #dee2e6!important}.border-start-0{border-left:0!important}.border-primary{border-color:#0d6efd!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#198754!important}.border-info{border-color:#0dcaf0!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#212529!important}.border-white{border-color:#fff!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-light{font-weight:300!important}.fw-lighter{font-weight:lighter!important}.fw-normal{font-weight:400!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{color:#0d6efd!important}.text-secondary{color:#6c757d!important}.text-success{color:#198754!important}.text-info{color:#0dcaf0!important}.text-warning{color:#ffc107!important}.text-danger{color:#dc3545!important}.text-light{color:#f8f9fa!important}.text-dark{color:#212529!important}.text-white{color:#fff!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-reset{color:inherit!important}.bg-primary{background-color:#0d6efd!important}.bg-secondary{background-color:#6c757d!important}.bg-success{background-color:#198754!important}.bg-info{background-color:#0dcaf0!important}.bg-warning{background-color:#ffc107!important}.bg-danger{background-color:#dc3545!important}.bg-light{background-color:#f8f9fa!important}.bg-dark{background-color:#212529!important}.bg-body{background-color:#fff!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:.25rem!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:.2rem!important}.rounded-2{border-radius:.25rem!important}.rounded-3{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-end{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-start{border-bottom-left-radius:.25rem!important;border-top-left-radius:.25rem!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} -/*# sourceMappingURL=bootstrap.min.css.map */ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/css/fontawesome.css b/domain-rrd/service-python/svc-pdfgenerator/src/public/css/fontawesome.css deleted file mode 100644 index dc98a1c590..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/public/css/fontawesome.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - */ -.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-bacteria:before{content:"\e059"}.fa-bacterium:before{content:"\e05a"}.fa-bahai:before{content:"\f666"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-box-tissue:before{content:"\e05b"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudflare:before{content:"\e07d"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-alt:before{content:"\f422"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dailymotion:before{content:"\e052"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-deezer:before{content:"\e077"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-disease:before{content:"\f7fa"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edge-legacy:before{content:"\e078"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-alt:before{content:"\f424"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-faucet:before{content:"\e005"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\e007"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-pay:before{content:"\e079"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guilded:before{content:"\e07e"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-holding-water:before{content:"\f4c1"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-sparkles:before{content:"\e05d"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-hands-wash:before{content:"\e05e"}.fa-handshake:before{content:"\f2b5"}.fa-handshake-alt-slash:before{content:"\e05f"}.fa-handshake-slash:before{content:"\e060"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-hdd:before{content:"\f0a0"}.fa-head-side-cough:before{content:"\e061"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-head-side-mask:before{content:"\e063"}.fa-head-side-virus:before{content:"\e064"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hive:before{content:"\e07f"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hospital-user:before{content:"\f80d"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-house-user:before{content:"\e065"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-ideal:before{content:"\e013"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-innosoft:before{content:"\e080"}.fa-instagram:before{content:"\f16d"}.fa-instagram-square:before{content:"\e055"}.fa-instalod:before{content:"\e081"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-house:before{content:"\e066"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lungs:before{content:"\f604"}.fa-lungs-virus:before{content:"\e067"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microblog:before{content:"\e01a"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mixer:before{content:"\e056"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse:before{content:"\f8cc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-octopus-deploy:before{content:"\e082"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-arrows:before{content:"\e068"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-perbyte:before{content:"\e083"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\e01e"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-plane-slash:before{content:"\e069"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pump-medical:before{content:"\e06a"}.fa-pump-soap:before{content:"\e06b"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-rust:before{content:"\e07a"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-shield-virus:before{content:"\e06c"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopify:before{content:"\e057"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sink:before{content:"\e06d"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-soap:before{content:"\e06e"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-stopwatch-20:before{content:"\e06f"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-store-alt-slash:before{content:"\e070"}.fa-store-slash:before{content:"\e071"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swift:before{content:"\f8e1"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-tiktok:before{content:"\e07b"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\e041"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-uncharted:before{content:"\e084"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\e049"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-unsplash:before{content:"\e07c"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-users-slash:before{content:"\e073"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-vest:before{content:"\e085"}.fa-vest-patches:before{content:"\e086"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-virus:before{content:"\e074"}.fa-virus-slash:before{content:"\e075"}.fa-viruses:before{content:"\e076"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-watchman-monitoring:before{content:"\e087"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wodu:before{content:"\e088"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.fab,.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/bitter-bold-webfont.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/bitter-bold-webfont.ttf deleted file mode 100644 index 1ee813f9aa..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/bitter-bold-webfont.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/bitter-regular-webfont.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/bitter-regular-webfont.ttf deleted file mode 100644 index b44c6fce2f..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/bitter-regular-webfont.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/deja-vu-sans.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/deja-vu-sans.ttf deleted file mode 100644 index e5f7eecce4..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/deja-vu-sans.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-bold-webfont.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-bold-webfont.ttf deleted file mode 100644 index 3e68bc2416..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-bold-webfont.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-bolditalic-webfont.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-bolditalic-webfont.ttf deleted file mode 100644 index 4b56351716..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-bolditalic-webfont.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-italic-webfont.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-italic-webfont.ttf deleted file mode 100644 index eedc5e4593..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-italic-webfont.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-regular-webfont.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-regular-webfont.ttf deleted file mode 100644 index 973bc2ed3a..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/notosans-regular-webfont.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-bold-webfont.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-bold-webfont.ttf deleted file mode 100644 index 02ae55e6e7..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-bold-webfont.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-bolditalic-webfont.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-bolditalic-webfont.ttf deleted file mode 100644 index b38bae9472..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-bolditalic-webfont.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-italic-webfont.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-italic-webfont.ttf deleted file mode 100644 index b513caef9b..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-italic-webfont.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-regular-webfont.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-regular-webfont.ttf deleted file mode 100644 index ac42fa1c24..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/fonts/sourcesanspro-regular-webfont.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/images/va-logo.png b/domain-rrd/service-python/svc-pdfgenerator/src/public/images/va-logo.png deleted file mode 100644 index f56368de02..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/images/va-logo.png and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/images/va-logo.svg b/domain-rrd/service-python/svc-pdfgenerator/src/public/images/va-logo.svg deleted file mode 100644 index c38b4dae07..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/public/images/va-logo.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/js/bootstrap.bundle.min.js b/domain-rrd/service-python/svc-pdfgenerator/src/public/js/bootstrap.bundle.min.js deleted file mode 100644 index 8a8cfb6582..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/public/js/bootstrap.bundle.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.0.2 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter(t=>t.matches(e)),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]}},e=t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t},i=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i="#"+i.split("#")[1]),e=i&&"#"!==i?i.trim():null}return e},n=t=>{const e=i(t);return e&&document.querySelector(e)?e:null},s=t=>{const e=i(t);return e?document.querySelector(e):null},o=t=>{t.dispatchEvent(new Event("transitionend"))},r=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),a=e=>r(e)?e.jquery?e[0]:e:"string"==typeof e&&e.length>0?t.findOne(e):null,l=(t,e,i)=>{Object.keys(i).forEach(n=>{const s=i[n],o=e[n],a=o&&r(o)?"element":null==(l=o)?""+l:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)})},c=t=>!(!r(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),h=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),d=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?d(t.parentNode):null},u=()=>{},f=t=>t.offsetHeight,p=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},m=[],g=()=>"rtl"===document.documentElement.dir,_=t=>{var e;e=()=>{const e=p();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(m.length||document.addEventListener("DOMContentLoaded",()=>{m.forEach(t=>t())}),m.push(e)):e()},b=t=>{"function"==typeof t&&t()},v=(t,e,i=!0)=>{if(!i)return void b(t);const n=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let s=!1;const r=({target:i})=>{i===e&&(s=!0,e.removeEventListener("transitionend",r),b(t))};e.addEventListener("transitionend",r),setTimeout(()=>{s||o(e)},n)},y=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},w=/[^.]*(?=\..*)\.|.*/,E=/\..*/,A=/::\d+$/,T={};let O=1;const C={mouseenter:"mouseover",mouseleave:"mouseout"},k=/^(mouseenter|mouseleave)/i,L=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function x(t,e){return e&&`${e}::${O++}`||t.uidEvent||O++}function D(t){const e=x(t);return t.uidEvent=e,T[e]=T[e]||{},T[e]}function S(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=I(e,i,n),l=D(t),c=l[a]||(l[a]={}),h=S(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=x(r,e.replace(w,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&P.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&P.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function j(t,e,i,n,s){const o=S(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function M(t){return t=t.replace(E,""),C[t]||t}const P={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=I(e,i,n),a=r!==e,l=D(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void j(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach(i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach(o=>{if(o.includes(n)){const n=s[o];j(t,e,i,n.originalHandler,n.delegationSelector)}})}(t,l,i,e.slice(1))});const h=l[r]||{};Object.keys(h).forEach(i=>{const n=i.replace(A,"");if(!a||e.includes(n)){const e=h[i];j(t,l,r,e.originalHandler,e.delegationSelector)}})},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=p(),s=M(e),o=e!==s,r=L.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach(t=>{Object.defineProperty(d,t,{get:()=>i[t]})}),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},H=new Map;var R={set(t,e,i){H.has(t)||H.set(t,new Map);const n=H.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>H.has(t)&&H.get(t).get(e)||null,remove(t,e){if(!H.has(t))return;const i=H.get(t);i.delete(e),0===i.size&&H.delete(t)}};class B{constructor(t){(t=a(t))&&(this._element=t,R.set(this._element,this.constructor.DATA_KEY,this))}dispose(){R.remove(this._element,this.constructor.DATA_KEY),P.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach(t=>{this[t]=null})}_queueCallback(t,e,i=!0){v(t,e,i)}static getInstance(t){return R.get(t,this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.0.2"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return"bs."+this.NAME}static get EVENT_KEY(){return"."+this.DATA_KEY}}class W extends B{static get NAME(){return"alert"}close(t){const e=t?this._getRootElement(t):this._element,i=this._triggerCloseEvent(e);null===i||i.defaultPrevented||this._removeElement(e)}_getRootElement(t){return s(t)||t.closest(".alert")}_triggerCloseEvent(t){return P.trigger(t,"close.bs.alert")}_removeElement(t){t.classList.remove("show");const e=t.classList.contains("fade");this._queueCallback(()=>this._destroyElement(t),t,e)}_destroyElement(t){t.remove(),P.trigger(t,"closed.bs.alert")}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);"close"===t&&e[t](this)}))}static handleDismiss(t){return function(e){e&&e.preventDefault(),t.close(this)}}}P.on(document,"click.bs.alert.data-api",'[data-bs-dismiss="alert"]',W.handleDismiss(new W)),_(W);class q extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=q.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function z(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function $(t){return t.replace(/[A-Z]/g,t=>"-"+t.toLowerCase())}P.on(document,"click.bs.button.data-api",'[data-bs-toggle="button"]',t=>{t.preventDefault();const e=t.target.closest('[data-bs-toggle="button"]');q.getOrCreateInstance(e).toggle()}),_(q);const U={setDataAttribute(t,e,i){t.setAttribute("data-bs-"+$(e),i)},removeDataAttribute(t,e){t.removeAttribute("data-bs-"+$(e))},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter(t=>t.startsWith("bs")).forEach(i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=z(t.dataset[i])}),e},getDataAttribute:(t,e)=>z(t.getAttribute("data-bs-"+$(e))),offset(t){const e=t.getBoundingClientRect();return{top:e.top+document.body.scrollTop,left:e.left+document.body.scrollLeft}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},F={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},V={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},K="next",X="prev",Y="left",Q="right",G={ArrowLeft:Q,ArrowRight:Y};class Z extends B{constructor(e,i){super(e),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(i),this._indicatorsElement=t.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return F}static get NAME(){return"carousel"}next(){this._slide(K)}nextWhenVisible(){!document.hidden&&c(this._element)&&this.next()}prev(){this._slide(X)}pause(e){e||(this._isPaused=!0),t.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(o(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(e){this._activeElement=t.findOne(".active.carousel-item",this._element);const i=this._getItemIndex(this._activeElement);if(e>this._items.length-1||e<0)return;if(this._isSliding)return void P.one(this._element,"slid.bs.carousel",()=>this.to(e));if(i===e)return this.pause(),void this.cycle();const n=e>i?K:X;this._slide(n,this._items[e])}_getConfig(t){return t={...F,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},l("carousel",t,V),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?Q:Y)}_addEventListeners(){this._config.keyboard&&P.on(this._element,"keydown.bs.carousel",t=>this._keydown(t)),"hover"===this._config.pause&&(P.on(this._element,"mouseenter.bs.carousel",t=>this.pause(t)),P.on(this._element,"mouseleave.bs.carousel",t=>this.cycle(t))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const e=t=>{!this._pointerEvent||"pen"!==t.pointerType&&"touch"!==t.pointerType?this._pointerEvent||(this.touchStartX=t.touches[0].clientX):this.touchStartX=t.clientX},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=t=>{!this._pointerEvent||"pen"!==t.pointerType&&"touch"!==t.pointerType||(this.touchDeltaX=t.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout(t=>this.cycle(t),500+this._config.interval))};t.find(".carousel-item img",this._element).forEach(t=>{P.on(t,"dragstart.bs.carousel",t=>t.preventDefault())}),this._pointerEvent?(P.on(this._element,"pointerdown.bs.carousel",t=>e(t)),P.on(this._element,"pointerup.bs.carousel",t=>n(t)),this._element.classList.add("pointer-event")):(P.on(this._element,"touchstart.bs.carousel",t=>e(t)),P.on(this._element,"touchmove.bs.carousel",t=>i(t)),P.on(this._element,"touchend.bs.carousel",t=>n(t)))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=G[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(e){return this._items=e&&e.parentNode?t.find(".carousel-item",e.parentNode):[],this._items.indexOf(e)}_getItemByOrder(t,e){const i=t===K;return y(this._items,e,i,this._config.wrap)}_triggerSlideEvent(e,i){const n=this._getItemIndex(e),s=this._getItemIndex(t.findOne(".active.carousel-item",this._element));return P.trigger(this._element,"slide.bs.carousel",{relatedTarget:e,direction:i,from:s,to:n})}_setActiveIndicatorElement(e){if(this._indicatorsElement){const i=t.findOne(".active",this._indicatorsElement);i.classList.remove("active"),i.removeAttribute("aria-current");const n=t.find("[data-bs-target]",this._indicatorsElement);for(let t=0;t{P.trigger(this._element,"slid.bs.carousel",{relatedTarget:r,direction:u,from:o,to:a})};if(this._element.classList.contains("slide")){r.classList.add(d),f(r),s.classList.add(h),r.classList.add(h);const t=()=>{r.classList.remove(h,d),r.classList.add("active"),s.classList.remove("active",d,h),this._isSliding=!1,setTimeout(p,0)};this._queueCallback(t,s,!0)}else s.classList.remove("active"),r.classList.add("active"),this._isSliding=!1,p();l&&this.cycle()}_directionToOrder(t){return[Q,Y].includes(t)?g()?t===Y?X:K:t===Y?K:X:t}_orderToDirection(t){return[K,X].includes(t)?g()?t===X?Y:Q:t===X?Q:Y:t}static carouselInterface(t,e){const i=Z.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){Z.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=s(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},n=this.getAttribute("data-bs-slide-to");n&&(i.interval=!1),Z.carouselInterface(e,i),n&&Z.getInstance(e).to(n),t.preventDefault()}}P.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",Z.dataApiClickHandler),P.on(window,"load.bs.carousel.data-api",()=>{const e=t.find('[data-bs-ride="carousel"]');for(let t=0,i=e.length;tt===this._element);null!==o&&r.length&&(this._selector=o,this._triggerArray.push(i))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}static get Default(){return J}static get NAME(){return"collapse"}toggle(){this._element.classList.contains("show")?this.hide():this.show()}show(){if(this._isTransitioning||this._element.classList.contains("show"))return;let e,i;this._parent&&(e=t.find(".show, .collapsing",this._parent).filter(t=>"string"==typeof this._config.parent?t.getAttribute("data-bs-parent")===this._config.parent:t.classList.contains("collapse")),0===e.length&&(e=null));const n=t.findOne(this._selector);if(e){const t=e.find(t=>n!==t);if(i=t?et.getInstance(t):null,i&&i._isTransitioning)return}if(P.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e&&e.forEach(t=>{n!==t&&et.collapseInterface(t,"hide"),i||R.set(t,"bs.collapse",null)});const s=this._getDimension();this._element.classList.remove("collapse"),this._element.classList.add("collapsing"),this._element.style[s]=0,this._triggerArray.length&&this._triggerArray.forEach(t=>{t.classList.remove("collapsed"),t.setAttribute("aria-expanded",!0)}),this.setTransitioning(!0);const o="scroll"+(s[0].toUpperCase()+s.slice(1));this._queueCallback(()=>{this._element.classList.remove("collapsing"),this._element.classList.add("collapse","show"),this._element.style[s]="",this.setTransitioning(!1),P.trigger(this._element,"shown.bs.collapse")},this._element,!0),this._element.style[s]=this._element[o]+"px"}hide(){if(this._isTransitioning||!this._element.classList.contains("show"))return;if(P.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=this._element.getBoundingClientRect()[t]+"px",f(this._element),this._element.classList.add("collapsing"),this._element.classList.remove("collapse","show");const e=this._triggerArray.length;if(e>0)for(let t=0;t{this.setTransitioning(!1),this._element.classList.remove("collapsing"),this._element.classList.add("collapse"),P.trigger(this._element,"hidden.bs.collapse")},this._element,!0)}setTransitioning(t){this._isTransitioning=t}_getConfig(t){return(t={...J,...t}).toggle=Boolean(t.toggle),l("collapse",t,tt),t}_getDimension(){return this._element.classList.contains("width")?"width":"height"}_getParent(){let{parent:e}=this._config;e=a(e);const i=`[data-bs-toggle="collapse"][data-bs-parent="${e}"]`;return t.find(i,e).forEach(t=>{const e=s(t);this._addAriaAndCollapsedClass(e,[t])}),e}_addAriaAndCollapsedClass(t,e){if(!t||!e.length)return;const i=t.classList.contains("show");e.forEach(t=>{i?t.classList.remove("collapsed"):t.classList.add("collapsed"),t.setAttribute("aria-expanded",i)})}static collapseInterface(t,e){let i=et.getInstance(t);const n={...J,...U.getDataAttributes(t),..."object"==typeof e&&e?e:{}};if(!i&&n.toggle&&"string"==typeof e&&/show|hide/.test(e)&&(n.toggle=!1),i||(i=new et(t,n)),"string"==typeof e){if(void 0===i[e])throw new TypeError(`No method named "${e}"`);i[e]()}}static jQueryInterface(t){return this.each((function(){et.collapseInterface(this,t)}))}}P.on(document,"click.bs.collapse.data-api",'[data-bs-toggle="collapse"]',(function(e){("A"===e.target.tagName||e.delegateTarget&&"A"===e.delegateTarget.tagName)&&e.preventDefault();const i=U.getDataAttributes(this),s=n(this);t.find(s).forEach(t=>{const e=et.getInstance(t);let n;e?(null===e._parent&&"string"==typeof i.parent&&(e._config.parent=i.parent,e._parent=e._getParent()),n="toggle"):n=i,et.collapseInterface(t,n)})})),_(et);var it="top",nt="bottom",st="right",ot="left",rt=[it,nt,st,ot],at=rt.reduce((function(t,e){return t.concat([e+"-start",e+"-end"])}),[]),lt=[].concat(rt,["auto"]).reduce((function(t,e){return t.concat([e,e+"-start",e+"-end"])}),[]),ct=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function ht(t){return t?(t.nodeName||"").toLowerCase():null}function dt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function ut(t){return t instanceof dt(t).Element||t instanceof Element}function ft(t){return t instanceof dt(t).HTMLElement||t instanceof HTMLElement}function pt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof dt(t).ShadowRoot||t instanceof ShadowRoot)}var mt={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];ft(s)&&ht(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});ft(n)&&ht(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function gt(t){return t.split("-")[0]}function _t(t){var e=t.getBoundingClientRect();return{width:e.width,height:e.height,top:e.top,right:e.right,bottom:e.bottom,left:e.left,x:e.left,y:e.top}}function bt(t){var e=_t(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function vt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&pt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function yt(t){return dt(t).getComputedStyle(t)}function wt(t){return["table","td","th"].indexOf(ht(t))>=0}function Et(t){return((ut(t)?t.ownerDocument:t.document)||window.document).documentElement}function At(t){return"html"===ht(t)?t:t.assignedSlot||t.parentNode||(pt(t)?t.host:null)||Et(t)}function Tt(t){return ft(t)&&"fixed"!==yt(t).position?t.offsetParent:null}function Ot(t){for(var e=dt(t),i=Tt(t);i&&wt(i)&&"static"===yt(i).position;)i=Tt(i);return i&&("html"===ht(i)||"body"===ht(i)&&"static"===yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&ft(t)&&"fixed"===yt(t).position)return null;for(var i=At(t);ft(i)&&["html","body"].indexOf(ht(i))<0;){var n=yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ct(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var kt=Math.max,Lt=Math.min,xt=Math.round;function Dt(t,e,i){return kt(t,Lt(e,i))}function St(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function It(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}var Nt={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=gt(i.placement),l=Ct(a),c=[ot,st].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return St("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:It(t,rt))}(s.padding,i),d=bt(o),u="y"===l?it:ot,f="y"===l?nt:st,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=Ot(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=Dt(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&vt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]},jt={top:"auto",right:"auto",bottom:"auto",left:"auto"};function Mt(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.offsets,r=t.position,a=t.gpuAcceleration,l=t.adaptive,c=t.roundOffsets,h=!0===c?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:xt(xt(e*n)/n)||0,y:xt(xt(i*n)/n)||0}}(o):"function"==typeof c?c(o):o,d=h.x,u=void 0===d?0:d,f=h.y,p=void 0===f?0:f,m=o.hasOwnProperty("x"),g=o.hasOwnProperty("y"),_=ot,b=it,v=window;if(l){var y=Ot(i),w="clientHeight",E="clientWidth";y===dt(i)&&"static"!==yt(y=Et(i)).position&&(w="scrollHeight",E="scrollWidth"),y=y,s===it&&(b=nt,p-=y[w]-n.height,p*=a?1:-1),s===ot&&(_=st,u-=y[E]-n.width,u*=a?1:-1)}var A,T=Object.assign({position:r},l&&jt);return a?Object.assign({},T,((A={})[b]=g?"0":"",A[_]=m?"0":"",A.transform=(v.devicePixelRatio||1)<2?"translate("+u+"px, "+p+"px)":"translate3d("+u+"px, "+p+"px, 0)",A)):Object.assign({},T,((e={})[b]=g?p+"px":"",e[_]=m?u+"px":"",e.transform="",e))}var Pt={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:gt(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,Mt(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,Mt(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}},Ht={passive:!0},Rt={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=dt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,Ht)})),a&&l.addEventListener("resize",i.update,Ht),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,Ht)})),a&&l.removeEventListener("resize",i.update,Ht)}},data:{}},Bt={left:"right",right:"left",bottom:"top",top:"bottom"};function Wt(t){return t.replace(/left|right|bottom|top/g,(function(t){return Bt[t]}))}var qt={start:"end",end:"start"};function zt(t){return t.replace(/start|end/g,(function(t){return qt[t]}))}function $t(t){var e=dt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ut(t){return _t(Et(t)).left+$t(t).scrollLeft}function Ft(t){var e=yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Vt(t,e){var i;void 0===e&&(e=[]);var n=function t(e){return["html","body","#document"].indexOf(ht(e))>=0?e.ownerDocument.body:ft(e)&&Ft(e)?e:t(At(e))}(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=dt(n),r=s?[o].concat(o.visualViewport||[],Ft(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Vt(At(r)))}function Kt(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Xt(t,e){return"viewport"===e?Kt(function(t){var e=dt(t),i=Et(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+Ut(t),y:a}}(t)):ft(e)?function(t){var e=_t(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Kt(function(t){var e,i=Et(t),n=$t(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=kt(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=kt(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ut(t),l=-n.scrollTop;return"rtl"===yt(s||i).direction&&(a+=kt(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Et(t)))}function Yt(t){return t.split("-")[1]}function Qt(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?gt(s):null,r=s?Yt(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case it:e={x:a,y:i.y-n.height};break;case nt:e={x:a,y:i.y+i.height};break;case st:e={x:i.x+i.width,y:l};break;case ot:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ct(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case"start":e[c]=e[c]-(i[h]/2-n[h]/2);break;case"end":e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function Gt(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?"clippingParents":o,a=i.rootBoundary,l=void 0===a?"viewport":a,c=i.elementContext,h=void 0===c?"popper":c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=St("number"!=typeof p?p:It(p,rt)),g="popper"===h?"reference":"popper",_=t.elements.reference,b=t.rects.popper,v=t.elements[u?g:h],y=function(t,e,i){var n="clippingParents"===e?function(t){var e=Vt(At(t)),i=["absolute","fixed"].indexOf(yt(t).position)>=0&&ft(t)?Ot(t):t;return ut(i)?e.filter((function(t){return ut(t)&&vt(t,i)&&"body"!==ht(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Xt(t,i);return e.top=kt(n.top,e.top),e.right=Lt(n.right,e.right),e.bottom=Lt(n.bottom,e.bottom),e.left=kt(n.left,e.left),e}),Xt(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}(ut(v)?v:v.contextElement||Et(t.elements.popper),r,l),w=_t(_),E=Qt({reference:w,element:b,strategy:"absolute",placement:s}),A=Kt(Object.assign({},b,E)),T="popper"===h?A:w,O={top:y.top-T.top+m.top,bottom:T.bottom-y.bottom+m.bottom,left:y.left-T.left+m.left,right:T.right-y.right+m.right},C=t.modifiersData.offset;if("popper"===h&&C){var k=C[s];Object.keys(O).forEach((function(t){var e=[st,nt].indexOf(t)>=0?1:-1,i=[it,nt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function Zt(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?lt:l,h=Yt(n),d=h?a?at:at.filter((function(t){return Yt(t)===h})):rt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=Gt(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[gt(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}var Jt={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=gt(g),b=l||(_!==g&&p?function(t){if("auto"===gt(t))return[];var e=Wt(t);return[zt(t),e,zt(e)]}(g):[Wt(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat("auto"===gt(i)?Zt(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=Gt(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),I=x?L?st:ot:L?nt:it;y[D]>w[D]&&(I=Wt(I));var N=Wt(I),j=[];if(o&&j.push(S[k]<=0),a&&j.push(S[I]<=0,S[N]<=0),j.every((function(t){return t}))){T=C,A=!1;break}E.set(C,j)}if(A)for(var M=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},P=p?3:1;P>0&&"break"!==M(P);P--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function te(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ee(t){return[it,st,nt,ot].some((function(e){return t[e]>=0}))}var ie={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=Gt(e,{elementContext:"reference"}),a=Gt(e,{altBoundary:!0}),l=te(r,n),c=te(a,s,o),h=ee(l),d=ee(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},ne={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=gt(t),s=[ot,it].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[ot,st].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},se={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Qt({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},oe={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=Gt(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=gt(e.placement),b=Yt(e.placement),v=!b,y=Ct(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?it:ot,L="y"===y?nt:st,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],I=E[y]-g[L],N=f?-T[x]/2:0,j="start"===b?A[x]:T[x],M="start"===b?-T[x]:-A[x],P=e.elements.arrow,H=f&&P?bt(P):{width:0,height:0},R=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},B=R[k],W=R[L],q=Dt(0,A[x],H[x]),z=v?A[x]/2-N-q-B-O:j-q-B-O,$=v?-A[x]/2+N+q+W+O:M+q+W+O,U=e.elements.arrow&&Ot(e.elements.arrow),F=U?"y"===y?U.clientTop||0:U.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-F,X=E[y]+$-V;if(o){var Y=Dt(f?Lt(S,K):S,D,f?kt(I,X):I);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?it:ot,G="x"===y?nt:st,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=Dt(f?Lt(J,K):J,Z,f?kt(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function re(t,e,i){void 0===i&&(i=!1);var n,s,o=Et(e),r=_t(t),a=ft(e),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(a||!a&&!i)&&(("body"!==ht(e)||Ft(o))&&(l=(n=e)!==dt(n)&&ft(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:$t(n)),ft(e)?((c=_t(e)).x+=e.clientLeft,c.y+=e.clientTop):o&&(c.x=Ut(o))),{x:r.left+l.scrollLeft-c.x,y:r.top+l.scrollTop-c.y,width:r.width,height:r.height}}var ae={placement:"bottom",modifiers:[],strategy:"absolute"};function le(){for(var t=arguments.length,e=new Array(t),i=0;i"applyStyles"===t.name&&!1===t.enabled);this._popper=ue(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}"ontouchstart"in document.documentElement&&!t.closest(".navbar-nav")&&[].concat(...document.body.children).forEach(t=>P.on(t,"mouseover",u)),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.toggle("show"),this._element.classList.toggle("show"),P.trigger(this._element,"shown.bs.dropdown",e)}}hide(){if(h(this._element)||!this._menu.classList.contains("show"))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_addEventListeners(){P.on(this._element,"click.bs.dropdown",t=>{t.preventDefault(),this.toggle()})}_completeHide(t){P.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>P.off(t,"mouseover",u)),this._popper&&this._popper.destroy(),this._menu.classList.remove("show"),this._element.classList.remove("show"),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),P.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},l("dropdown",t,this.constructor.DefaultType),"object"==typeof t.reference&&!r(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError("dropdown".toUpperCase()+': Option "reference" provided type "object" without a required "getBoundingClientRect" method.');return t}_getMenuElement(){return t.next(this._element,".dropdown-menu")[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ve;if(t.classList.contains("dropstart"))return ye;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ge:me:e?be:_e}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:e,target:i}){const n=t.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(c);n.length&&y(n,i,"ArrowDown"===e,!n.includes(i)).focus()}static dropdownInterface(t,e){const i=Ae.getOrCreateInstance(t,e);if("string"==typeof e){if(void 0===i[e])throw new TypeError(`No method named "${e}"`);i[e]()}}static jQueryInterface(t){return this.each((function(){Ae.dropdownInterface(this,t)}))}static clearMenus(e){if(e&&(2===e.button||"keyup"===e.type&&"Tab"!==e.key))return;const i=t.find('[data-bs-toggle="dropdown"]');for(let t=0,n=i.length;tthis.matches('[data-bs-toggle="dropdown"]')?this:t.prev(this,'[data-bs-toggle="dropdown"]')[0];return"Escape"===e.key?(n().focus(),void Ae.clearMenus()):"ArrowUp"===e.key||"ArrowDown"===e.key?(i||n().click(),void Ae.getInstance(n())._selectMenuItem(e)):void(i&&"Space"!==e.key||Ae.clearMenus())}}P.on(document,"keydown.bs.dropdown.data-api",'[data-bs-toggle="dropdown"]',Ae.dataApiKeydownHandler),P.on(document,"keydown.bs.dropdown.data-api",".dropdown-menu",Ae.dataApiKeydownHandler),P.on(document,"click.bs.dropdown.data-api",Ae.clearMenus),P.on(document,"keyup.bs.dropdown.data-api",Ae.clearMenus),P.on(document,"click.bs.dropdown.data-api",'[data-bs-toggle="dropdown"]',(function(t){t.preventDefault(),Ae.dropdownInterface(this)})),_(Ae);class Te{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,"paddingRight",e=>e+t),this._setElementAttributes(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top","paddingRight",e=>e+t),this._setElementAttributes(".sticky-top","marginRight",e=>e-t)}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=i(Number.parseFloat(s))+"px"})}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top","paddingRight"),this._resetElementAttributes(".sticky-top","marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)})}_applyManipulationCallback(e,i){r(e)?i(e):t.find(e,this._element).forEach(i)}isOverflowing(){return this.getWidth()>0}}const Oe={isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},Ce={isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"};class ke{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&f(this._getElement()),this._getElement().classList.add("show"),this._emulateAnimation(()=>{b(t)})):b(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove("show"),this._emulateAnimation(()=>{this.dispose(),b(t)})):b(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className="modal-backdrop",this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...Oe,..."object"==typeof t?t:{}}).rootElement=a(t.rootElement),l("backdrop",t,Ce),t}_append(){this._isAppended||(this._config.rootElement.appendChild(this._getElement()),P.on(this._getElement(),"mousedown.bs.backdrop",()=>{b(this._config.clickCallback)}),this._isAppended=!0)}dispose(){this._isAppended&&(P.off(this._element,"mousedown.bs.backdrop"),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){v(t,this._getElement(),this._config.isAnimated)}}const Le={backdrop:!0,keyboard:!0,focus:!0},xe={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"};class De extends B{constructor(e,i){super(e),this._config=this._getConfig(i),this._dialog=t.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new Te}static get Default(){return Le}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||P.trigger(this._element,"show.bs.modal",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add("modal-open"),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),P.on(this._element,"click.dismiss.bs.modal",'[data-bs-dismiss="modal"]',t=>this.hide(t)),P.on(this._dialog,"mousedown.dismiss.bs.modal",()=>{P.one(this._element,"mouseup.dismiss.bs.modal",t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)})}),this._showBackdrop(()=>this._showElement(t)))}hide(t){if(t&&["A","AREA"].includes(t.target.tagName)&&t.preventDefault(),!this._isShown||this._isTransitioning)return;if(P.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const e=this._isAnimated();e&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),P.off(document,"focusin.bs.modal"),this._element.classList.remove("show"),P.off(this._element,"click.dismiss.bs.modal"),P.off(this._dialog,"mousedown.dismiss.bs.modal"),this._queueCallback(()=>this._hideModal(),this._element,e)}dispose(){[window,this._dialog].forEach(t=>P.off(t,".bs.modal")),this._backdrop.dispose(),super.dispose(),P.off(document,"focusin.bs.modal")}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new ke({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_getConfig(t){return t={...Le,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},l("modal",t,xe),t}_showElement(e){const i=this._isAnimated(),n=t.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,n&&(n.scrollTop=0),i&&f(this._element),this._element.classList.add("show"),this._config.focus&&this._enforceFocus(),this._queueCallback(()=>{this._config.focus&&this._element.focus(),this._isTransitioning=!1,P.trigger(this._element,"shown.bs.modal",{relatedTarget:e})},this._dialog,i)}_enforceFocus(){P.off(document,"focusin.bs.modal"),P.on(document,"focusin.bs.modal",t=>{document===t.target||this._element===t.target||this._element.contains(t.target)||this._element.focus()})}_setEscapeEvent(){this._isShown?P.on(this._element,"keydown.dismiss.bs.modal",t=>{this._config.keyboard&&"Escape"===t.key?(t.preventDefault(),this.hide()):this._config.keyboard||"Escape"!==t.key||this._triggerBackdropTransition()}):P.off(this._element,"keydown.dismiss.bs.modal")}_setResizeEvent(){this._isShown?P.on(window,"resize.bs.modal",()=>this._adjustDialog()):P.off(window,"resize.bs.modal")}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide(()=>{document.body.classList.remove("modal-open"),this._resetAdjustments(),this._scrollBar.reset(),P.trigger(this._element,"hidden.bs.modal")})}_showBackdrop(t){P.on(this._element,"click.dismiss.bs.modal",t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())}),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(P.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains("modal-static")||(n||(i.overflowY="hidden"),t.add("modal-static"),this._queueCallback(()=>{t.remove("modal-static"),n||this._queueCallback(()=>{i.overflowY=""},this._dialog)},this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!g()||i&&!t&&g())&&(this._element.style.paddingLeft=e+"px"),(i&&!t&&!g()||!i&&t&&g())&&(this._element.style.paddingRight=e+"px")}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=De.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}P.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=s(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),P.one(e,"show.bs.modal",t=>{t.defaultPrevented||P.one(e,"hidden.bs.modal",()=>{c(this)&&this.focus()})}),De.getOrCreateInstance(e).toggle(this)})),_(De);const Se={backdrop:!0,keyboard:!0,scroll:!1},Ie={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"};class Ne extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._addEventListeners()}static get NAME(){return"offcanvas"}static get Default(){return Se}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||P.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||((new Te).hide(),this._enforceFocusOnElement(this._element)),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add("show"),this._queueCallback(()=>{P.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})},this._element,!0))}hide(){this._isShown&&(P.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(P.off(document,"focusin.bs.offcanvas"),this._element.blur(),this._isShown=!1,this._element.classList.remove("show"),this._backdrop.hide(),this._queueCallback(()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new Te).reset(),P.trigger(this._element,"hidden.bs.offcanvas")},this._element,!0)))}dispose(){this._backdrop.dispose(),super.dispose(),P.off(document,"focusin.bs.offcanvas")}_getConfig(t){return t={...Se,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},l("offcanvas",t,Ie),t}_initializeBackDrop(){return new ke({isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_enforceFocusOnElement(t){P.off(document,"focusin.bs.offcanvas"),P.on(document,"focusin.bs.offcanvas",e=>{document===e.target||t===e.target||t.contains(e.target)||t.focus()}),t.focus()}_addEventListeners(){P.on(this._element,"click.dismiss.bs.offcanvas",'[data-bs-dismiss="offcanvas"]',()=>this.hide()),P.on(this._element,"keydown.dismiss.bs.offcanvas",t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()})}static jQueryInterface(t){return this.each((function(){const e=Ne.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}P.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(e){const i=s(this);if(["A","AREA"].includes(this.tagName)&&e.preventDefault(),h(this))return;P.one(i,"hidden.bs.offcanvas",()=>{c(this)&&this.focus()});const n=t.findOne(".offcanvas.show");n&&n!==i&&Ne.getInstance(n).hide(),Ne.getOrCreateInstance(i).toggle(this)})),P.on(window,"load.bs.offcanvas.data-api",()=>t.find(".offcanvas.show").forEach(t=>Ne.getOrCreateInstance(t).show())),_(Ne);const je=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Me=/^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/i,Pe=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,He=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!je.has(i)||Boolean(Me.test(t.nodeValue)||Pe.test(t.nodeValue));const n=e.filter(t=>t instanceof RegExp);for(let t=0,e=n.length;t{He(t,a)||i.removeAttribute(t.nodeName)})}return n.body.innerHTML}const Be=new RegExp("(^|\\s)bs-tooltip\\S+","g"),We=new Set(["sanitize","allowList","sanitizeFn"]),qe={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},ze={AUTO:"auto",TOP:"top",RIGHT:g()?"left":"right",BOTTOM:"bottom",LEFT:g()?"right":"left"},$e={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ue={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"};class Fe extends B{constructor(t,e){if(void 0===fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return $e}static get NAME(){return"tooltip"}static get Event(){return Ue}static get DefaultType(){return qe}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains("show"))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),P.off(this._element.closest(".modal"),"hide.bs.modal",this._hideModalHandler),this.tip&&this.tip.remove(),this._popper&&this._popper.destroy(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=P.trigger(this._element,this.constructor.Event.SHOW),i=d(this._element),n=null===i?this._element.ownerDocument.documentElement.contains(this._element):i.contains(this._element);if(t.defaultPrevented||!n)return;const s=this.getTipElement(),o=e(this.constructor.NAME);s.setAttribute("id",o),this._element.setAttribute("aria-describedby",o),this.setContent(),this._config.animation&&s.classList.add("fade");const r="function"==typeof this._config.placement?this._config.placement.call(this,s,this._element):this._config.placement,a=this._getAttachment(r);this._addAttachmentClass(a);const{container:l}=this._config;R.set(s,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(l.appendChild(s),P.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=ue(this._element,s,this._getPopperConfig(a)),s.classList.add("show");const c="function"==typeof this._config.customClass?this._config.customClass():this._config.customClass;c&&s.classList.add(...c.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>{P.on(t,"mouseover",u)});const h=this.tip.classList.contains("fade");this._queueCallback(()=>{const t=this._hoverState;this._hoverState=null,P.trigger(this._element,this.constructor.Event.SHOWN),"out"===t&&this._leave(null,this)},this.tip,h)}hide(){if(!this._popper)return;const t=this.getTipElement();if(P.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove("show"),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>P.off(t,"mouseover",u)),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains("fade");this._queueCallback(()=>{this._isWithActiveTrigger()||("show"!==this._hoverState&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),P.trigger(this._element,this.constructor.Event.HIDDEN),this._popper&&(this._popper.destroy(),this._popper=null))},this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");return t.innerHTML=this._config.template,this.tip=t.children[0],this.tip}setContent(){const e=this.getTipElement();this.setElementContent(t.findOne(".tooltip-inner",e),this.getTitle()),e.classList.remove("fade","show")}setElementContent(t,e){if(null!==t)return r(e)?(e=a(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.appendChild(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Re(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){let t=this._element.getAttribute("data-bs-original-title");return t||(t="function"==typeof this._config.title?this._config.title.call(this._element):this._config.title),t}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){const i=this.constructor.DATA_KEY;return(e=e||R.get(t.delegateTarget,i))||(e=new this.constructor(t.delegateTarget,this._getDelegateConfig()),R.set(t.delegateTarget,i,e)),e}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add("bs-tooltip-"+this.updateAttachment(t))}_getAttachment(t){return ze[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach(t=>{if("click"===t)P.on(this._element,this.constructor.Event.CLICK,this._config.selector,t=>this.toggle(t));else if("manual"!==t){const e="hover"===t?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i="hover"===t?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;P.on(this._element,e,this._config.selector,t=>this._enter(t)),P.on(this._element,i,this._config.selector,t=>this._leave(t))}}),this._hideModalHandler=()=>{this._element&&this.hide()},P.on(this._element.closest(".modal"),"hide.bs.modal",this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?"focus":"hover"]=!0),e.getTipElement().classList.contains("show")||"show"===e._hoverState?e._hoverState="show":(clearTimeout(e._timeout),e._hoverState="show",e._config.delay&&e._config.delay.show?e._timeout=setTimeout(()=>{"show"===e._hoverState&&e.show()},e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?"focus":"hover"]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState="out",e._config.delay&&e._config.delay.hide?e._timeout=setTimeout(()=>{"out"===e._hoverState&&e.hide()},e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach(t=>{We.has(t)&&delete e[t]}),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:a(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),l("tooltip",t,this.constructor.DefaultType),t.sanitize&&(t.template=Re(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};if(this._config)for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=t.getAttribute("class").match(Be);null!==e&&e.length>0&&e.map(t=>t.trim()).forEach(e=>t.classList.remove(e))}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}static jQueryInterface(t){return this.each((function(){const e=Fe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}_(Fe);const Ve=new RegExp("(^|\\s)bs-popover\\S+","g"),Ke={...Fe.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},Xe={...Fe.DefaultType,content:"(string|element|function)"},Ye={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class Qe extends Fe{static get Default(){return Ke}static get NAME(){return"popover"}static get Event(){return Ye}static get DefaultType(){return Xe}isWithContent(){return this.getTitle()||this._getContent()}getTipElement(){return this.tip||(this.tip=super.getTipElement(),this.getTitle()||t.findOne(".popover-header",this.tip).remove(),this._getContent()||t.findOne(".popover-body",this.tip).remove()),this.tip}setContent(){const e=this.getTipElement();this.setElementContent(t.findOne(".popover-header",e),this.getTitle());let i=this._getContent();"function"==typeof i&&(i=i.call(this._element)),this.setElementContent(t.findOne(".popover-body",e),i),e.classList.remove("fade","show")}_addAttachmentClass(t){this.getTipElement().classList.add("bs-popover-"+this.updateAttachment(t))}_getContent(){return this._element.getAttribute("data-bs-content")||this._config.content}_cleanTipClass(){const t=this.getTipElement(),e=t.getAttribute("class").match(Ve);null!==e&&e.length>0&&e.map(t=>t.trim()).forEach(e=>t.classList.remove(e))}static jQueryInterface(t){return this.each((function(){const e=Qe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}_(Qe);const Ge={offset:10,method:"auto",target:""},Ze={offset:"number",method:"string",target:"(string|element)"};class Je extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._selector=`${this._config.target} .nav-link, ${this._config.target} .list-group-item, ${this._config.target} .dropdown-item`,this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,P.on(this._scrollElement,"scroll.bs.scrollspy",()=>this._process()),this.refresh(),this._process()}static get Default(){return Ge}static get NAME(){return"scrollspy"}refresh(){const e=this._scrollElement===this._scrollElement.window?"offset":"position",i="auto"===this._config.method?e:this._config.method,s="position"===i?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),t.find(this._selector).map(e=>{const o=n(e),r=o?t.findOne(o):null;if(r){const t=r.getBoundingClientRect();if(t.width||t.height)return[U[i](r).top+s,o]}return null}).filter(t=>t).sort((t,e)=>t[0]-e[0]).forEach(t=>{this._offsets.push(t[0]),this._targets.push(t[1])})}dispose(){P.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){if("string"!=typeof(t={...Ge,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target&&r(t.target)){let{id:i}=t.target;i||(i=e("scrollspy"),t.target.id=i),t.target="#"+i}return l("scrollspy",t,Ze),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${t}[data-bs-target="${e}"],${t}[href="${e}"]`),n=t.findOne(i.join(","));n.classList.contains("dropdown-item")?(t.findOne(".dropdown-toggle",n.closest(".dropdown")).classList.add("active"),n.classList.add("active")):(n.classList.add("active"),t.parents(n,".nav, .list-group").forEach(e=>{t.prev(e,".nav-link, .list-group-item").forEach(t=>t.classList.add("active")),t.prev(e,".nav-item").forEach(e=>{t.children(e,".nav-link").forEach(t=>t.classList.add("active"))})})),P.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:e})}_clear(){t.find(this._selector).filter(t=>t.classList.contains("active")).forEach(t=>t.classList.remove("active"))}static jQueryInterface(t){return this.each((function(){const e=Je.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}P.on(window,"load.bs.scrollspy.data-api",()=>{t.find('[data-bs-spy="scroll"]').forEach(t=>new Je(t))}),_(Je);class ti extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains("active"))return;let e;const i=s(this._element),n=this._element.closest(".nav, .list-group");if(n){const i="UL"===n.nodeName||"OL"===n.nodeName?":scope > li > .active":".active";e=t.find(i,n),e=e[e.length-1]}const o=e?P.trigger(e,"hide.bs.tab",{relatedTarget:this._element}):null;if(P.trigger(this._element,"show.bs.tab",{relatedTarget:e}).defaultPrevented||null!==o&&o.defaultPrevented)return;this._activate(this._element,n);const r=()=>{P.trigger(e,"hidden.bs.tab",{relatedTarget:this._element}),P.trigger(this._element,"shown.bs.tab",{relatedTarget:e})};i?this._activate(i,i.parentNode,r):r()}_activate(e,i,n){const s=(!i||"UL"!==i.nodeName&&"OL"!==i.nodeName?t.children(i,".active"):t.find(":scope > li > .active",i))[0],o=n&&s&&s.classList.contains("fade"),r=()=>this._transitionComplete(e,s,n);s&&o?(s.classList.remove("show"),this._queueCallback(r,e,!0)):r()}_transitionComplete(e,i,n){if(i){i.classList.remove("active");const e=t.findOne(":scope > .dropdown-menu .active",i.parentNode);e&&e.classList.remove("active"),"tab"===i.getAttribute("role")&&i.setAttribute("aria-selected",!1)}e.classList.add("active"),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!0),f(e),e.classList.contains("fade")&&e.classList.add("show");let s=e.parentNode;if(s&&"LI"===s.nodeName&&(s=s.parentNode),s&&s.classList.contains("dropdown-menu")){const i=e.closest(".dropdown");i&&t.find(".dropdown-toggle",i).forEach(t=>t.classList.add("active")),e.setAttribute("aria-expanded",!0)}n&&n()}static jQueryInterface(t){return this.each((function(){const e=ti.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}P.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),h(this)||ti.getOrCreateInstance(this).show()})),_(ti);const ei={animation:"boolean",autohide:"boolean",delay:"number"},ii={animation:!0,autohide:!0,delay:5e3};class ni extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return ei}static get Default(){return ii}static get NAME(){return"toast"}show(){P.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove("hide"),f(this._element),this._element.classList.add("showing"),this._queueCallback(()=>{this._element.classList.remove("showing"),this._element.classList.add("show"),P.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()},this._element,this._config.animation))}hide(){this._element.classList.contains("show")&&(P.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.remove("show"),this._queueCallback(()=>{this._element.classList.add("hide"),P.trigger(this._element,"hidden.bs.toast")},this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains("show")&&this._element.classList.remove("show"),super.dispose()}_getConfig(t){return t={...ii,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},l("toast",t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout(()=>{this.hide()},this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){P.on(this._element,"click.dismiss.bs.toast",'[data-bs-dismiss="toast"]',()=>this.hide()),P.on(this._element,"mouseover.bs.toast",t=>this._onInteraction(t,!0)),P.on(this._element,"mouseout.bs.toast",t=>this._onInteraction(t,!1)),P.on(this._element,"focusin.bs.toast",t=>this._onInteraction(t,!0)),P.on(this._element,"focusout.bs.toast",t=>this._onInteraction(t,!1))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ni.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return _(ni),{Alert:W,Button:q,Carousel:Z,Collapse:et,Dropdown:Ae,Modal:De,Offcanvas:Ne,Popover:Qe,ScrollSpy:Je,Tab:ti,Toast:ni,Tooltip:Fe}})); -//# sourceMappingURL=bootstrap.bundle.min.js.map diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.eot b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.eot deleted file mode 100644 index cba6c6cce8..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.eot and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.svg b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.svg deleted file mode 100644 index 36215d7945..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.svg +++ /dev/null @@ -1,3717 +0,0 @@ - - - - -Created by FontForge 20201107 at Wed Aug 4 12:25:29 2021 - By Robert Madole -Copyright (c) Font Awesome - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.ttf deleted file mode 100644 index 8d75deddae..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.woff b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.woff deleted file mode 100644 index 3375bef091..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.woff and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.woff2 b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.woff2 deleted file mode 100644 index 402f81c0bc..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-brands-400.woff2 and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.eot b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.eot deleted file mode 100644 index a4e598936b..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.eot and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.svg b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.svg deleted file mode 100644 index 4e85a37401..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.svg +++ /dev/null @@ -1,801 +0,0 @@ - - - - -Created by FontForge 20201107 at Wed Aug 4 12:25:29 2021 - By Robert Madole -Copyright (c) Font Awesome - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.ttf deleted file mode 100644 index 7157aafbac..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.woff b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.woff deleted file mode 100644 index ad077c6bec..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.woff and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.woff2 b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.woff2 deleted file mode 100644 index 56328948b3..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-regular-400.woff2 and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.eot b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.eot deleted file mode 100644 index e99417197e..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.eot and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.svg b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.svg deleted file mode 100644 index 2bbbe11038..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.svg +++ /dev/null @@ -1,5034 +0,0 @@ - - - - -Created by FontForge 20201107 at Wed Aug 4 12:25:29 2021 - By Robert Madole -Copyright (c) Font Awesome - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.ttf b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.ttf deleted file mode 100644 index 25abf389e2..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.ttf and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.woff b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.woff deleted file mode 100644 index 23ee663443..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.woff and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.woff2 b/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.woff2 deleted file mode 100644 index 2217164f0c..0000000000 Binary files a/domain-rrd/service-python/svc-pdfgenerator/src/public/webfonts/fa-solid-900.woff2 and /dev/null differ diff --git a/domain-rrd/service-python/svc-pdfgenerator/src/requirements.txt.bak b/domain-rrd/service-python/svc-pdfgenerator/src/requirements.txt.bak deleted file mode 100644 index 152aac853c..0000000000 --- a/domain-rrd/service-python/svc-pdfgenerator/src/requirements.txt.bak +++ /dev/null @@ -1,13 +0,0 @@ - -# Linting + Testing -flake8==6.0.0 -isort==5.12.0 -Jinja2==3.1.3 -pdfkit==1.0.0 -pika==1.3.1 -pytest==7.3.1 -pytest-cov==4.0.0 -pytest-mock-resources==2.6.11 -python-dateutil==2.8.2 -pytz==2023.3 -redis==4.5.4 diff --git a/domain-rrd/service-python/tests/__init__.py b/domain-rrd/service-python/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/tests/assessclaim/_init_.py b/domain-rrd/service-python/tests/assessclaim/_init_.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/tests/assessclaim/cancer/test_cancer_condition.py b/domain-rrd/service-python/tests/assessclaim/cancer/test_cancer_condition.py deleted file mode 100644 index 5cb80f518c..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/cancer/test_cancer_condition.py +++ /dev/null @@ -1,283 +0,0 @@ -import pytest -from assessclaimcancer.src.lib import condition - - -@pytest.mark.parametrize( - "request_body, cancer_type, response", - [ - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.2", - "text": "Malignant neoplasm of vertebral column", - "onsetDate": "2014-11-27"}, - {"code": "C91.52", - "text": "Adult T-cell lymphoma/leukemia (HTLV-1-associated), in relapse", - "onsetDate": "2016-11-27"} - ] - }, - "dateOfClaim": "2021-11-09", - }, - "neck", - {"conditionsMeetDateRequirements": False, - "conditions": [{"code": "C41.2", - "suggestedCategory": "Bone", - "text": "Malignant neoplasm of vertebral column", - "onsetDate": "2014-11-27"}], - "conditionsCount": 2, - "relevantConditionsCount": 1}, - ), - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2014-11-27"}, - {"code": "C25", - "text": "Malignant neoplasm of pancreas", - "onsetDate": "2021-11-1"}] - }, - "dateOfClaim": "2021-11-09", - }, - "pancreatic", - { - "conditionsMeetDateRequirements": True, - "conditions": [{"code": "C25", - "text": "Malignant neoplasm of pancreas", - "onsetDate": "2021-11-1"}], - "conditionsCount": 2, - "relevantConditionsCount": 1, - }, - ), - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2014-11-27"}, - {"code": "C43.72", - "text": "Malignant melanoma of left lower limb, including hip", - "onsetDate": "2014-11-27"}] - }, - "dateOfClaim": "2021-11-09", - }, - "melanoma", - {"conditionsMeetDateRequirements": False, - "conditions": [ - {"code": "C43.72", - "text": "Malignant melanoma of left lower limb, including hip", - "onsetDate": "2014-11-27"}], - "conditionsCount": 2, - "relevantConditionsCount": 1}, - ), - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2014-11-27"}, - {"code": "C61", - "text": "Malignant neoplasm of prostate", - "onsetDate": "2021-11-1"}] - }, - "dateOfClaim": "2021-11-09", - }, - "prostate", - {"conditionsMeetDateRequirements": True, - "conditions": [{"code": "C61", - "text": "Malignant neoplasm of prostate", - "onsetDate": "2021-11-1"}], - "conditionsCount": 2, - "relevantConditionsCount": 1}, - ), - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2014-11-27"}, - {"code": "C56", - "text": "Malignant neoplasm of ovary", - "onsetDate": "2014-11-27"}] - }, - "dateOfClaim": "2021-11-09", - }, - "gyn", - {"conditionsMeetDateRequirements": False, - "conditions": [{"code": "C56", - "text": "Malignant neoplasm of ovary", - "suggestedCategory": "Ovarian", - "onsetDate": "2014-11-27"}], - "conditionsCount": 2, - "relevantConditionsCount": 1}, - ), - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2020-11-27"}, - {"code": "C41.2", - "text": "Malignant neoplasm of vertebral column", - "onsetDate": "2014-11-27"}] - }, - "dateOfClaim": "2021-11-09", - }, - "head", - {"conditionsMeetDateRequirements": True, - "conditions": [{"code": "C41.0", - "suggestedCategory": "Bone", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2020-11-27"}], - "conditionsCount": 2, - "relevantConditionsCount": 1}, - ), - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2014-11-27"}, - {"code": "C63.7", - "text": "Malignant neoplasm of other specified male genital organs", - "onsetDate": "2014-11-27"}] - }, - "dateOfClaim": "2021-11-09", - }, - "male_reproductive", - {"conditionsMeetDateRequirements": False, - "conditions": [{"code": "C63.7", - "suggestedCategory": "Multiple", - "text": "Malignant neoplasm of other specified male genital organs", - "onsetDate": "2014-11-27"}], - "conditionsCount": 2, - "relevantConditionsCount": 1}, - ), - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2014-11-27"}, - {"code": "C18.1", - "text": "Malignant neoplasm of appendix", - "onsetDate": "2014-11-27"}] - }, - "dateOfClaim": "2021-11-09", - }, - "gi", - {"conditionsMeetDateRequirements": False, - "conditions": [{"code": "C18.1", - "text": "Malignant neoplasm of appendix", - "onsetDate": "2014-11-27"}], - "conditionsCount": 2, - "relevantConditionsCount": 1}, - ), - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2014-11-27"}, - {"code": "C50", - "text": "Malignant neoplasm of breast", - "onsetDate": "2014-11-27"}] - }, - "dateOfClaim": "2021-11-09", - }, - "breast", - {"conditionsMeetDateRequirements": False, - "conditions": [{"code": "C50", - "text": "Malignant neoplasm of breast", - "onsetDate": "2014-11-27"}], - "conditionsCount": 2, - "relevantConditionsCount": 1}, - ), - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2014-11-27"}, - {"code": "C64", - "text": "Malignant neoplasm of kidney, except renal pelvis", - "onsetDate": "2014-11-27"}] - }, - "dateOfClaim": "2021-11-09", - }, - "kidney", - {"conditionsMeetDateRequirements": False, - "conditions": [{"code": "C64", - "text": "Malignant neoplasm of kidney, except renal pelvis", - "onsetDate": "2014-11-27"}], - "conditionsCount": 2, - "relevantConditionsCount": 1}, - ), - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2014-11-27"}, - {"code": "C71", - "text": "Malignant neoplasm of brain", - "onsetDate": "2014-11-27"}] - }, - "dateOfClaim": "2021-11-09", - }, - "brain", - {"conditionsMeetDateRequirements": False, - "conditions": [{"code": "C71", - "text": "Malignant neoplasm of brain", - "onsetDate": "2014-11-27"}], - "conditionsCount": 2, - "relevantConditionsCount": 1}, - ), - ( - { - "evidence": { - "medications": [], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face", - "onsetDate": "2014-11-27"}, - {"code": "C34.0", - "text": "Malignant neoplasm of main bronchus", - "onsetDate": "2014-11-27"}] - }, - "dateOfClaim": "2021-11-09", - }, - "respiratory", - {"conditionsMeetDateRequirements": False, - "conditions": [{"code": "C34.0", - "suggestedCategory": "Bronchus", - "text": "Malignant neoplasm of main bronchus", - "onsetDate": "2014-11-27"}], - "conditionsCount": 2, - "relevantConditionsCount": 1}, - ), - - ], -) -def test_condition(request_body, cancer_type, response): - """ - Test the function that takes the request and returns the response - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param response: response after running data through algorithms - :type response: dict - """ - api_response = condition.active_cancer_condition(request_body, cancer_type) - - assert api_response == response diff --git a/domain-rrd/service-python/tests/assessclaim/cancer/test_cancer_main.py b/domain-rrd/service-python/tests/assessclaim/cancer/test_cancer_main.py deleted file mode 100644 index f8c44cc19e..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/cancer/test_cancer_main.py +++ /dev/null @@ -1,59 +0,0 @@ -import pytest -from assessclaimcancer.src.lib import main - - -@pytest.mark.parametrize( - "request_body, response", - [ - ( - { - "evidence": { - "medications": [ - { - "description": "0.4 ML Otrexup 56.3 MG/ML Auto-Injector", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - {"evidence": {"conditions": [], - "medications": [{"authoredOn": "1962-04-06T04:00:00Z", - "conditionRelated": True, - "description": "CISplatin 50 MG", - "status": "active", - "suggestedCategory": "Multiple"}, - {"authoredOn": "1952-04-06T04:00:00Z", - "conditionRelated": True, - "description": "0.4 ML Otrexup 56.3 MG/ML " - "Auto-Injector", - "status": "active", - "suggestedCategory": "Lung"}]}, - "evidenceSummary": {"conditionsCount": 1, - "relevantConditionsCount": 0, - "relevantMedCount": 2, - "totalMedCount": 2}, - "sufficientForFastTracking": None} - ) - ], -) -def test_main(request_body, response): - """ - Test the function that takes the request and returns the response - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param response: response after running data through algorithms - :type response: dict - """ - api_response = main.assess_cancer(request_body) - - assert api_response == response diff --git a/domain-rrd/service-python/tests/assessclaim/cancer/test_cancer_medication.py b/domain-rrd/service-python/tests/assessclaim/cancer/test_cancer_medication.py deleted file mode 100644 index 0747c83d19..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/cancer/test_cancer_medication.py +++ /dev/null @@ -1,393 +0,0 @@ -import pytest -from assessclaimcancer.src.lib import medication - - -@pytest.mark.parametrize( - "request_body, cancer_type, response", - [ - ( - { - "evidence": { - "medications": [ - { - "description": "0.4 ML Otrexup 56.3 MG/ML Auto-Injector", - "status": "active", - "authoredOn": "2021-04-06T04:00:00Z", - }, - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - "head", - {"medicationMeetsDateRequirements": False, - "medications": [{"authoredOn": "2021-04-06T04:00:00Z", - "conditionRelated": True, - "description": "0.4 ML Otrexup 56.3 MG/ML Auto-Injector", - "status": "active", - "suggestedCategory": "Multiple"}, - {"authoredOn": "1962-04-06T04:00:00Z", - "conditionRelated": True, - "description": "CISplatin 50 MG", - "status": "active", - "suggestedCategory": "Multiple"}], - "relevantMedCount": 2, - "totalMedCount": 2} - ), - ( - { - "evidence": { - "medications": [ - { - "description": "0.4 ML Otrexup 56.3 MG/ML Auto-Injector", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - "neck", - {"medicationMeetsDateRequirements": False, - "medications": [ - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - "suggestedCategory": "Multiple", - "conditionRelated": True - }, - { - "description": "0.4 ML Otrexup 56.3 MG/ML Auto-Injector", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - "suggestedCategory": "Multiple", - "conditionRelated": True - }], - "relevantMedCount": 2, - "totalMedCount": 2} - ), - ( - { - "evidence": { - "medications": [ - { - "description": "0.4 ML Otrexup 56.3 MG/ML Auto-Injector", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - "male_reproductive", - { - "medicationMeetsDateRequirements": False, - "medications": [ - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - "suggestedCategory": "Multiple", - "conditionRelated": True - } - ], - "relevantMedCount": 1, - "totalMedCount": 2 - } - ), - ( - { - "evidence": { - "medications": [ - { - "description": "0.4 ML Otrexup 56.3 MG/ML Auto-Injector", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "paclitaxel 6 MG/ML", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - "gyn", - { - "medicationMeetsDateRequirements": False, - "medications": [ - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "paclitaxel 6 MG/ML", - "status": "active", - "suggestedCategory": "Cervical, Uterine", - "conditionRelated": True - } - ], - "relevantMedCount": 1, - "totalMedCount": 2 - } - ), - ( - { - "evidence": { - "medications": [ - { - "description": "0.4 ML Otrexup 56.3 MG/ML Auto-Injector", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - "prostate", - { - "medicationMeetsDateRequirements": False, - "medications": [ - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - "conditionRelated": True - } - ], - "relevantMedCount": 1, - "totalMedCount": 2 - } - ), - ( - { - "evidence": { - "medications": [ - { - "description": "everolimus 0.75 MG", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - "pancreatic", - {"medicationMeetsDateRequirements": False, - "medications": [ - { - "description": "everolimus 0.75 MG", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - "conditionRelated": True - }], - "relevantMedCount": 1, - "totalMedCount": 2} - ), - ( - { - "evidence": { - "medications": [ - { - "description": "aldesleukin 22000000 UNT [Proleukin]", - "status": "active", - "authoredOn": "2021-06-06T04:00:00Z", - }, - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - "melanoma", - {"medicationMeetsDateRequirements": True, - "medications": [ - { - "description": "aldesleukin 22000000 UNT [Proleukin]", - "status": "active", - "authoredOn": "2021-06-06T04:00:00Z", - "suggestedCategory": "Systemic chemotherapy", - "conditionRelated": True - }], - "relevantMedCount": 1, - "totalMedCount": 2} - ), - ( - { - "evidence": { - "medications": [ - { - "description": "aldesleukin 22000000 UNT [Proleukin]", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - "kidney", - {"medicationMeetsDateRequirements": False, - "medications": [{"authoredOn": "1952-04-06T04:00:00Z", - "conditionRelated": True, - "description": "aldesleukin 22000000 UNT [Proleukin]", - "status": "active"}], - "relevantMedCount": 1, - "totalMedCount": 2} - ), - ( - { - "evidence": { - "medications": [ - { - "description": "methotrexate 2.5 MG/ML Injectable Solution", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - "breast", - {"medicationMeetsDateRequirements": False, - "medications": [ - { - "description": "methotrexate 2.5 MG/ML Injectable Solution", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - "conditionRelated": True - }], - "relevantMedCount": 1, - "totalMedCount": 2} - ), - ( - { - "evidence": { - "medications": [ - { - "description": "aldesleukin 22000000 UNT [Proleukin]", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - { - "authoredOn": "2021-06-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - "gi", - {"medicationMeetsDateRequirements": True, - "medications": [ - { - "description": "CISplatin 50 MG", - "status": "active", - "authoredOn": "2021-06-06T04:00:00Z", - "conditionRelated": True - }], - "relevantMedCount": 1, - "totalMedCount": 2} - ), - ( - { - "evidence": { - "medications": [ - { - "description": "aldesleukin 22000000 UNT [Proleukin]", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - { - "authoredOn": "1962-04-06T04:00:00Z", - "description": "CISplatin 50 MG", - "status": "active", - }, - ], - "conditions": [{"code": "C41.0", - "text": "Malignant neoplasm of bones of skull and face"}] - }, - "dateOfClaim": "2021-11-09", - }, - "brain", - {"medicationMeetsDateRequirements": False, - "medications": [ - { - "description": "CISplatin 50 MG", - "status": "active", - "authoredOn": "1962-04-06T04:00:00Z", - "conditionRelated": True - }], - "relevantMedCount": 1, - "totalMedCount": 2} - ) - ], -) -def test_medication(request_body, cancer_type, response): - """ - Test the function that takes the request and returns the response - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param response: response after running data through algorithms - :type response: dict - """ - api_response = medication.medication_match(request_body, cancer_type) - - assert api_response == response diff --git a/domain-rrd/service-python/tests/assessclaim/dc6510/_init_.py b/domain-rrd/service-python/tests/assessclaim/dc6510/_init_.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_condition.py b/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_condition.py deleted file mode 100644 index 03f875e177..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_condition.py +++ /dev/null @@ -1,122 +0,0 @@ -import pytest -from assessclaimdc6510.src.lib import condition - - -@pytest.mark.parametrize( - "request_body, filtered_condition", - [ - ( - { - "evidence": { - "conditions": [ - {"text": "Chronic maxillary sinusitis", - "code": "35923002", - "status": "active", - "onsetDate": "2021-11-01"} - ], - }, - "dateOfClaim": "2021-11-09", - }, - { - "conditions": [], - "constantSinusitis": False, - "relevantConditionsCount": 0, - "totalConditionsCount": 1, - "osteomyelitis": False, - }, - ), - ( - { - "evidence": { - "conditions": [ - {"text": "Asthma", - "code": "J45", - "status": "active", - "onsetDate": "2021-11-01"} - ], - }, - "dateOfClaim": "2021-11-09", - }, - { - "conditions": [ - ], - "relevantConditionsCount": 0, - "totalConditionsCount": 1, - "constantSinusitis": False, - "osteomyelitis": False, - }, - ), - ( - { - "evidence": { - "conditions": [ - {"text": "Chronic maxillary sinusitis", - "code": "35923002", - "status": "active", - "onsetDate": "2021-11-01"}, - {"text": "Asthma", - "code": "J45", - "status": "active", - "onsetDate": "2021-11-01"}, - ], - }, - "dateOfClaim": "2022-06-09", - }, - { - "conditions": [], - "relevantConditionsCount": 0, - "totalConditionsCount": 2, - "constantSinusitis": False, - "osteomyelitis": False, - }, - ), - ( - { - "evidence": { - "conditions": [ - {"text": "Osteomyelitis", - "code": "H05.029", - "status": "active", - "onsetDate": "2021-11-01"}, - {"text": "Chronic maxillary sinusitis", - "code": "J32.0", - "status": "active", - "onsetDate": "2021-11-01"}, - ] - }, - "dateOfClaim": "2021-11-09", - }, - { - "conditions": [ - {"text": "Osteomyelitis", - "code": "H05.029", - "status": "active", - "onsetDate": "2021-11-01"}, - {"text": "Chronic maxillary sinusitis", - "code": "J32.0", - "status": "active", - "onsetDate": "2021-11-01"}, - ], - "relevantConditionsCount": 2, - "totalConditionsCount": 2, - "constantSinusitis": False, - "osteomyelitis": True, - }, - ), - ], -) -def test_condition( - request_body, filtered_condition -): - """ - Test the condition filtering algorithm - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param filtered_condition: correct return value from algorithm - :type filtered_condition: dict - """ - assert ( - condition.conditions_calculation(request_body) - == filtered_condition - ) diff --git a/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_main.py b/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_main.py deleted file mode 100644 index 26deba40bf..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_main.py +++ /dev/null @@ -1,165 +0,0 @@ -import pytest -from assessclaimdc6510.src.lib import main - - -@pytest.mark.parametrize( - "request_body, response", - [ - ( - { - "evidence": { - "medications": [ - { - "description": "azithromycin 250 MG Oral Tablet [Zithromax]", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - } - ], - "conditions": [], - "procedures": [] - }, - "dateOfClaim": "2021-11-09", - "claimSubmissionId": "1234" - }, - { - "evidence": { - "medications": [ - { - "conditionRelated": True, - "authoredOn": "1952-04-06T04:00:00Z", - "description": "azithromycin 250 MG Oral Tablet [Zithromax]", - "status": "active", - } - ], - "conditions": [], - "procedures": [] - }, - "evidenceSummary": {"relevantConditionsCount": 0, - "relevantMedCount": 1, - "totalConditionsCount": 0, - "totalMedCount": 1, - "relevantProceduresCount": 0, - "totalProceduresCount": 0}, - "sufficientForFastTracking": None, - "claimSubmissionId": "1234" - } - ), - # demonstrates ability to match substrings in medication["text"] property - ( - { - "evidence": { - "medications": [ - { - "description": "azithromycin 250 MG Oral Tablet [Zithromax]", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - } - ], - "conditions": [{"text": "Chronic maxillary sinusitis", - "code": "35923002", - "status": "active", - "onsetDate": "2020-11-01"}], - "procedures": [] - }, - "dateOfClaim": "2021-06-09", - "claimSubmissionId": "1234" - }, - { - "evidence": { - "medications": [ - { - "conditionRelated": True, - "authoredOn": "1952-04-06T04:00:00Z", - "description": "azithromycin 250 MG Oral Tablet [Zithromax]", - "status": "active", - } - ], - "conditions": [], - "procedures": [] - }, - "evidenceSummary": {"relevantConditionsCount": 0, - "relevantMedCount": 1, - "totalConditionsCount": 1, - "totalMedCount": 1, - "relevantProceduresCount": 0, - "totalProceduresCount": 0}, - "sufficientForFastTracking": None, - "claimSubmissionId": "1234" - }, - ), - ( - { - "evidence": { - "medications": [ - { - "description": "Advil", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - } - ], - "conditions": [{"text": "Chronic maxillary sinusitis", - "code": "35923002", - "status": "active", - "onsetDate": "2021-11-01"}, - {"text": "Chronic maxillary sinusitis", - "code": "J32.0", - "status": "active", - "onsetDate": "2021-11-01"}], - "procedures": [{"text": "Nasal/sinus endoscopy, surgical, with dilation (eg, balloon " - "dilation); sphenoid " - "sinus ostium", - "code": "31297", - "status": "completed", - "performedDate": "2010-2-22"} - ] - }, - "dateOfClaim": "2021-11-09", - "claimSubmissionId": "1234" - }, - { - "evidence": { - "medications": [ - { - "conditionRelated": False, - "authoredOn": "1952-04-06T04:00:00Z", - "description": "Advil", - "status": "active", - } - ], - "conditions": [ - {"text": "Chronic maxillary sinusitis", - "code": "J32.0", - "status": "active", - "onsetDate": "2021-11-01"}, - ], - "procedures": [{"text": "Nasal/sinus endoscopy, surgical, with dilation (eg, balloon " - "dilation); sphenoid sinus ostium", - "code": "31297", - "status": "completed", - "performedDate": "2010-2-22"}, - ] - }, - "evidenceSummary": {"relevantConditionsCount": 1, - "relevantMedCount": 0, - "totalConditionsCount": 2, - "totalMedCount": 1, - "relevantProceduresCount": 1, - "totalProceduresCount": 1}, - "sufficientForFastTracking": False, - "claimSubmissionId": "1234" - }, - ), - ], -) -def test_main(request_body, response): - """ - Test the function that takes the request and returns the response - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param response: response after running data through algorithms - :type response: dict - """ - api_response = main.assess_sinusitis(request_body) - - assert api_response == response diff --git a/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_medication.py b/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_medication.py deleted file mode 100644 index 89805f0a3c..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_medication.py +++ /dev/null @@ -1,143 +0,0 @@ -import pytest -from assessclaimdc6510.src.lib import medication - - -@pytest.mark.parametrize( - "request_body, continuous_medication_required_calculation", - [ - # Service connected and medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "azithromycin 250 MG Oral Tablet [Zithromax]", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - "dateOfClaim": "2021-11-09", - } - }, - { - "medications": [ - { - "conditionRelated": True, - "authoredOn": "1950-04-06T04:00:00Z", - "description": "azithromycin 250 MG Oral Tablet [Zithromax]", - "status": "active", - } - ], - "relevantMedCount": 1, - "totalMedCount": 1, - }, - ), - # Not service connected but uses medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "azithromycin 250 MG Oral Tablet [Zithromax]", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - "dateOfClaim": "2021-11-09", - } - }, - { - "medications": [ - { - "conditionRelated": True, - "authoredOn": "1950-04-06T04:00:00Z", - "description": "azithromycin 250 MG Oral Tablet [Zithromax]", - "status": "active", - } - ], - "relevantMedCount": 1, - "totalMedCount": 1, - }, - ), - # Service connected but doesn't use medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "Advil", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - "dateOfClaim": "2021-11-09", - } - }, - { - "medications": [ - { - "conditionRelated": False, - "authoredOn": "1950-04-06T04:00:00Z", - "description": "Advil", - "status": "active", - } - ], - "relevantMedCount": 0, - "totalMedCount": 1, - }, - ), - # multiple medications, some to treat and others not to treat asthma - ( - { - "evidence": { - "medications": [ - { - "description": "azithromycin 250 MG Oral Tablet [Zithromax]", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - }, - { - "description": "Advil", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - ], - "dateOfClaim": "2021-11-09", - } - }, - { - "medications": [ - { - "conditionRelated": True, - "authoredOn": "1950-04-06T04:00:00Z", - "description": "azithromycin 250 MG Oral Tablet [Zithromax]", - "status": "active", - }, - { - "conditionRelated": False, - "authoredOn": "1952-04-06T04:00:00Z", - "description": "Advil", - "status": "active", - }, - ], - "relevantMedCount": 1, - "totalMedCount": 2, - }, - ), - ], -) -def test_continuous_medication_required( - request_body, continuous_medication_required_calculation -): - """ - Test the history of continuous medication required algorithm - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param continuous_medication_required_calculation: correct return value from algorithm - :type continuous_medication_required_calculation: dict - """ - assert ( - medication.medication_required(request_body) - == continuous_medication_required_calculation - ) diff --git a/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_procedure.py b/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_procedure.py deleted file mode 100644 index 327e21a00c..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6510/test_sinusitis_procedure.py +++ /dev/null @@ -1,90 +0,0 @@ -import pytest -from assessclaimdc6510.src.lib import procedure - - -@pytest.mark.parametrize( - "request_body, filtered_procedures", - [ - ( - { - "evidence": { - "procedures": [ - {"text": "Nasal/sinus endoscopy, surgical, with dilation (eg, balloon dilation); sphenoid " - "sinus ostium", - "code": "31297", - "status": "completed", - "performedDate": "2010-03-22"}, - {"text": "Anesthesia for procedures on nose and accessory sinuses; radical surgery", - "code": "00162", - "status": "completed", - "performedDate": "2010-2-22"} - ], - "dateOfClaim": "2021-11-09", - } - }, - { - "procedures": [ - {"text": "Nasal/sinus endoscopy, surgical, with dilation (eg, balloon dilation); sphenoid " - "sinus ostium", - "code": "31297", - "status": "completed", - "performedDate": "2010-03-22"}, - {"text": "Anesthesia for procedures on nose and accessory sinuses; radical surgery", - "code": "00162", - "status": "completed", - "performedDate": "2010-2-22"} - ], - "relevantProceduresCount": 2, - "totalProceduresCount": 2, - "radicalSurgery": True, - "multipleSurgery": False - }, - ), - ( - { - "evidence": { - "procedures": [ - {"text": "Nasal/sinus endoscopy, surgical, with dilation (eg, balloon dilation); sphenoid " - "sinus ostium", - "code": "31297", - "status": "completed", - "performedDate": "2010-2-22"}, - {"text": "Thoracoscopy, surgical; with partial pulmonary decortication", - "code": "32651", - "status": "completed", - "performedDate": "2010-2-22"} - ], - "dateOfClaim": "2021-11-09", - } - }, - { - "procedures": [ - {"text": "Nasal/sinus endoscopy, surgical, with dilation (eg, balloon dilation); sphenoid " - "sinus ostium", - "code": "31297", - "status": "completed", - "performedDate": "2010-2-22"} - ], - "radicalSurgery": False, - "relevantProceduresCount": 1, - "totalProceduresCount": 2, - "multipleSurgery": False - }, - ), - ], -) -def test_procedure( - request_body, filtered_procedures -): - """ - Test the condition filtering algorithm - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param filtered_procedures: correct return value from algorithm - :type filtered_procedures: dict - """ - assert ( - procedure.procedures_calculation(request_body) - == filtered_procedures - ) diff --git a/domain-rrd/service-python/tests/assessclaim/dc6522/_init_.py b/domain-rrd/service-python/tests/assessclaim/dc6522/_init_.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_conditions.py b/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_conditions.py deleted file mode 100644 index 427565efbb..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_conditions.py +++ /dev/null @@ -1,89 +0,0 @@ -import pytest -from assessclaimdc6522.src.lib import conditions - - -@pytest.mark.parametrize( - "request_body, conditions_calc", - [ - # Service connected and medication used to treat hypertension - ( - { - "evidence": { - "conditions": [ - {"text": "Granulomatous rhinitis (chronic)", - "code": "J31.0", - "status": "Active" - }, - { - "text": "Nasal polyps", - "code": "J33.9", - "status": "Active" - } - - ], - }, - "date_of_claim": "2021-11-09", - }, - {"conditions": [{ - "text": "Granulomatous rhinitis (chronic)", - "code": "J31.0", - "status": "Active" - }, - { - "text": "Nasal polyps", - "code": "J33.9", - "status": "Active"}], - "relevantConditionsCount": 2, - "totalConditionsCount": 2, - "diagnosticCodes": ["6524"], - "nasalPolyps": True - } - ), - ( - { - "evidence": { - "conditions": [ - {"text": "Allergic rhinitis due to food", "code": "J30.5", "status": "Active"}, - {"code": "72409005", "text": "Rhinoscleroma (disorder)", "status": "recurrence"} - ], - }, - "date_of_claim": "2021-11-09", - }, - {"conditions": [{"text": "Allergic rhinitis due to food", "code": "J30.5", "status": "Active" - }], - "relevantConditionsCount": 1, - "totalConditionsCount": 2, - "diagnosticCodes": ["6522"], - "nasalPolyps": False - } - ), - ( - { - "evidence": { - "conditions": [ - { - "text": "Eosinophilic asthma", - "code": "J82.83", - "status": "Active", - } - ], - "date_of_claim": "2021-11-09", - } - }, - {"conditions": [], - "relevantConditionsCount": 0, - "totalConditionsCount": 1, - "diagnosticCodes": [], - "nasalPolyps": False - } - ), - ], -) -def test_conditions_calculation(request_body, conditions_calc): - """ - Test the filtering of conditions for Asthma - :param request_body: sample data for a claim reqeust - :param conditions_calc:e expected output from the condition algorithm - """ - active_conditions = conditions.conditions_calculation(request_body) - assert active_conditions == conditions_calc diff --git a/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_main.py b/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_main.py deleted file mode 100644 index 108f6ebf1f..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_main.py +++ /dev/null @@ -1,138 +0,0 @@ -import pytest -from assessclaimdc6522.src.lib import main - - -@pytest.mark.parametrize( - "request_body, response", - [ - ( - { - "evidence": { - "medications": [ - { - "description": "Prednisone", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - } - ], - "conditions": [{ - "text": "Nasal polyps", - "code": "J33.9", - "status": "Active" - }], - "procedures": [] - }, - "date_of_claim": "2021-11-09", - "claimSubmissionId": "1234" - }, - {"evidence": {"medications": [{"authoredOn": "1952-04-06T04:00:00Z", - "conditionRelated": False, - "description": "Prednisone", - "status": "active"}], - "conditions": [{ - "text": "Nasal polyps", - "code": "J33.9", - "status": "Active" - }], - "procedures": [] - }, - "evidenceSummary": {"diagnosticCodes": [], - "relevantConditionsCount": 1, - "relevantMedCount": 0, - "relevantProceduresCount": 0, - "totalConditionsCount": 1, - "totalMedCount": 1, - "totalProceduresCount": 0}, - "sufficientForFastTracking": True} - ), - # demonstrates ability to match substrings in medication["text"] property - ( - { - "evidence": { - "medications": [ - { - "description": "predniSONE 1 MG Oral Tablet", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - } - ], - "conditions": [], - "procedures": [] - }, - "date_of_claim": "2021-11-09", - "claimSubmissionId": "1234" - }, - {"evidence": {"medications": [{"authoredOn": "1952-04-06T04:00:00Z", - "conditionRelated": False, - "description": "predniSONE 1 MG Oral Tablet", - "status": "active"}], - "conditions": [], - "procedures": [] - }, - "evidenceSummary": {"diagnosticCodes": [], - "relevantConditionsCount": 0, - "relevantMedCount": 0, - "relevantProceduresCount": 0, - "totalConditionsCount": 0, - "totalMedCount": 1, - "totalProceduresCount": 0}, - "sufficientForFastTracking": None}, - ), - # calculator feild mild-persistent-asthma-or-greater is True - ( - { - "evidence": { - "medications": [ - { - "description": "Advil", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - } - ], - "conditions": [{"text": "Granulomatous rhinitis (chronic)", - "code": "J31.0", - "status": "Active" - }], - "procedures": [] - }, - "date_of_claim": "2021-11-09", - "claimSubmissionId": "1234" - }, - { - "evidence": { - "medications": [{ - "authoredOn": "1952-04-06T04:00:00Z", - "conditionRelated": False, - "description": "Advil", - "status": "active"}, - ], - "conditions": [{"text": "Granulomatous rhinitis (chronic)", - "code": "J31.0", - "status": "Active" - }], - "procedures": [] - }, - "evidenceSummary": {"diagnosticCodes": ["6524"], - "relevantConditionsCount": 1, - "relevantMedCount": 0, - "relevantProceduresCount": 0, - "totalConditionsCount": 1, - "totalMedCount": 1, - "totalProceduresCount": 0}, - "sufficientForFastTracking": False - }, - ), - ], -) -def test_main(request_body, response): - """ - Test the function that takes the request and returns the response - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param response: response after running data through algorithms - :type response: dict - """ - api_response = main.assess_rhinitis(request_body) - - assert api_response == response diff --git a/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_medication.py b/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_medication.py deleted file mode 100644 index 64644f2cba..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_medication.py +++ /dev/null @@ -1,146 +0,0 @@ -import pytest -from assessclaimdc6522.src.lib import medication - - -@pytest.mark.parametrize( - "request_body, continuous_medication_required_calculation", - [ - # Service connected and medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "fexofenadine Oral Tablet [Allegra]", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - "date_of_claim": "2021-11-09", - } - }, - { - "medications": [ - { - "conditionRelated": True, - "authoredOn": "1950-04-06T04:00:00Z", - "description": "fexofenadine Oral Tablet [Allegra]", - "status": "active", - "suggestedCategory": "Antihistimine" - } - ], - "relevantMedCount": 1, - "totalMedCount": 1, - }, - ), - # Not service connected but uses medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "pseudoephedrine 45 MG", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - "date_of_claim": "2021-11-09", - } - }, - { - "medications": [ - { - "conditionRelated": True, - "authoredOn": "1950-04-06T04:00:00Z", - "description": "pseudoephedrine 45 MG", - "status": "active", - "suggestedCategory": "Antihistamine / Decongestant" - } - ], - "relevantMedCount": 1, - "totalMedCount": 1, - }, - ), - # Service connected but doesn"t use medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "Advil", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - "date_of_claim": "2021-11-09", - } - }, - { - "medications": [ - { - "conditionRelated": False, - "authoredOn": "1950-04-06T04:00:00Z", - "description": "Advil", - "status": "active", - } - ], - "relevantMedCount": 0, - "totalMedCount": 1, - }, - ), - # multiple medications, some to treat and others not to treat asthma - ( - { - "evidence": { - "medications": [ - { - "description": "diphenhydrAMINE hydrochloride 2.5 MG/ML Oral Solution", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - }, - { - "description": "Advil", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - ], - "date_of_claim": "2021-11-09", - } - }, - { - "medications": [ - { - "conditionRelated": True, - "authoredOn": "1950-04-06T04:00:00Z", - "description": "diphenhydrAMINE hydrochloride 2.5 MG/ML Oral Solution", - "status": "active", - "suggestedCategory": "Antihistimine" - }, - { - "conditionRelated": False, - "authoredOn": "1952-04-06T04:00:00Z", - "description": "Advil", - "status": "active", - }, - ], - "relevantMedCount": 1, - "totalMedCount": 2, - }, - ), - ], -) -def test_medication( - request_body, continuous_medication_required_calculation -): - """ - Test the history of continuous medication required algorithm - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param continuous_medication_required_calculation: correct return value from algorithm - :type continuous_medication_required_calculation: dict - """ - assert ( - medication.medication_required(request_body) - == continuous_medication_required_calculation - ) diff --git a/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_procedures.py b/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_procedures.py deleted file mode 100644 index 5291165dbd..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6522/test_rhinitis_procedures.py +++ /dev/null @@ -1,78 +0,0 @@ -import pytest -from assessclaimdc6522.src.lib import procedure - - -@pytest.mark.parametrize( - "request_body, continuous_medication_required_calculation", - [ - # Service connected and medication used to treat hypertension - ( - { - "evidence": { - "procedures": [ - { - "text": "Professional services for allergen immunotherapy not including " - "provision of allergenic extracts; two or more injections", - "code": "95117", - "status": "completed", - "performedDate": "1950-04-06", - } - ], - "date_of_claim": "2021-11-09", - } - }, - { - "procedures": [ - { - "text": "Professional services for allergen immunotherapy not including " - "provision of allergenic extracts; two or more injections", - "code": "95117", - "status": "completed", - "performedDate": "1950-04-06", - } - ], - "relevantProceduresCount": 1, - "totalProceduresCount": 1, - }, - ), - ( - { - "evidence": { - "procedures": [ - { - "text": "Documentation of current medications", - "code": "XXXXX", - "status": "Completed", - "performedDate": "2009-03-19", - "codeSystem": "http://www.ama-assn.org/go/cpt" - } - ], - "date_of_claim": "2021-11-09", - } - }, - { - "procedures": [ - ], - "relevantProceduresCount": 0, - "totalProceduresCount": 1, - }, - - - ), - ], -) -def test_procedures( - request_body, continuous_medication_required_calculation -): - """ - Test the history of continuous medication required algorithm - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param continuous_medication_required_calculation: correct return value from algorithm - :type continuous_medication_required_calculation: dict - """ - assert ( - procedure.procedures_calculation(request_body) - == continuous_medication_required_calculation - ) diff --git a/domain-rrd/service-python/tests/assessclaim/dc6602/_init_.py b/domain-rrd/service-python/tests/assessclaim/dc6602/_init_.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/tests/assessclaim/dc6602/test_asthma_main.py b/domain-rrd/service-python/tests/assessclaim/dc6602/test_asthma_main.py deleted file mode 100644 index 0ec5460d2a..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6602/test_asthma_main.py +++ /dev/null @@ -1,110 +0,0 @@ -import pytest -from assessclaimdc6602.src.lib import main - - -@pytest.mark.parametrize( - "request_body, response", - [ - ( - { - "evidence": { - "medications": [ - { - "description": "Prednisone", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - } - ] - }, - "dateOfClaim": "2021-11-09", - "claimSubmissionId": "1234" - }, - { - "evidence": { - "medications": [ - { - "asthmaRelevant": "true", - "authoredOn": "1952-04-06T04:00:00Z", - "description": "Prednisone", - "status": "active", - } - ] - }, - "evidenceSummary": {"relevantMedCount": 1, "totalMedCount": 1}, - "claimSubmissionId": "1234" - }, - ), - # demonstrates ability to match substrings in medication["text"] property - ( - { - "evidence": { - "medications": [ - { - "description": "predniSONE 1 MG Oral Tablet", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - } - ] - }, - "dateOfClaim": "2021-11-09", - "claimSubmissionId": "1234" - }, - { - "evidence": { - "medications": [ - { - "asthmaRelevant": "true", - "authoredOn": "1952-04-06T04:00:00Z", - "description": "predniSONE 1 MG Oral Tablet", - "status": "active", - } - ] - }, - "evidenceSummary": {"relevantMedCount": 1, "totalMedCount": 1}, - "claimSubmissionId": "1234" - }, - ), - # calculator feild mild-persistent-asthma-or-greater is True - ( - { - "evidence": { - "medications": [ - { - "description": "Advil", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - } - ] - }, - "dateOfClaim": "2021-11-09", - "claimSubmissionId": "1234" - }, - { - "evidence": { - "medications": [ - { - "asthmaRelevant": "false", - "authoredOn": "1952-04-06T04:00:00Z", - "description": "Advil", - "status": "active", - } - ] - }, - "evidenceSummary": {"relevantMedCount": 0, "totalMedCount": 1}, - "claimSubmissionId": "1234" - }, - ), - ], -) -def test_main(request_body, response): - """ - Test the function that takes the request and returns the response - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param response: response after running data through algorithms - :type response: dict - """ - api_response = main.assess_asthma(request_body) - - assert api_response == response diff --git a/domain-rrd/service-python/tests/assessclaim/dc6602/test_asthma_medication.py b/domain-rrd/service-python/tests/assessclaim/dc6602/test_asthma_medication.py deleted file mode 100644 index 8c1c350650..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6602/test_asthma_medication.py +++ /dev/null @@ -1,143 +0,0 @@ -import pytest -from assessclaimdc6602.src.lib import medication - - -@pytest.mark.parametrize( - "request_body, continuous_medication_required_calculation", - [ - # Service connected and medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "Albuterol inhaler", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - "dateOfClaim": "2021-11-09", - } - }, - { - "medications": [ - { - "asthmaRelevant": "true", - "authoredOn": "1950-04-06T04:00:00Z", - "description": "Albuterol inhaler", - "status": "active", - } - ], - "relevantMedCount": 1, - "totalMedCount": 1, - }, - ), - # Not service connected but uses medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "Albuterol", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - "dateOfClaim": "2021-11-09", - } - }, - { - "medications": [ - { - "asthmaRelevant": "true", - "authoredOn": "1950-04-06T04:00:00Z", - "description": "Albuterol", - "status": "active", - } - ], - "relevantMedCount": 1, - "totalMedCount": 1, - }, - ), - # Service connected but doesn't use medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "Advil", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - "dateOfClaim": "2021-11-09", - } - }, - { - "medications": [ - { - "asthmaRelevant": "false", - "authoredOn": "1950-04-06T04:00:00Z", - "description": "Advil", - "status": "active", - } - ], - "relevantMedCount": 0, - "totalMedCount": 1, - }, - ), - # multiple medications, some to treat and others not to treat asthma - ( - { - "evidence": { - "medications": [ - { - "description": "Albuterol", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - }, - { - "description": "Advil", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - ], - "dateOfClaim": "2021-11-09", - } - }, - { - "medications": [ - { - "asthmaRelevant": "true", - "authoredOn": "1950-04-06T04:00:00Z", - "description": "Albuterol", - "status": "active", - }, - { - "asthmaRelevant": "false", - "authoredOn": "1952-04-06T04:00:00Z", - "description": "Advil", - "status": "active", - }, - ], - "relevantMedCount": 1, - "totalMedCount": 2, - }, - ), - ], -) -def test_continuous_medication_required( - request_body, continuous_medication_required_calculation -): - """ - Test the history of continuous medication required algorithm - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param continuous_medication_required_calculation: correct return value from algorithm - :type continuous_medication_required_calculation: dict - """ - assert ( - medication.medication_required(request_body) - == continuous_medication_required_calculation - ) diff --git a/domain-rrd/service-python/tests/assessclaim/dc6602v2/_init_.py b/domain-rrd/service-python/tests/assessclaim/dc6602v2/_init_.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/tests/assessclaim/dc6602v2/test_conditions_v2.py b/domain-rrd/service-python/tests/assessclaim/dc6602v2/test_conditions_v2.py deleted file mode 100644 index 64bc81be08..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6602v2/test_conditions_v2.py +++ /dev/null @@ -1,70 +0,0 @@ -import pytest -from assessclaimdc6602v2.src.lib import condition - - -@pytest.mark.parametrize( - "request_body, conditions_calc", - [ - ( - { - "evidence": { - "bp_readings": [], - "conditions": [ - { - "text": "Eosinophilic asthma", - "code": "J82.83", - "status": "Active", - "dataSource": "LH" - } - ], - "medications": [{"description": "Hydrochlorothiazide 25 MG"}], - }, - "claimSubmissionDateTime": "2021-11-09", - }, - {"conditions": [{"code": "J82.83", - "dateFormatted": "", - "dataSource": "LH", - "relevant": True, - "status": "Active", - "text": "Eosinophilic asthma"}], - "relevantConditionsLighthouseCount": 1, - "totalConditionsCount": 1, - "twoYearsConditions": []} - ), - ( - { - "evidence": { - "bp_readings": [], - "conditions": [ - { - "code": "Asthma", - "text": "asthma", - "recordedDate": "1950-04-06", - "dataSource": "MAS" - } - ], - "medications": [{"description": "Hydrochlorothiazide 25 MG"}], - }, - "claimSubmissionDateTime": "2021-11-09", - }, - {"conditions": [{ - "code": "Asthma", - "dataSource": "MAS", - "dateFormatted": "4/6/1950", - "recordedDate": "1950-04-06", - "relevant": False, - "text": "asthma"}], - "relevantConditionsLighthouseCount": 0, - "totalConditionsCount": 1, - "twoYearsConditions": []} - ), - ], -) -def test_conditions_calculation(request_body, conditions_calc): - """ - Test the filtering of conditions for Asthma - :param request_body: sample data for a claim reqeust - :param conditions_calc:e expected output from the condition algorithm - """ - active_conditions = condition.conditions_calculation(request_body) - assert active_conditions == conditions_calc diff --git a/domain-rrd/service-python/tests/assessclaim/dc6602v2/test_continuous_medication_v2.py b/domain-rrd/service-python/tests/assessclaim/dc6602v2/test_continuous_medication_v2.py deleted file mode 100644 index fae57d4afd..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6602v2/test_continuous_medication_v2.py +++ /dev/null @@ -1,197 +0,0 @@ -import pytest -from assessclaimdc6602v2.src.lib import medication - - -@pytest.mark.parametrize( - "request_body, continuous_medication_required_calculation", - [ - # Service connected and medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "Albuterol inhaler", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - "dataSource": "MAS" - } - ], - }, - "claimSubmissionDateTime": "2021-11-09", - }, - {"medications": [{"authoredOn": "1950-04-06T04:00:00Z", - "classification": "Bronchodilator/Used in Respiratory " - "Failure", - "dataSource": "MAS", - "dateFormatted": "4/6/1950", - "description": "Albuterol inhaler", - "status": "active"}], - "allMedicationsCount": 1, - "oneYearMedication": [], - "oneYearMedicationsCount": 0, - "schedularMedicationOneYearCount": 0} - ), - # Not service connected but uses medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "Albuterol", - "dataSource": "MAS", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ] - }, - "claimSubmissionDateTime": "2021-11-09", - }, - {"medications": [{"authoredOn": "1950-04-06T04:00:00Z", - "classification": "Bronchodilator/Used in Respiratory " - "Failure", - "dataSource": "MAS", - "dateFormatted": "4/6/1950", - "description": "Albuterol", - "status": "active"}], - "allMedicationsCount": 1, - "oneYearMedication": [], - "oneYearMedicationsCount": 0, - "schedularMedicationOneYearCount": 0} - ), - # Service connected but doesn"t use medication used to treat hypertension - ( - { - "evidence": { - "medications": [ - { - "description": "Advil", - "status": "active", - "dataSource": "MAS", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - }, - "claimSubmissionDateTime": "2021-11-09", - }, - {"medications": [{"authoredOn": "1950-04-06T04:00:00Z", - "classification": "", - "dataSource": "MAS", - "dateFormatted": "4/6/1950", - "description": "Advil", - "status": "active"}], - "allMedicationsCount": 1, - "oneYearMedication": [], - "oneYearMedicationsCount": 0, - "schedularMedicationOneYearCount": 0} - ), - # multiple medications, some to treat and others not to treat asthma - ( - { - "evidence": { - "medications": [ - { - "description": "Albuterol", - "status": "active", - "dataSource": "MAS", - "authoredOn": "1950-04-06T04:00:00Z", - }, - { - "description": "Advil", - "status": "active", - "dataSource": "MAS", - "authoredOn": "1952-04-06T04:00:00Z", - }, - ] - }, - "claimSubmissionDateTime": "2021-11-09", - }, - {"medications": [{"authoredOn": "1952-04-06T04:00:00Z", - "classification": "", - "dataSource": "MAS", - "dateFormatted": "4/6/1952", - "description": "Advil", - "status": "active"}, - {"authoredOn": "1950-04-06T04:00:00Z", - "classification": "Bronchodilator/Used in Respiratory " - "Failure", - "dataSource": "MAS", - "dateFormatted": "4/6/1950", - "description": "Albuterol", - "status": "active"}], - "allMedicationsCount": 2, - "oneYearMedication": [], - "oneYearMedicationsCount": 0, - "schedularMedicationOneYearCount": 0} - ), - # medication description contains multiple keywords - ( - { - "evidence": { - "medications": [ - { - "description": "14 ACTUAT fluticasone furoate 0.1 MG/ACTUAT / " - "vilanterol 0.025 MG/ACTUAT Dry Powder Inhaler", - "status": "active", - "dataSource": "MAS", - "authoredOn": "2021-04-06T04:00:00Z", - } - ] - }, - "claimSubmissionDateTime": "2021-11-09", - }, - {"medications": [{"authoredOn": "2021-04-06T04:00:00Z", - "classification": "Anti-Inflammatory/Bronchodilator/Corticosteroid/Immuno-Suppressive", - "dataSource": "MAS", - "dateFormatted": "4/6/2021", - "description": "14 ACTUAT fluticasone furoate 0.1 " - "MG/ACTUAT / vilanterol 0.025 MG/ACTUAT " - "Dry Powder Inhaler", - "status": "active"}], - "allMedicationsCount": 1, - "oneYearMedication": [], - "oneYearMedicationsCount": 0, - "schedularMedicationOneYearCount": 0} - ), - ], -) -def test_continuous_medication_required( - request_body, continuous_medication_required_calculation -): - """ - Test the history of continuous medication required algorithm - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param continuous_medication_required_calculation: correct return value from algorithm - :type continuous_medication_required_calculation: dict - """ - assert ( - medication.filter_categorize_mas_medication(request_body) - == continuous_medication_required_calculation - ) - - -@pytest.mark.parametrize( - "medication_display, expected", - [ - ("Albuterol", "Bronchodilator/Used in Respiratory Failure"), - ("Advil", ""), - # medication description contains multiple keywords, - # returns the most general category for any medication in description - ( - "14 ACTUAT fluticasone furoate 0.1 MG/ACTUAT / vilanterol 0.025 MG/ACTUAT Dry Powder Inhaler", - "Anti-Inflammatory/Bronchodilator/Corticosteroid/Immuno-Suppressive", - ), - ], -) -# Service connected and medication used to treat hypertension -def test_categorize_med(medication_display, expected): - """ - Test the categorization of medications - :param medication_display: medication description - :param expected: category - """ - - category = medication.classify_med(medication_display) - - assert category == expected diff --git a/domain-rrd/service-python/tests/assessclaim/dc6602v2/test_main_v2.py b/domain-rrd/service-python/tests/assessclaim/dc6602v2/test_main_v2.py deleted file mode 100644 index 873ff321cd..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc6602v2/test_main_v2.py +++ /dev/null @@ -1,130 +0,0 @@ -import pytest -from assessclaimdc6602v2.src.lib import main - - -@pytest.mark.parametrize( - "request_body, response", - [ - ( - { - "evidence": { - "medications": [ - { - "description": "Prednisone", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - "dataSource": "MAS" - } - ], - "conditions": [], - "procedures": [] - }, - "claimSubmissionDateTime": "2021-11-09", - "claimSubmissionId": "1234", - "disabilityActionType": "INCREASE" - }, - {"claimSubmissionDateTime": "2021-11-09", - "claimSubmissionId": "1234", - "disabilityActionType": "INCREASE", - "evidence": {"conditions": [], - "documentsWithoutAnnotationsChecked": [], - "medications": [{"authoredOn": "1952-04-06T04:00:00Z", - "classification": "Anti-Inflammatory/Corticosteroid/Immuno-Suppressive", - "dataSource": "MAS", - "dateFormatted": "4/6/1952", - "description": "Prednisone", - "status": "active"}], - "procedures": []}, - "evidenceSummary": {"proceduresCount": 0, - "relevantConditionsLighthouseCount": 0, - "schedularMedicationOneYearCount": 0, - "totalConditionsCount": 0, - "totalMedCount": 1}} - ), - # demonstrates ability to match substrings in medication["text"] property - ( - { - "evidence": { - "medications": [ - { - "description": "predniSONE 1 MG Oral Tablet", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - "dataSource": "MAS" - } - ], - "conditions": [], - "procedures": [] - }, - "claimSubmissionDateTime": "2021-11-09", - "claimSubmissionId": "1234", - "disabilityActionType": "INCREASE" - }, - {"claimSubmissionDateTime": "2021-11-09", - "claimSubmissionId": "1234", - "disabilityActionType": "INCREASE", - "evidence": {"conditions": [], - "documentsWithoutAnnotationsChecked": [], - "medications": [{"authoredOn": "1952-04-06T04:00:00Z", - "classification": "Anti-Inflammatory/Corticosteroid/Immuno-Suppressive", - "dataSource": "MAS", - "dateFormatted": "4/6/1952", - "description": "predniSONE 1 MG Oral Tablet", - "status": "active"}], - "procedures": []}, - "evidenceSummary": {"proceduresCount": 0, - "relevantConditionsLighthouseCount": 0, - "schedularMedicationOneYearCount": 0, - "totalConditionsCount": 0, - "totalMedCount": 1}} - ), - # calculator feild mild-persistent-asthma-or-greater is True - ( - { - "evidence": { - "medications": [ - { - "description": "Advil", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - "dataSource": "MAS" - } - ], - "conditions": [], - "procedures": [] - }, - "claimSubmissionDateTime": "2021-11-09", - "claimSubmissionId": "1234", - "disabilityActionType": "INCREASE" - }, - {"claimSubmissionDateTime": "2021-11-09", - "claimSubmissionId": "1234", - "disabilityActionType": "INCREASE", - "evidence": {"conditions": [], - "documentsWithoutAnnotationsChecked": [], - "medications": [{"authoredOn": "1952-04-06T04:00:00Z", - "classification": "", - "dataSource": "MAS", - "dateFormatted": "4/6/1952", - "description": "Advil", - "status": "active"}], - "procedures": []}, - "evidenceSummary": {"proceduresCount": 0, - "relevantConditionsLighthouseCount": 0, - "schedularMedicationOneYearCount": 0, - "totalConditionsCount": 0, - "totalMedCount": 1}} - ), - ], -) -def test_main(request_body, response): - """ - Test the function that takes the request and returns the response - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param response: response after running data through algorithms - :type response: dict - """ - api_response = main.assess_sufficiency_asthma(request_body) - - assert api_response == response diff --git a/domain-rrd/service-python/tests/assessclaim/dc7101/_init_.py b/domain-rrd/service-python/tests/assessclaim/dc7101/_init_.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/tests/assessclaim/dc7101/bp_sufficiency_test.py b/domain-rrd/service-python/tests/assessclaim/dc7101/bp_sufficiency_test.py deleted file mode 100644 index 1b9d7f5f12..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc7101/bp_sufficiency_test.py +++ /dev/null @@ -1,1807 +0,0 @@ -import pytest -from assessclaimdc7101.src.lib import bp_calculator - - -@pytest.mark.parametrize( - "request_body, bp_calculator_result", - [ - # Two readings. No out of range dates. - ( - {"evidence": { - "bp_readings": [ - { - "diastolic": { - "value": 115 - }, - "systolic": { - "value": 180 - }, - "organization": "", - "receiptDate": "11/1/2022", - "date": "2021-11-01", - "dataSource": "MAS" - }, - { - "diastolic": { - "value": 110 - }, - "systolic": { - "value": 200 - }, - "organization": "", - "receiptDate": "11/1/2022", - "date": "2021-09-01", - "dataSource": "LH" - } - ] - }, - "claimSubmissionDateTime": "2021-11-09T17:45:59Z", - }, - {'allBp': [{'dataSource': 'MAS', - 'date': '2021-11-01', - "organization": "", - 'dateFormatted': '11/1/2021', - 'diastolic': {'value': 115}, - 'receiptDate': '11/1/2022', - 'systolic': {'value': 180}}, - {'dataSource': 'LH', - 'date': '2021-09-01', - "organization": "", - 'dateFormatted': '9/1/2021', - 'diastolic': {'value': 110}, - 'receiptDate': '11/1/2022', - 'systolic': {'value': 200}}], - 'oneYearBp': [{'dataSource': 'MAS', - 'date': '2021-11-01', - "organization": "", - 'dateFormatted': '11/1/2021', - 'diastolic': {'value': 115}, - 'receiptDate': '11/1/2022', - 'systolic': {'value': 180}}, - {'dataSource': 'LH', - 'date': '2021-09-01', - "organization": "", - 'dateFormatted': '9/1/2021', - 'diastolic': {'value': 110}, - 'receiptDate': '11/1/2022', - 'systolic': {'value': 200}}], - 'oneYearBpCount': 2, - 'twoYearsElevatedBpCount': 2, - 'totalBpCount': 2, - 'twoYearsBp': [{'dataSource': 'MAS', - 'date': '2021-11-01', - "organization": "", - 'dateFormatted': '11/1/2021', - 'diastolic': {'value': 115}, - 'receiptDate': '11/1/2022', - 'systolic': {'value': 180}}, - {'dataSource': 'LH', - 'date': '2021-09-01', - "organization": "", - 'dateFormatted': '9/1/2021', - 'diastolic': {'value': 110}, - 'receiptDate': '11/1/2022', - 'systolic': {'value': 200}}], - 'twoYearsBpCount': 2} - ), - # 3 reading test case with one out of range date - ( - - {"evidence": { - "bp_readings": [ - { - "diastolic": { - "value": 115 - }, - "systolic": { - "value": 180 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2019-11-01" - }, - { - "diastolic": { - "value": 0 - }, - "systolic": { - "value": 0 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-09-01" - }, - { - "diastolic": { - "value": 120 - }, - "systolic": { - "value": 210 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2020-11-09" - } - ] - }, - "claimSubmissionDateTime": "2021-11-09T17:45:59Z", - }, - {'allBp': [{'date': '2021-09-01', - 'dateFormatted': '9/1/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 0}, - 'receiptDate': '', - 'systolic': {'value': 0}}, - {'date': '2020-11-09', - 'dateFormatted': '11/9/2020', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 120}, - 'receiptDate': '', - 'systolic': {'value': 210}}, - {'date': '2019-11-01', - 'dateFormatted': '11/1/2019', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 115}, - 'receiptDate': '', - 'systolic': {'value': 180}}], - 'oneYearBp': [{'date': '2020-11-09', - 'dateFormatted': '11/9/2020', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 120}, - 'receiptDate': '', - 'systolic': {'value': 210}}], - 'oneYearBpCount': 1, - 'totalBpCount': 3, - 'twoYearsBp': [{'date': '2021-09-01', - 'dateFormatted': '9/1/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 0}, - 'receiptDate': '', - 'systolic': {'value': 0}}, - {'date': '2020-11-09', - 'dateFormatted': '11/9/2020', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 120}, - 'receiptDate': '', - 'systolic': {'value': 210}}], - 'twoYearsBpCount': 1, - 'twoYearsElevatedBpCount': 1} - ), - ( - { - "evidence": { - - "bp_readings": [ - { - "diastolic": { - "value": 112 - }, - "systolic": { - "value": 181 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-10-09" - }, - { - "diastolic": { - "value": 109 - }, - "systolic": { - "value": 181 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-10-10" - }, - { - "diastolic": { - "value": 113 - }, - "systolic": { - "value": 131 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-05-13" - }, - { - "diastolic": { - "value": 101 - }, - "systolic": { - "value": 160 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-09-13" - }, - { - "diastolic": { - "value": 104 - }, - "systolic": { - "value": 120 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-09-13" - }, - { - "diastolic": { - "value": 116 - }, - "systolic": { - "value": 180 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-10-13" - }, - { - "diastolic": { - "value": 111 - }, - "systolic": { - "value": 155 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-10-14" - } - ] - }, - "claimSubmissionDateTime": "2021-11-09T17:45:59Z", - }, - {'allBp': [{'date': '2021-10-14', - "receiptDate": "", - 'dateFormatted': '10/14/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 111}, - 'systolic': {'value': 155}}, - {'date': '2021-10-13', - "receiptDate": "", - 'dateFormatted': '10/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 116}, - 'systolic': {'value': 180}}, - {'date': '2021-10-10', - "receiptDate": "", - 'dateFormatted': '10/10/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 109}, - 'systolic': {'value': 181}}, - {'date': '2021-10-09', - "receiptDate": "", - 'dateFormatted': '10/9/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 112}, - 'systolic': {'value': 181}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 101}, - 'systolic': {'value': 160}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 104}, - 'systolic': {'value': 120}}, - {'date': '2021-05-13', - "receiptDate": "", - "organization": "", - "dataSource": "", - 'dateFormatted': '5/13/2021', - 'diastolic': {'value': 113}, - 'systolic': {'value': 131}}], - 'oneYearBp': [{'date': '2021-10-14', - "receiptDate": "", - 'dateFormatted': '10/14/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 111}, - 'systolic': {'value': 155}}, - {'date': '2021-10-13', - "receiptDate": "", - 'dateFormatted': '10/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 116}, - 'systolic': {'value': 180}}, - {'date': '2021-10-10', - "receiptDate": "", - 'dateFormatted': '10/10/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 109}, - 'systolic': {'value': 181}}, - {'date': '2021-10-09', - "receiptDate": "", - 'dateFormatted': '10/9/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 112}, - 'systolic': {'value': 181}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 101}, - 'systolic': {'value': 160}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 104}, - 'systolic': {'value': 120}}, - {'date': '2021-05-13', - "receiptDate": "", - 'dateFormatted': '5/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 113}, - 'systolic': {'value': 131}}], - 'oneYearBpCount': 7, - 'twoYearsElevatedBpCount': 4, - 'totalBpCount': 7, - 'twoYearsBp': [{'date': '2021-10-14', - "receiptDate": "", - 'dateFormatted': '10/14/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 111}, - 'systolic': {'value': 155}}, - {'date': '2021-10-13', - "receiptDate": "", - 'dateFormatted': '10/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 116}, - 'systolic': {'value': 180}}, - {'date': '2021-10-10', - "receiptDate": "", - 'dateFormatted': '10/10/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 109}, - 'systolic': {'value': 181}}, - {'date': '2021-10-09', - "receiptDate": "", - 'dateFormatted': '10/9/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 112}, - 'systolic': {'value': 181}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 101}, - 'systolic': {'value': 160}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 104}, - 'systolic': {'value': 120}}, - {'date': '2021-05-13', - "receiptDate": "", - 'dateFormatted': '5/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 113}, - 'systolic': {'value': 131}}], - 'twoYearsBpCount': 7} - ), - ( - { - "evidence": { - - "bp_readings": [ - { - "diastolic": { - "value": 109 - }, - "systolic": { - "value": 181 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-10-10" - }, - { - "diastolic": { - "value": 113 - }, - "systolic": { - "value": 131 - }, - "organization": "", - "dataSource": "", - "receiptDate": "9/13/2021", - "date": "" # no date - }, - { - "diastolic": { - "value": 101 - }, - "systolic": { - "value": 160 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-09-13" - }, - { - "diastolic": { - "value": 104 - }, - "systolic": { - "value": 120 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-09-13" - }, - { - "diastolic": { - "value": 116 - }, - "systolic": { - "value": 180 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-10-13" - }, - { - "diastolic": { - "value": 111 - }, - "systolic": { - "value": 155 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-10-14" - } - ] - }, - "claimSubmissionDateTime": "2021-11-09T17:45:59Z", - }, - {'allBp': [{'date': '2021-10-14', - "receiptDate": "", - 'dateFormatted': '10/14/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 111}, - 'systolic': {'value': 155}}, - {'date': '2021-10-13', - "receiptDate": "", - 'dateFormatted': '10/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 116}, - 'systolic': {'value': 180}}, - {'date': '2021-10-10', - "receiptDate": "", - 'dateFormatted': '10/10/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 109}, - 'systolic': {'value': 181}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 101}, - 'systolic': {'value': 160}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 104}, - 'systolic': {'value': 120}}, - {'date': '', - "receiptDate": "9/13/2021", - 'dateFormatted': '', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 113}, - 'systolic': {'value': 131}}], - 'oneYearBp': [{'date': '2021-10-14', - "receiptDate": "", - 'dateFormatted': '10/14/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 111}, - 'systolic': {'value': 155}}, - {'date': '2021-10-13', - "receiptDate": "", - 'dateFormatted': '10/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 116}, - 'systolic': {'value': 180}}, - {'date': '2021-10-10', - "receiptDate": "", - 'dateFormatted': '10/10/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 109}, - 'systolic': {'value': 181}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 101}, - 'systolic': {'value': 160}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 104}, - 'systolic': {'value': 120}}, - ], - 'oneYearBpCount': 5, - 'twoYearsElevatedBpCount': 3, - 'totalBpCount': 6, - 'twoYearsBp': [{'date': '2021-10-14', - "receiptDate": "", - 'dateFormatted': '10/14/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 111}, - 'systolic': {'value': 155}}, - {'date': '2021-10-13', - "receiptDate": "", - 'dateFormatted': '10/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 116}, - 'systolic': {'value': 180}}, - {'date': '2021-10-10', - "receiptDate": "", - 'dateFormatted': '10/10/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 109}, - 'systolic': {'value': 181}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 101}, - 'systolic': {'value': 160}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 104}, - 'systolic': {'value': 120}}, - ], - 'twoYearsBpCount': 5} - ), - ( - { - "evidence": { - - "bp_readings": [ - { - "diastolic": { - "value": 109 - }, - "systolic": { - "value": 181 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-10-10" - }, - { - "diastolic": { - "value": 113 - }, - "systolic": { - "value": 131 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-05-13" - }, - { - "diastolic": { - "value": 101 - }, - "systolic": { - "value": 160 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-09-13" - }, - { - "diastolic": { - "value": 104 - }, - "systolic": { - "value": 120 - }, - "organization": "", - "dataSource": "", - "receiptDate": "", - "date": "2021-09-13" - }, - { - "diastolic": { - "value": 116 - }, - "systolic": { - "value": 180 - }, - "organization": "", - "dataSource": "", - "date": "2021-10-13", - "receiptDate": "", - }, - { - "diastolic": { - "value": 111 - }, - "systolic": { - "value": 155 - }, - "organization": "", - "dataSource": "", - "date": "2021-10-14", - "receiptDate": "", - }, - { - "diastolic": { - "value": 105 - }, - "systolic": { - "value": 154 - }, - "organization": "", - "dataSource": "", - "date": "2020-11-08", - "receiptDate": "", - } - ] - }, - "claimSubmissionDateTime": "2021-11-09T17:45:59Z", - }, - {'allBp': [{'date': '2021-10-14', - "receiptDate": "", - 'dateFormatted': '10/14/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 111}, - 'systolic': {'value': 155}}, - {'date': '2021-10-13', - "receiptDate": "", - 'dateFormatted': '10/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 116}, - 'systolic': {'value': 180}}, - {'date': '2021-10-10', - "receiptDate": "", - 'dateFormatted': '10/10/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 109}, - 'systolic': {'value': 181}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 101}, - 'systolic': {'value': 160}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 104}, - 'systolic': {'value': 120}}, - {'date': '2021-05-13', - "receiptDate": "", - 'dateFormatted': '5/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 113}, - 'systolic': {'value': 131}}, - {'date': '2020-11-08', - "receiptDate": "", - 'dateFormatted': '11/8/2020', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 105}, - 'systolic': {'value': 154}}], - 'oneYearBp': [{'date': '2021-10-14', - "receiptDate": "", - 'dateFormatted': '10/14/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 111}, - 'systolic': {'value': 155}}, - {'date': '2021-10-13', - "receiptDate": "", - 'dateFormatted': '10/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 116}, - 'systolic': {'value': 180}}, - {'date': '2021-10-10', - "receiptDate": "", - 'dateFormatted': '10/10/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 109}, - 'systolic': {'value': 181}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 101}, - 'systolic': {'value': 160}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 104}, - 'systolic': {'value': 120}}, - {'date': '2021-05-13', - "receiptDate": "", - 'dateFormatted': '5/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 113}, - 'systolic': {'value': 131}}], - 'oneYearBpCount': 6, - 'twoYearsElevatedBpCount': 3, - 'totalBpCount': 7, - 'twoYearsBp': [{'date': '2021-10-14', - "receiptDate": "", - 'dateFormatted': '10/14/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 111}, - 'systolic': {'value': 155}}, - {'date': '2021-10-13', - "receiptDate": "", - 'dateFormatted': '10/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 116}, - 'systolic': {'value': 180}}, - {'date': '2021-10-10', - "receiptDate": "", - 'dateFormatted': '10/10/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 109}, - 'systolic': {'value': 181}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 101}, - 'systolic': {'value': 160}}, - {'date': '2021-09-13', - "receiptDate": "", - 'dateFormatted': '9/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 104}, - 'systolic': {'value': 120}}, - {'date': '2021-05-13', - "receiptDate": "", - 'dateFormatted': '5/13/2021', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 113}, - 'systolic': {'value': 131}}, - {'date': '2020-11-08', - "receiptDate": "", - 'dateFormatted': '11/8/2020', - "organization": "", - "dataSource": "", - 'diastolic': {'value': 105}, - 'systolic': {'value': 154}}], - 'twoYearsBpCount': 7} - ), - ( - { - "evidence": { - - "bp_readings": [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 90 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 180 - }, - "date": "2021-10-01", - "dataSource": "", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "date": "2021-09-01", - "dataSource": "", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - } - ] - }, - "claimSubmissionDateTime": "2021-11-09T17:45:59Z", - }, - {'allBp': [{'date': '2021-10-01', - "receiptDate": "", - 'dateFormatted': '10/1/2021', - "dataSource": "", - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 90}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 180}}, - {'date': '2021-09-01', - "receiptDate": "", - 'dateFormatted': '9/1/2021', - "dataSource": "", - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}], - 'oneYearBp': [{'date': '2021-10-01', - "receiptDate": "", - 'dateFormatted': '10/1/2021', - "dataSource": "", - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 90}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 180}}, - {'date': '2021-09-01', - "receiptDate": "", - 'dateFormatted': '9/1/2021', - "dataSource": "", - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}], - 'oneYearBpCount': 2, - 'twoYearsElevatedBpCount': 1, - 'totalBpCount': 2, - 'twoYearsBp': [{'date': '2021-10-01', - 'dateFormatted': '10/1/2021', - "receiptDate": "", - "dataSource": "", - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 90}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 180}}, - {'date': '2021-09-01', - "receiptDate": "", - 'dateFormatted': '9/1/2021', - "dataSource": "", - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}], - 'twoYearsBpCount': 2} - ), - ( - { - "evidence": { - - "bp_readings": [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 115 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 180 - }, - "date": "2021-04-01", - "receiptDate": "", - "dataSource": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 100 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "LH", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 190 - }, - "dataSource": "LH", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "LH", - "date": "2021-10-11", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "VAMC Other Output Reports" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "VAMC Other Output Reports" - } - ] - }, - "claimSubmissionDateTime": "2021-11-09T17:45:59Z", - }, - {'allBp': [{'dataSource': 'LH', - 'date': '2021-10-11', - 'dateFormatted': '10/11/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': 'LH', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 100}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': 'LH', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 190}}, - {'dataSource': 'MAS', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'VAMC Other Output Reports', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': 'MAS', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'VAMC Other Output Reports', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': '', - 'date': '2021-04-01', - 'dateFormatted': '4/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 180}}], - 'oneYearBp': [{'dataSource': 'LH', - 'date': '2021-10-11', - 'dateFormatted': '10/11/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': 'LH', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 100}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': 'LH', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 190}}, - {'dataSource': 'MAS', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'VAMC Other Output Reports', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': 'MAS', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'VAMC Other Output Reports', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': '', - 'date': '2021-04-01', - 'dateFormatted': '4/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 180}}], - 'oneYearBpCount': 6, - 'totalBpCount': 6, - 'twoYearsBp': [{'dataSource': 'LH', - 'date': '2021-10-11', - 'dateFormatted': '10/11/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': 'LH', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 100}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': 'LH', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 190}}, - {'dataSource': 'MAS', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'VAMC Other Output Reports', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': 'MAS', - 'date': '2021-10-10', - 'dateFormatted': '10/10/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'VAMC Other Output Reports', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'dataSource': '', - 'date': '2021-04-01', - 'dateFormatted': '4/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 180}}], - 'twoYearsBpCount': 6, - 'twoYearsElevatedBpCount': 6} - ), - # 1 reading - ( - { - "evidence": { - - "bp_readings": [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 115 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 180 - }, - "receiptDate": "", - "dataSource": "", - "date": "2021-11-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - } - ] - }, - "claimSubmissionDateTime": "2021-11-09T17:45:59Z", - }, - {'allBp': [{'date': '2021-11-01', - 'dateFormatted': '11/1/2021', - "receiptDate": "", - "dataSource": "", - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 180}}], - 'oneYearBp': [{'date': '2021-11-01', - "receiptDate": "", - "dataSource": "", - 'dateFormatted': '11/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 180}}], - 'oneYearBpCount': 1, - 'twoYearsElevatedBpCount': 1, - 'totalBpCount': 1, - 'twoYearsBp': [{'date': '2021-11-01', - 'dateFormatted': '11/1/2021', - "receiptDate": "", - "dataSource": "", - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood pressure', - 'unit': 'mm[Hg]', - 'value': 180}}], - 'twoYearsBpCount': 1} - ), - # 0 readings - ( - { - "evidence": { - "bp_readings": [] - }, - "claimSubmissionDateTime": "2021-11-09T17:45:59Z", - }, - {'allBp': [], - 'oneYearBp': [], - 'oneYearBpCount': 0, - 'twoYearsElevatedBpCount': 0, - 'totalBpCount': 0, - 'twoYearsBp': [], - 'twoYearsBpCount': 0} - ) - ], -) -def test_bp_reader(request_body, bp_calculator_result): - """ - Test the history of blood pressure sufficiency algorithm - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param bp_calculator_result: correct return value from algorithm - :type bp_calculator_result: dict - """ - assert bp_calculator.bp_reader(request_body) == bp_calculator_result - - -@pytest.mark.parametrize( - "bp_readings, expected", - [ - ( - [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "LH", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "VAMC Other Output Reports" - } - ], - [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "VAMC Other Output Reports" - } - ] - ), - ( - [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 100 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "LH", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { # Not from HDR - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 100 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "Medical Treatment Record - Government Facility" - } - ], - [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 100 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "LH", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { # Not from HDR - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 100 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "Medical Treatment Record - Government Facility" - } - ] - ), - ( - [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 210 - }, - "dataSource": "LH", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "VAMC Other Output Reports" - } - ], - [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 210 - }, - "dataSource": "LH", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "VAMC Other Output Reports" - } - ] - ), - ( - [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "VAMC Other Output Reports" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "VAMC Other Output Reports" - } - ], - [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "VAMC Other Output Reports" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "MAS", - "date": "2021-10-10", - "receiptDate": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "VAMC Other Output Reports" - } - ] - ) - ] -) -def test_deduplicate(bp_readings, expected): - """ - Tests for deduplication of BP data between HDR and LH - - :param bp_readings: List of BP readings - :param expected: Deduplicated list - :return: - """ - - assert bp_calculator.deduplicate(bp_readings) == expected diff --git a/domain-rrd/service-python/tests/assessclaim/dc7101/continous_medication_test.py b/domain-rrd/service-python/tests/assessclaim/dc7101/continous_medication_test.py deleted file mode 100644 index 2853fa56bd..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc7101/continous_medication_test.py +++ /dev/null @@ -1,315 +0,0 @@ -import pytest -from assessclaimdc7101.src.lib import medications - - -@pytest.mark.parametrize( - "request_body, medication_required_calculation", - [ - ( - { - "evidence": { - "bp_readings": [], - "medications": [ - { - "description": "Benazepril", - "status": "active", - "authoredOn": "2020-04-06T04:00:00Z", - } - ], - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - } - }, - { - "medications": [ - { - "authoredOn": "2020-04-06T04:00:00Z", - "description": "Benazepril", - "status": "active", - } - ], - "medicationsCount": 1, - }, - ), - ( - { - "evidence": { - "bp_readings": [], - "medications": [ - { - "description": "Benazepril", - "status": "active", - "authoredOn": "2020-04-06T04:00:00Z", - } - ], - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - } - }, - { - "medications": [ - { - "authoredOn": "2020-04-06T04:00:00Z", - "description": "Benazepril", - "status": "active", - } - ], - "medicationsCount": 1, - }, - ), - ( - { - "evidence": { - "bp_readings": [], - "medications": [ - { - "description": "Advil", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - } - }, - { - "medications": [ - { - "authoredOn": "1950-04-06T04:00:00Z", - "description": "Advil", - "status": "active", - } - ], - "medicationsCount": 1, - }, - ), - ( - { - "evidence": { - "bp_readings": [], - "medications": [ - { - "description": "Benazepril", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - }, - { - "description": "Advil", - "status": "active", - "authoredOn": "1952-04-06T04:00:00Z", - }, - ], - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - } - }, - { - "medications": [ - { - "authoredOn": "1952-04-06T04:00:00Z", - "description": "Advil", - "status": "active", - }, - { - "authoredOn": "1950-04-06T04:00:00Z", - "description": "Benazepril", - "status": "active", - }, - ], - "medicationsCount": 2, - }, - ), - # Service connected but no medication - ( - { - "evidence": { - "bp_readings": [], - "medications": [], - } - }, - {"medications": [], "medicationsCount": 0}, - ), - ], -) -def test_medication_required( - request_body, medication_required_calculation -): - """ - Test the medication algorithm - - :param request_body: request body with medications - :type request_body: dict - :param medication_required_calculation: correct return value from algorithm - :type medication_required_calculation: dict - """ - assert ( - medications.medication_required(request_body) - == medication_required_calculation - ) - - -@pytest.mark.parametrize( - "request_body, mas_medication_calculation", - [ - # Medication used to treat hypertension - ( - { - "evidence": { - "bp_readings": [], - "medications": [ - { - "description": "Benazepril", - "status": "active", - "authoredOn": "2020-04-06T04:00:00Z", - "dataSource": "MAS", - "receiptDate": "", - } - ] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "disabilityActionType": "INCREASE" - }, - {'allMedications': [{'authoredOn': '2020-04-06T04:00:00Z', - 'dataSource': 'MAS', - 'dateFormatted': '4/6/2020', - 'description': 'Benazepril', - 'receiptDate': '', - 'status': 'active'}], - 'allMedicationsCount': 1, - 'twoYearsMedications': [{'authoredOn': '2020-04-06T04:00:00Z', - 'dataSource': 'MAS', - 'dateFormatted': '4/6/2020', - 'description': 'Benazepril', - 'receiptDate': '', - 'status': 'active'}], - 'twoYearsMedicationsCount': 1}, - ), - # Medication used to treat hypertension - ( - { - "evidence": { - "bp_readings": [], - "medications": [ - { - "description": "Benazepril", - "status": "active", - "authoredOn": "2020-04-06T04:00:00Z", - "dataSource": "MAS", - "receiptDate": "", - } - ] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "disabilityActionType": "INCREASE" - }, - {'allMedications': [{'authoredOn': '2020-04-06T04:00:00Z', - 'dataSource': 'MAS', - 'dateFormatted': '4/6/2020', - 'description': 'Benazepril', - 'receiptDate': '', - 'status': 'active'}], - 'allMedicationsCount': 1, - 'twoYearsMedications': [{'authoredOn': '2020-04-06T04:00:00Z', - 'dataSource': 'MAS', - 'dateFormatted': '4/6/2020', - 'description': 'Benazepril', - 'receiptDate': '', - 'status': 'active'}], - 'twoYearsMedicationsCount': 1} - ), - # Medication not used to treat hypertension - ( - { - "evidence": { - "bp_readings": [], - "medications": [ - { - "description": "Advil", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - "dataSource": "MAS", - "receiptDate": "", - - } - ] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "disabilityActionType": "INCREASE" - }, - {'allMedications': [{'authoredOn': '1950-04-06T04:00:00Z', - 'dataSource': 'MAS', - 'dateFormatted': '4/6/1950', - 'description': 'Advil', - 'receiptDate': '', - 'status': 'active'}], - 'allMedicationsCount': 1, - 'twoYearsMedications': [], - 'twoYearsMedicationsCount': 0} - ), - ( - { - "evidence": { - "bp_readings": [], - "medications": [ - { - "description": "Benazepril", - "status": "active", - "authoredOn": "", - "receiptDate": "", - "dataSource": "MAS" - }, - { - "description": "Advil", - "status": "active", - "receiptDate": "", - "authoredOn": "2021-04-06T04:00:00Z", - "dataSource": "LH" - }, - { - "description": "some medication", - "status": "active", - "authoredOn": "", - "receiptDate": "", - "partialDate": "**/**/1988", - "dataSource": "MAS" - }, - ], - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "disabilityActionType": "NEW" - }, - {'allMedications': [{'authoredOn': '', - 'dataSource': 'MAS', - 'dateFormatted': '', - 'description': 'Benazepril', - 'receiptDate': '', - 'status': 'active'}, - {'authoredOn': '', - 'dataSource': 'MAS', - 'dateFormatted': '', - 'description': 'some medication', - 'partialDate': '**/**/1988', - 'receiptDate': '', - 'status': 'active'}], - 'allMedicationsCount': 3, - 'twoYearsMedications': [], - 'twoYearsMedicationsCount': 0} - ), - ( - { - "evidence": { - "bp_readings": [], - "medications": [], - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "disabilityActionType": "INCREASE" - }, - {'allMedications': [], - 'allMedicationsCount': 0, - 'twoYearsMedications': [], - 'twoYearsMedicationsCount': 0} - ), - ], -) -def test_filter_mas_medication(request_body, mas_medication_calculation): - - assert ( - medications.filter_mas_medication(request_body) - == mas_medication_calculation - ) diff --git a/domain-rrd/service-python/tests/assessclaim/dc7101/main_sufficiency_test.py b/domain-rrd/service-python/tests/assessclaim/dc7101/main_sufficiency_test.py deleted file mode 100644 index 2ef4f12683..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc7101/main_sufficiency_test.py +++ /dev/null @@ -1,1075 +0,0 @@ -import pytest -from assessclaimdc7101.src.lib import main - - -@pytest.mark.parametrize( - "request_body, response", - [ - # New claim with two twoYears BP (one elevated, one normal) and relevant condition - ( - { - "evidence": { - "bp_readings": [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 90 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 120 - }, - "dataSource": "", - "date": "2021-11-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200.0 - }, - "dataSource": "", - "date": "2021-09-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - {'date': '2021-10-01', - "dataSource": "", - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200.0} - }, - - ], - "conditions": [{"code": "Hypertension", - "text": "Essential (primary) hypertension", - "recordedDate": "1950-04-06", - "dataSource": "MAS"}, - {"code": "123", - "text": "other condition", - "recordedDate": "2020-04-06", - "dataSource": "MAS"}, - {"code": "I10.", - "text": "Essential (primary) hypertension", - "recordedDate": "", - "category": "Encounter Diagnosis", - "dataSource": "LH"}], - "procedures": [], - "medications": [], - 'documentsWithoutAnnotationsChecked': [] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "disabilityActionType": "NEW", - "claimSubmissionId": "1234" - }, - {'claimSubmissionDateTime': '2021-11-09T04:00:00Z', - 'claimSubmissionId': '1234', - 'disabilityActionType': 'NEW', - 'evidence': {'bp_readings': [{'date': '2021-11-01', - 'dateFormatted': '11/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 90}, - 'document': '', - "dataSource": "", - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 120}}, - {'date': '2021-10-01', - 'dateFormatted': '10/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'document': '', - "dataSource": "", - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200.0}}, - {'date': '2021-09-01', - 'dateFormatted': '9/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'document': '', - "dataSource": "", - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200.0}}], - 'conditions': [{'code': '123', - 'category': '', - 'dataSource': 'MAS', - 'dateFormatted': '4/6/2020', - 'document': '', - 'organization': '', - 'page': '', - 'partialDate': '', - 'receiptDate': '', - 'recordedDate': '2020-04-06', - 'relevant': False, - 'text': 'other condition'}, - {'code': 'Hypertension', - 'category': '', - 'dataSource': 'MAS', - 'dateFormatted': '4/6/1950', - 'document': '', - 'organization': '', - 'page': '', - 'partialDate': '', - 'receiptDate': '', - 'recordedDate': '1950-04-06', - 'relevant': False, - 'text': 'Essential (primary) hypertension'}, - {'category': 'Encounter Diagnosis', - 'code': 'I10.', - 'dataSource': 'LH', - 'dateFormatted': '', - 'document': '', - 'organization': '', - 'page': '', - 'partialDate': '', - 'receiptDate': '', - 'recordedDate': '', - 'relevant': True, - 'text': 'Essential (primary) hypertension'}], - 'medications': [], - 'documentsWithoutAnnotationsChecked': []}, - 'evidenceSummary': {'allMedicationsCount': 0, - "lighthouseDuplicateBpCount": 0, - 'oneYearBpCount': 3, - 'relevantConditionsLighthouseCount': 1, - 'totalBpCount': 3, - 'totalConditionsCount': 3, - 'twoYearsBpCount': 3, - 'twoYearsElevatedBpCount': 2, - 'twoYearsMedicationsCount': 0}, - 'sufficientForFastTracking': True} - ), - # New claim with two twoYears BP both elevated and no condition - ( - { - "evidence": { - "bp_readings": [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 115 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 180 - }, - "dataSource": "", - "date": "2020-11-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "", - "date": "2020-09-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - } - ], - "conditions": [], - "medications": [], - 'documentsWithoutAnnotationsChecked': [] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "diagnosticCode": "7101", - "disabilityActionType": "NEW", - "claimSubmissionId": "1234" - }, - {'claimSubmissionDateTime': '2021-11-09T04:00:00Z', - 'claimSubmissionId': '1234', - 'disabilityActionType': 'NEW', - 'evidence': {'bp_readings': [{'date': '2020-11-01', - 'dateFormatted': '11/1/2020', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - "dataSource": "", - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 180}}, - {'date': '2020-09-01', - 'dateFormatted': '9/1/2020', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 0}, - 'document': '', - "dataSource": "", - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200}}], - 'conditions': [], - 'documentsWithoutAnnotationsChecked': [], - 'medications': []}, - 'evidenceSummary': {'allMedicationsCount': 0, - "lighthouseDuplicateBpCount": 0, - 'oneYearBpCount': 0, - 'relevantConditionsLighthouseCount': 0, - 'totalBpCount': 2, - 'totalConditionsCount': 0, - 'twoYearsBpCount': 1, - 'twoYearsElevatedBpCount': 1, - 'twoYearsMedicationsCount': 0}, - 'sufficientForFastTracking': None} - ), - # New claim with relevant condition but no twoYears BP - ( - { - "evidence": { - "bp_readings": [{"date": "2020-11-01", - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 115}, - "dataSource": "", - "organization": "LYONS VA MEDICAL CENTER", - "practitioner": "DR. JANE460 DOE922 MD", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 180}}, ], - "conditions": [ - {"code": "I10", - "text": "Essential (primary) hypertension", - "recordedDate": "1950-04-06", - "category": "Encounter Diagnosis", - "dataSource": "LH"}, - {"code": "1234", - "text": "snomed diagnosis", - "recordedDate": "", - "category": "", - "dataSource": "LH" - }, - ], - "medications": [{ - "text": "some medication", - "relevant": True, - "authoredOn": "1950-04-06T07:24:55Z", - "dataSource": "MAS" - }, - { - "text": "some medication", - "relevant": True, - "authoredOn": "", - "partialDate": "**/**/1988", - "dataSource": "MAS" - }] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "diagnosticCode": "7101", - "disabilityActionType": "NEW", - "claimSubmissionId": "1234" - }, - {'claimSubmissionDateTime': '2021-11-09T04:00:00Z', - 'claimSubmissionId': '1234', - 'disabilityActionType': 'NEW', - 'evidence': {'bp_readings': [{'date': '2020-11-01', - 'dateFormatted': '11/1/2020', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - "dataSource": "", - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 180}}], - 'conditions': [{'category': 'Encounter Diagnosis', - 'code': 'I10', - 'dataSource': 'LH', - 'dateFormatted': '4/6/1950', - 'document': '', - 'organization': '', - 'page': '', - 'partialDate': '', - 'receiptDate': '', - 'recordedDate': '1950-04-06', - 'relevant': True, - 'text': 'Essential (primary) hypertension'}, - {'category': '', - 'code': '1234', - 'dataSource': 'LH', - 'dateFormatted': '', - 'document': '', - 'organization': '', - 'page': '', - 'partialDate': '', - 'receiptDate': '', - 'recordedDate': '', - 'relevant': False, - 'text': 'snomed diagnosis'}], - 'medications': [{'authoredOn': '1950-04-06T07:24:55Z', - 'dateFormatted': '4/6/1950', - 'document': '', - 'organization': '', - 'page': '', - 'partialDate': '', - 'receiptDate': '', - 'relevant': True, - 'text': 'some medication', - "dataSource": "MAS"}, - {'authoredOn': '', - 'dateFormatted': '', - 'document': '', - 'organization': '', - 'page': '', - 'partialDate': '**/**/1988', - 'receiptDate': '', - 'relevant': True, - 'text': 'some medication', - "dataSource": "MAS"}], - 'documentsWithoutAnnotationsChecked': []}, - 'evidenceSummary': {'allMedicationsCount': 2, - "lighthouseDuplicateBpCount": 0, - 'oneYearBpCount': 0, - 'relevantConditionsLighthouseCount': 1, - 'totalBpCount': 1, - 'totalConditionsCount': 2, - 'twoYearsBpCount': 1, - 'twoYearsElevatedBpCount': 1, - 'twoYearsMedicationsCount': 0}, - 'sufficientForFastTracking': False} - ), - # New claim with no condition and no twoYears BP, BP not elevated - ( - { - "evidence": { - "bp_readings": [{"date": "", # missing date # noqa: E261 - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 115}, - "organization": "LYONS VA MEDICAL CENTER", - "practitioner": "DR. JANE460 DOE922 MD", - "dataSource": "", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 100}}, - {'date': '2020-11-01', - 'dateFormatted': '9/1/2020', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 90}, - "dataSource": "", - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {"date": "2020-09-01", - "dataSource": "", - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 90}, - "organization": "LYONS VA MEDICAL CENTER", - "practitioner": "DR. JANE460 DOE922 MD", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 200}}], - "conditions": [], - "medications": [{ - "text": "some medication", - "relevant": True, - "dataSource": "MAS" - }] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "diagnosticCode": "7101", - "disabilityActionType": "NEW", - "claimSubmissionId": "1234" - }, - {'claimSubmissionDateTime': '2021-11-09T04:00:00Z', - 'claimSubmissionId': '1234', - 'disabilityActionType': 'NEW', - 'evidence': {'bp_readings': [{'date': '2020-11-01', - "dataSource": "", - 'dateFormatted': '11/1/2020', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 90}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'date': '2020-09-01', - "dataSource": "", - 'dateFormatted': '9/1/2020', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 90}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'date': '', - "dataSource": "", - 'dateFormatted': '', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 100}}], - 'conditions': [], - 'medications': [{'dateFormatted': '', - 'document': '', - 'organization': '', - 'page': '', - 'partialDate': '', - 'receiptDate': '', - 'relevant': True, - 'text': 'some medication', - "dataSource": "MAS"}], - 'documentsWithoutAnnotationsChecked': []}, - 'evidenceSummary': {'allMedicationsCount': 1, - "lighthouseDuplicateBpCount": 0, - 'oneYearBpCount': 0, - 'relevantConditionsLighthouseCount': 0, - 'totalBpCount': 3, - 'totalConditionsCount': 0, - 'twoYearsBpCount': 2, - 'twoYearsElevatedBpCount': 0, - 'twoYearsMedicationsCount': 0}, - 'sufficientForFastTracking': None} - ), - # Claim for increase, not enough BP readings - ( - { - "evidence": { - "bp_readings": [{"date": "****-11-01", # Date is not formatted correctly - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 115}, - "organization": "LYONS VA MEDICAL CENTER", - "dataSource": "", - "practitioner": "DR. JANE460 DOE922 MD", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 180}}, - {"date": "2020-09-01", - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 110}, - "organization": "LYONS VA MEDICAL CENTER", - "dataSource": "", - "practitioner": "DR. JANE460 DOE922 MD", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 200}}], - "conditions": [], - 'documentsWithoutAnnotationsChecked': ["{guid}"] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "claimSubmissionId": "1234" - }, - {'claimSubmissionDateTime': '2021-11-09T04:00:00Z', - 'claimSubmissionId': '1234', - 'disabilityActionType': 'INCREASE', - 'evidence': {'bp_readings': [{'date': '2020-09-01', - 'dateFormatted': '9/1/2020', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - "dataSource": "", - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200}}], - 'conditions': [], - 'medications': [], - 'documentsWithoutAnnotationsChecked': ['{guid}']}, - 'evidenceSummary': {'allMedicationsCount': 0, - "lighthouseDuplicateBpCount": 0, - 'oneYearBpCount': 0, - 'relevantConditionsLighthouseCount': 0, - 'totalBpCount': 2, - 'totalConditionsCount': 0, - 'twoYearsBpCount': 1, - 'twoYearsElevatedBpCount': 1, - 'twoYearsMedicationsCount': 0}, - 'sufficientForFastTracking': False} - ), - ( - { - "evidence": { - "bp_readings": [{"date": "2020-11-01", - "dataSource": "", - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 115}, - "organization": "LYONS VA MEDICAL CENTER", - "practitioner": "DR. JANE460 DOE922 MD", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 180}}, - {"date": "2020-09-01", - "dataSource": "", - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 110}, - "organization": "LYONS VA MEDICAL CENTER", - "practitioner": "DR. JANE460 DOE922 MD", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 200}}, - {"date": "2020-11-01", - "dataSource": "", - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 115}, - "organization": "LYONS VA MEDICAL CENTER", - "practitioner": "DR. JANE460 DOE922 MD", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 180}}, - {"date": "2020-09-01", - "dataSource": "", - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 110}, - "organization": "LYONS VA MEDICAL CENTER", - "practitioner": "DR. JANE460 DOE922 MD", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 200}}], - "conditions": [] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "claimSubmissionId": "1234" - }, - {'claimSubmissionDateTime': '2021-11-09T04:00:00Z', - 'claimSubmissionId': '1234', - 'disabilityActionType': 'INCREASE', - 'evidence': {'bp_readings': [{'date': '2020-11-01', - 'dateFormatted': '11/1/2020', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - "dataSource": "", - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 180}}, - {'date': '2020-11-01', - 'dateFormatted': '11/1/2020', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - "dataSource": "", - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 180}}, - {'date': '2020-09-01', - 'dateFormatted': '9/1/2020', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - "dataSource": "", - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'date': '2020-09-01', - 'dateFormatted': '9/1/2020', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - "dataSource": "", - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200}}], - 'conditions': [], - 'medications':[], - 'documentsWithoutAnnotationsChecked': []}, - 'evidenceSummary': {'allMedicationsCount': 0, - "lighthouseDuplicateBpCount": 0, - 'oneYearBpCount': 0, - 'relevantConditionsLighthouseCount': 0, - 'totalBpCount': 4, - 'totalConditionsCount': 0, - 'twoYearsBpCount': 4, - 'twoYearsElevatedBpCount': 4, - 'twoYearsMedicationsCount': 0}, - 'sufficientForFastTracking': False} - ), - # Claim for increase - ( - - { - "evidence": { - "bp_readings": [{"date": "2021-08-01", - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 115}, - "organization": "LYONS VA MEDICAL CENTER", - "practitioner": "DR. JANE460 DOE922 MD", - "dataSource": "", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 180}}, - {"date": "2021-09-01", - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 110}, - "organization": "LYONS VA MEDICAL CENTER", - "practitioner": "DR. JANE460 DOE922 MD", - "dataSource": "", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 200}}, - {"date": "2021-11-01", - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 115}, - "organization": "LYONS VA MEDICAL CENTER", - "practitioner": "DR. JANE460 DOE922 MD", - "dataSource": "", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 180}}, - {"date": "2021-10-01", - "diastolic": {"code": "8462-4", - "display": "Diastolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 110}, - "organization": "LYONS VA MEDICAL CENTER", - "practitioner": "DR. JANE460 DOE922 MD", - "dataSource": "", - "systolic": {"code": "8480-6", - "display": "Systolic blood " - "pressure", - "unit": "mm[Hg]", - "value": 200}}], - "medications": [], - "conditions": [] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "claimSubmissionId": "1234" - }, - {'claimSubmissionDateTime': '2021-11-09T04:00:00Z', - 'claimSubmissionId': '1234', - 'disabilityActionType': 'INCREASE', - 'evidence': {'bp_readings': [{'date': '2021-11-01', - 'dateFormatted': '11/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - 'partialDate': '', - "dataSource": "", - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 180}}, - {'date': '2021-10-01', - 'dateFormatted': '10/1/2021', - "dataSource": "", - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'date': '2021-09-01', - 'dateFormatted': '9/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - "dataSource": "", - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200}}, - {'date': '2021-08-01', - 'dateFormatted': '8/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'document': '', - 'organization': 'LYONS VA MEDICAL CENTER', - 'page': '', - "dataSource": "", - 'partialDate': '', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'receiptDate': '', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 180}}], - 'conditions': [], - 'medications': [], - 'documentsWithoutAnnotationsChecked': []}, - 'evidenceSummary': {'allMedicationsCount': 0, - "lighthouseDuplicateBpCount": 0, - 'oneYearBpCount': 4, - 'relevantConditionsLighthouseCount': 0, - 'totalBpCount': 4, - 'totalConditionsCount': 0, - 'twoYearsBpCount': 4, - 'twoYearsElevatedBpCount': 4, - 'twoYearsMedicationsCount': 0}, - 'sufficientForFastTracking': True} - - ), - ( - - { - "evidence": { - "bp_readings": [], - "medications": [], - "conditions": [] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "diagnosticCode": "7101", - "disabilityActionType": "INCREASE", - "claimSubmissionId": "1234" - }, - {'claimSubmissionDateTime': '2021-11-09T04:00:00Z', - 'claimSubmissionId': '1234', - 'disabilityActionType': 'INCREASE', - 'evidence': {'bp_readings': [], 'conditions': [], 'medications': [], 'documentsWithoutAnnotationsChecked': []}, - 'evidenceSummary': {'allMedicationsCount': 0, - "lighthouseDuplicateBpCount": 0, - 'oneYearBpCount': 0, - 'relevantConditionsLighthouseCount': 0, - 'totalBpCount': 0, - 'totalConditionsCount': 0, - 'twoYearsBpCount': 0, - 'twoYearsElevatedBpCount': 0, - 'twoYearsMedicationsCount': 0}, - 'sufficientForFastTracking': False} - ), - # Bad data missing action type - ( - { - "evidence": { - "bp_readings": [], - "conditions": [], - }, - "claimSubmissionId": "1234" - }, - {"errorMessage": "error validating request message data", - "claimSubmissionId": "1234"} - ), - # Bad data: - # - "diastolic" value is string instead of int - # - Medication is an array with a single element *that is an int* rather than string - # - "veteran_is_service_connected_for_dc7101" is a string - ( - { - "evidence": { - "bp_readings": [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": "115" - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 180 - }, - "dataSource": "", - "date": "2021-11-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200 - }, - "dataSource": "", - "date": "2021-09-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - } - ], - "medications": [] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "claimSubmissionId": "1234" - }, - {"errorMessage": "error validating request message data", - "claimSubmissionId": "1234"} - ), - ], -) -def test_main(request_body, response): - """ - Test the function that takes the request and returns the response - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param response: response after running data through algorithms - :type response: dict - """ - api_response = main.assess_sufficiency(request_body) - - assert api_response == response diff --git a/domain-rrd/service-python/tests/assessclaim/dc7101/main_test.py b/domain-rrd/service-python/tests/assessclaim/dc7101/main_test.py deleted file mode 100644 index 09d62334a4..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/dc7101/main_test.py +++ /dev/null @@ -1,266 +0,0 @@ -import pytest -from assessclaimdc7101.src.lib import main - - -@pytest.mark.parametrize( - "request_body, response", - [ - # All three calculator functions return valid results readings - ( - { - "evidence": { - "bp_readings": [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 115, - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 180, - }, - "dataSource": "", - "date": "2021-11-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER", - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110, - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200.0, - }, - "dataSource": "", - "date": "2021-09-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER", - }, - ], - "medications": [ - { - "description": "Capoten", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - } - ], - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "claimSubmissionId": "1234" - }, - {'evidence': {'bp_readings': [{'date': '2021-11-01', - "dataSource": "", - 'dateFormatted': '11/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 115}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 180}}, - {'date': '2021-09-01', - "dataSource": "", - 'dateFormatted': '9/1/2021', - 'diastolic': {'code': '8462-4', - 'display': 'Diastolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 110}, - 'organization': 'LYONS VA MEDICAL CENTER', - 'practitioner': 'DR. JANE460 DOE922 MD', - 'systolic': {'code': '8480-6', - 'display': 'Systolic blood ' - 'pressure', - 'unit': 'mm[Hg]', - 'value': 200.0}}], - 'medications': [{'authoredOn': '1950-04-06T04:00:00Z', - 'description': 'Capoten', - 'status': 'active'}]}, - 'evidenceSummary': {'medicationsCount': 1, - 'recentBpCount': 2, - 'totalBpCount': 2}, - "claimSubmissionId": "1234" - }, - ), - ( - { - "evidence": { - "bp_readings": [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 115, - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 180, - }, - "date": "2020-11-01", - "dataSource": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER", - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110, - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200, - }, - "date": "2020-09-01", - "dataSource": "", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER", - }, - ], - "medications": [], - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "diagnosticCode": "7101", - "claimSubmissionId": "1234" - }, - # Blood pressue readings don't meet date specs - { - "evidence": {"bp_readings": [], "medications": []}, - "evidenceSummary": { - "medicationsCount": 0, - "recentBpCount": 0, - "totalBpCount": 2, - }, - "claimSubmissionId": "1234" - }, - ), - # Sufficiency and history algos fail - ( - { - "evidence": { - "bp_readings": [], - "medications": [], - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "diagnosticCode": "7101", - "claimSubmissionId": "1234" - }, - { - "evidence": {"bp_readings": [], "medications": []}, - "evidenceSummary": { - "medicationsCount": 0, - "recentBpCount": 0, - "totalBpCount": 0, - }, - "claimSubmissionId": "1234" - }, - ), - # Un-readable date - ( - { - "evidence": { - "bp_readings": [], - "medications": [], - }, - "claimSubmissionDateTime": "2021-11-09T04", - "diagnosticCode": "7101", - "claimSubmissionId": "1234" - }, - { - "evidence": {"bp_readings": [], "medications": []}, - "evidenceSummary": { - "medicationsCount": 0, - "recentBpCount": 0, - "totalBpCount": 0, - }, - "claimSubmissionId": "1234" - } - ), - # Bad data: - # - "diastolic" value is string instead of int - # - Medication is an array with a single element *that is an int* rather than string - # - "veteran_is_service_connected_for_dc7101" is a string - ( - { - "evidence": { - "bp_readings": [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": "115", - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 180, - }, - "date": "2021-11-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER", - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 110, - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 200, - }, - "date": "2021-09-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER", - }, - ], - "medications": [{"description": 11}], - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "claimSubmissionId": "1234" - }, - { - "errorMessage": "error validating request message data", - "claimSubmissionId": "1234" - }, - ), - ], -) -def test_main(request_body, response): - """ - Test the function that takes the request and returns the response - - :param request_body: request body with blood pressure readings and other data - :type request_body: dict - :param response: response after running data through algorithms - :type response: dict - """ - api_response = main.assess_hypertension(request_body) - - assert api_response == response diff --git a/domain-rrd/service-python/tests/assessclaim/test_data_model.py b/domain-rrd/service-python/tests/assessclaim/test_data_model.py deleted file mode 100644 index 4140c5adfc..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/test_data_model.py +++ /dev/null @@ -1,110 +0,0 @@ -import pytest -from data_model import validate_request_body - - -@pytest.mark.parametrize( - "request_body, result_is_valid, errors", - [ - ( - { - "evidence": - { - "bp_readings": [ - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 115 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 180 - }, - "date": "2021-11-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - ], - "medications": [{"description": "Capoten", - "status": "active", - "authoredOn": "1950-04-06T04:00:00Z", - "asthmaRelevant": "false"}], - "conditions": [] - }, - "claimSubmissionDateTime": "2021-11-09T04:00:00Z", - "diagnosticCode": "7101", - "veteranIcn": "1234567890V123456", - "disabilityActionType": "NEW" - }, - True, - {} - ), - ( - { - "evidence": { - - "bp_readings": [ - { - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": "180" - }, - "date": "2021-11-01", - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": "115" - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 180 - }, - "date": 20211101, - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - ], - "medications": [{"description": 123}], - "conditions": [] - }, - "claimSubmissionDateTime": 20211109, - "diagnosticCode": "7101", - "disabilityActionType": "NEW" - }, - False, - {'claimSubmissionDateTime': ['must be of string type'], - 'evidence': [{'bp_readings': [{0: [{'diastolic': ['required field'], - 'systolic': [{'value': ['must be of ' - 'number type']}]}], - 1: [{'date': ['must be of string type'], - 'diastolic': [{'value': ['must be of ' - 'number ' - 'type']}]}]}], - 'medications': [{0: [{'description': ['must be of string ' - 'type']}]}]}]} - ), - ], -) -def test_validate_request_body(request_body, result_is_valid, errors): - """ - Test validation of request body - :param request_body: example message - :param result_is_valid: Boolean - :param errors: expected errors from malformed message - :return: - """ - result = validate_request_body(request_body) - assert result["is_valid"] == result_is_valid - assert result["errors"] == errors diff --git a/domain-rrd/service-python/tests/assessclaim/test_queues.py b/domain-rrd/service-python/tests/assessclaim/test_queues.py deleted file mode 100644 index a25f75be19..0000000000 --- a/domain-rrd/service-python/tests/assessclaim/test_queues.py +++ /dev/null @@ -1,91 +0,0 @@ -import json -import logging -from unittest.mock import Mock, patch - -import pytest -from assessclaimcancer.src.lib import queues as qcancer -from assessclaimdc6510.src.lib import queues as q6510 -from assessclaimdc6510.src.lib.main import assess_sinusitis as main6510 -from assessclaimdc6522.src.lib import queues as q6522 -from assessclaimdc6522.src.lib.main import assess_rhinitis as main6522 -from assessclaimdc6602.src.lib import queues as q6602 -from assessclaimdc6602.src.lib.main import assess_asthma as main6602 -from assessclaimdc6602v2.src.lib import queues as q6602v2 -from assessclaimdc6602v2.src.lib.main import \ - assess_sufficiency_asthma as main6602v2 -from assessclaimdc7101.src.lib import queues as q7101 - - -@pytest.mark.parametrize( - "queue, service_queue_name", [ - # V1 - (q7101, "health-assess.hypertension"), - (q6602, "health-assess.asthma"), - # V2 - (q6602v2, "health-sufficiency-assess.asthma"), - (q6522, "health-sufficiency-assess.rhinitis"), - (q6510, "health-sufficiency-assess.sinusitis"), - (qcancer, "health-sufficiency-assess.cancer") - ] -) -def test_queue_setup(queue, service_queue_name, caplog): - channel = Mock(autospec=True, create=True) - with caplog.at_level(logging.INFO): - queue.queue_setup(channel=channel) - - channel.exchange_declare.assert_called_with( - exchange="health-assess-exchange", - exchange_type="direct", - durable=True, - auto_delete=True, - ) - - channel.queue_declare.assert_called_with(queue=service_queue_name, durable=True, auto_delete=True) - channel.queue_bind.assert_called_with( - queue=service_queue_name, exchange="health-assess-exchange" - ) - assert channel.basic_consume - - assert ( - f" [*] Waiting for data for queue: {service_queue_name}. To exit press CTRL+C" - in caplog.text - ) - - -@pytest.mark.parametrize( - "queue, diagnosticCode, body, main", - [ - (q6602, "6602", {"evidence": "some medical data body", - "claimSubmissionId": "1234"}, main6602), - (q6602v2, "6602v2", {"evidence": "some medical data body", - "claimSubmissionId": "1234"}, main6602v2), - (q6510, "6510", {"evidence": "some medical data body", - "claimSubmissionId": "1234"}, main6510), - (q6522, "6522", {"evidence": "some medical data body", - "claimSubmissionId": "1234"}, main6522), - ], -) -def test_on_request_callback(queue, diagnosticCode, body, main, caplog): - channel = Mock(autospec=True, create=True) - method = Mock(autospec=True, create=True) - properties = Mock(autospec=True, create=True) - properties.correlation_id = 1234 - properties.reply_to = "some_queue" - method.routing_key = diagnosticCode - - body_formatted = json.dumps(body).encode("utf-8") - - with caplog.at_level(logging.INFO): - with patch( - f"assessclaimdc{diagnosticCode}.src.lib.main.{main.__name__}", - return_value={"claimSubmissionId": "1234"}, - ): - queue.on_request_callback(channel, method, properties, body_formatted) - - assert ( - f"claimSubmissionId: 1234, health data received by {diagnosticCode}" - in caplog.text - ) - assert ( - f"claimSubmissionId: 1234, evaluation sent by {diagnosticCode}" in caplog.text - ) diff --git a/domain-rrd/service-python/tests/conftest.py b/domain-rrd/service-python/tests/conftest.py deleted file mode 100644 index 21d6ce3129..0000000000 --- a/domain-rrd/service-python/tests/conftest.py +++ /dev/null @@ -1,47 +0,0 @@ -import sys - -import data_model -import utils - - -def data_model_validate_request_body(data): - """Patch for tests""" - - return data_model.validate_request_body(data) - - -module = type(sys)('data_model') -module.validate_request_body = data_model_validate_request_body -sys.modules['data_model'] = module - - -def lib_queues(channel): - """Patch for tests""" - return channel - - -module = type(sys)('lib.queues') -module.queue_setup = lib_queues -sys.modules['lib.queues'] = module - - -def extract_date(date): - """Patch for tests""" - return utils.extract_date(date) - - -def format_date(date): - """Patch for tests""" - return utils.format_date(date) - - -def docs_without_annotations_ids(date): - """Patch for tests""" - return utils.docs_without_annotations_ids(date) - - -module = type(sys)('utils') -module.docs_without_annotations_ids = docs_without_annotations_ids -module.extract_date = extract_date -module.format_date = format_date -sys.modules['utils'] = module diff --git a/domain-rrd/service-python/tests/featuretoggle/__init__.py b/domain-rrd/service-python/tests/featuretoggle/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/tests/featuretoggle/test_queues.py b/domain-rrd/service-python/tests/featuretoggle/test_queues.py deleted file mode 100644 index ffbb98770e..0000000000 --- a/domain-rrd/service-python/tests/featuretoggle/test_queues.py +++ /dev/null @@ -1,33 +0,0 @@ -import logging -from unittest.mock import Mock - -import pytest -from featuretoggle.src.lib import queues - - -@pytest.mark.parametrize( - "queue, toggle_queue_name", [(queues, "feature-toggle-queue")] -) -def test_queue_setup(queue, toggle_queue_name, caplog): - queue_name = f"{toggle_queue_name}" - channel = Mock(autospec=True, create=True) - with caplog.at_level(logging.INFO): - queue.queue_setup(channel=channel) - - channel.exchange_declare.assert_called_with( - exchange="feature-toggle-exchange", - exchange_type="direct", - durable=True, - auto_delete=True, - ) - - channel.queue_declare.assert_called_with(queue=queue_name, durable=True, auto_delete=True) - channel.queue_bind.assert_called_with( - queue=queue_name, exchange="feature-toggle-exchange" - ) - assert channel.basic_consume - - assert ( - f" [*] Waiting for data for queue: {queue_name}. To exit press CTRL+C" - in caplog.text - ) diff --git a/domain-rrd/service-python/tests/featuretoggle/test_redis_client.py b/domain-rrd/service-python/tests/featuretoggle/test_redis_client.py deleted file mode 100644 index c777a242f7..0000000000 --- a/domain-rrd/service-python/tests/featuretoggle/test_redis_client.py +++ /dev/null @@ -1,13 +0,0 @@ -from featuretoggle.src.lib.redis_client import RedisClient - -redis_config = { - "host": "localhost", - "port": 6379, - "retry_limit": 1, - "expiration": 60 * 60 * 3, # 3 hours -} - - -def test_valid_redis_connection(): - redis = RedisClient(redis_config) - assert redis diff --git a/domain-rrd/service-python/tests/featuretoggle/test_settings.py b/domain-rrd/service-python/tests/featuretoggle/test_settings.py deleted file mode 100644 index f2995167e9..0000000000 --- a/domain-rrd/service-python/tests/featuretoggle/test_settings.py +++ /dev/null @@ -1,22 +0,0 @@ -from featuretoggle.src.lib.settings import queue_config, redis_config - -valid_redis = { - "host": "", - "port": "", - "password": "", - "retry_limit": "", - "expiration": "" -} - -valid_queue = { - "exchange_name": "", - "toggle_queue_name": "", -} - - -def test_valid_redis_options(): - assert all(key in valid_redis.keys() for key in redis_config.keys()) - - -def test_valid_queue_options(): - assert all(key in valid_queue.keys() for key in queue_config.keys()) diff --git a/domain-rrd/service-python/tests/pdfgenerator/__init__.py b/domain-rrd/service-python/tests/pdfgenerator/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/domain-rrd/service-python/tests/pdfgenerator/test_pdf_generator.py b/domain-rrd/service-python/tests/pdfgenerator/test_pdf_generator.py deleted file mode 100644 index 759b1aa444..0000000000 --- a/domain-rrd/service-python/tests/pdfgenerator/test_pdf_generator.py +++ /dev/null @@ -1,123 +0,0 @@ -import json -import os -from datetime import datetime -from unittest.mock import patch - -import pytest -from pdfgenerator.src.lib.pdf_generator import PDFGenerator - -lib_dir = os.path.dirname(__file__) - - -@pytest.mark.parametrize("template", ["asthma-v1"]) -def test_default_template_variables(template): - """Test if default values all get added into the template.""" - pdf_generator = PDFGenerator({}) - - default_variables = json.load( - open( - os.path.join( - lib_dir, - f"../../pdfgenerator/src/lib/template_variables/{template}.json", - ) - ) - ) - - generated_variables = pdf_generator.generate_template_variables(template, {}) - - # these variables are only available when the pdf_generator is called so no need to compare - del generated_variables["timestamp"] - del generated_variables["start_date"] - del generated_variables["base_path"] - - # reset this field because it gets turned into a datetime object so it wont match - generated_variables["veteranInfo"]["birthdate"] = default_variables["veteranInfo"]["birthdate"] - - # reset this field because it gets turned into a datetime object so it wont match - generated_variables["veteranInfo"]["birthdate"] = default_variables["veteranInfo"]["birthdate"] - - assert default_variables == generated_variables - - -@pytest.mark.parametrize("template", ["asthma-v1"]) -def test_replaced_template_variables(template): - """Test if the default values get replaced.""" - pdf_generator = PDFGenerator({}) - - first_name = "test" - rabbitmq_data = {"veteranInfo": {"first": first_name, "birthdate": "1935-06-15T00:00:00+00:00"}} - generated_variables = pdf_generator.generate_template_variables( - template, rabbitmq_data - ) - - assert generated_variables["veteranInfo"]["first"] == first_name - - -@pytest.mark.parametrize("template", ["asthma-v1"]) -def test_generate_html_file(template): - """Test if the PDF HTML file gets generated.""" - pdf_generator = PDFGenerator({}) - - generated_variables = pdf_generator.generate_template_variables(template, {}) - html_file = pdf_generator.generate_template_file( - template, generated_variables, True - ) - - document_title = "Rapid Ready for Decision | Claim for Increase" - assert document_title in html_file - - -@pytest.mark.parametrize("template", ["asthma-v1"]) -def test_valid_variables_in_html_file(template): - """Test that the replaced variable appears in the HTML file.""" - pdf_generator = PDFGenerator({}) - - first_name = "test" - rabbitmq_data = {"veteranInfo": {"first": first_name, "birthdate": "1935-06-15T00:00:00+00:00"}} - generated_variables = pdf_generator.generate_template_variables( - template, rabbitmq_data - ) - html_file = pdf_generator.generate_template_file( - template, generated_variables, True - ) - - assert first_name in html_file - - -@pytest.mark.parametrize("template", ["asthma-v1"]) -def test_medication_date_conversion(template): - """Test if 'authoredOn' in 'medications' is a datetime.""" - pdf_generator = PDFGenerator({}) - - rabbitmq_data = {"evidence": {"medications": [{"authoredOn": "1935-06-15T00:00:00+00:00"}]}} - generated_variables = pdf_generator.generate_template_variables( - template, rabbitmq_data - ) - - selected_date = generated_variables["evidence"]["medications"][0]["authoredOn"] - - assert isinstance(selected_date, datetime) - - -@patch("pdfkit.from_string") -@pytest.mark.parametrize("template", ["asthma-v1"]) -def test_pdf_generation(pdfkit_mock, template): - """Test if the generate PDF function gets called.""" - pdf_generator = PDFGenerator({}) - - rabbitmq_data = {"veteranInfo": {"birthdate": "1935-06-15T00:00:00+00:00Z"}} - generated_variables = pdf_generator.generate_template_variables( - template, rabbitmq_data - ) - html_file = pdf_generator.generate_template_file( - template, generated_variables, True - ) - tag = ( - " findAllClaimInfoPage(ClaimInfoQueryParams params) { - int size = params.getSize(); - int page = params.getPage(); - String icn = params.getIcn(); - PageRequest pageRequest = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "updatedAt")); - if (icn == null) { - return claimRepository.findAll(pageRequest); - } else { - return claimRepository.findAllByVeteranIcn(icn, pageRequest); - } - } - - @Override - public ClaimsInfo findAllClaimInfo(ClaimInfoQueryParams params) { - Page claims = findAllClaimInfoPage(params); - List resp = new ArrayList<>(); - for (ClaimEntity claim : claims) { - ClaimInfoResponse info; - if (claim.getVbmsId() != null) { - info = claimInfoResponseMapper.toClaimInfoResponseV2(claim); - } else { - info = claimInfoResponseMapper.toClaimInfoResponseV1(claim); - } - resp.add(info); - } - return new ClaimsInfo(resp, claims.getTotalElements()); - } - - private Page findAllExamOrderInfoPage(ExamOrderInfoQueryParams params) { - int size = params.getSize(); - int page = params.getPage(); - PageRequest pageRequest = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "updatedAt")); - return examOrderRepository.findAll(pageRequest); - } - - @Override - public ExamOrdersInfo findExamOrderInfo(ExamOrderInfoQueryParams params) { - List examOrdersInfo; - if (params.getNotOrdered() == Boolean.TRUE) { - List examOrders = examOrderRepository.findByOrderedAtIsNull(); - examOrdersInfo = examOrderInfoResponseMapper.toExamOrderInfoResponses(examOrders); - } else { - Page examOrders = findAllExamOrderInfoPage(params); - examOrdersInfo = examOrderInfoResponseMapper.toExamOrderInfoResponses(examOrders); - } - return new ExamOrdersInfo(examOrdersInfo, examOrdersInfo.size()); - } - - @Override - public ExamOrdersInfo findExamOrderInfoOlderThan24(ExamOrderInfoQueryParams params) { - List examOrdersInfo; - if (params.getNotOrdered() == Boolean.TRUE) { - LocalDateTime date = LocalDateTime.now().minus(24, ChronoUnit.HOURS); - List examOrders = - examOrderRepository.findByCreatedAtBeforeAndOrderedAtIsNull(date); - examOrdersInfo = examOrderInfoResponseMapper.toExamOrderInfoResponses(examOrders); - } else { - LocalDateTime date = LocalDateTime.now().minus(24, ChronoUnit.HOURS); - List examOrders = examOrderRepository.findByCreatedAtBefore(date); - examOrdersInfo = examOrderInfoResponseMapper.toExamOrderInfoResponses(examOrders); - } - return new ExamOrdersInfo(examOrdersInfo, examOrdersInfo.size()); - } -} diff --git a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/PersistingAuditEventService.java b/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/PersistingAuditEventService.java deleted file mode 100644 index 6508f7c763..0000000000 --- a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/PersistingAuditEventService.java +++ /dev/null @@ -1,22 +0,0 @@ -package gov.va.vro.service.rrd.db; - -import gov.va.vro.model.rrd.event.AuditEvent; -import gov.va.vro.persistence.repository.AuditEventRepository; -import gov.va.vro.service.rrd.db.mapper.AuditEventMapper; -import gov.va.vro.service.spi.audit.AuditEventService; -import lombok.RequiredArgsConstructor; -import org.mapstruct.factory.Mappers; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class PersistingAuditEventService implements AuditEventService { - - private final AuditEventMapper mapper = Mappers.getMapper(AuditEventMapper.class); - private final AuditEventRepository auditEventRepository; - - @Override - public void logEvent(AuditEvent auditEvent) { - auditEventRepository.save(mapper.toEntity(auditEvent)); - } -} diff --git a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/SaveToDbServiceImpl.java b/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/SaveToDbServiceImpl.java deleted file mode 100644 index 9fdadd72c3..0000000000 --- a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/SaveToDbServiceImpl.java +++ /dev/null @@ -1,440 +0,0 @@ -package gov.va.vro.service.rrd.db; - -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.persistence.model.AssessmentResultEntity; -import gov.va.vro.persistence.model.ClaimEntity; -import gov.va.vro.persistence.model.ClaimSubmissionEntity; -import gov.va.vro.persistence.model.ContentionEntity; -import gov.va.vro.persistence.model.EvidenceSummaryDocumentEntity; -import gov.va.vro.persistence.model.ExamOrderEntity; -import gov.va.vro.persistence.model.VeteranEntity; -import gov.va.vro.persistence.model.VeteranFlashIdEntity; -import gov.va.vro.persistence.repository.AssessmentResultRepository; -import gov.va.vro.persistence.repository.ClaimRepository; -import gov.va.vro.persistence.repository.ClaimSubmissionRepository; -import gov.va.vro.persistence.repository.EvidenceSummaryDocumentRepository; -import gov.va.vro.persistence.repository.ExamOrderRepository; -import gov.va.vro.persistence.repository.VeteranRepository; -import gov.va.vro.service.rrd.db.mapper.ClaimMapper; -import gov.va.vro.service.spi.db.SaveToDbService; -import gov.va.vro.service.spi.model.Claim; -import gov.va.vro.service.spi.model.ExamOrder; -import gov.va.vro.service.spi.model.GeneratePdfPayload; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; -import javax.transaction.Transactional; - -@Service -@RequiredArgsConstructor -@Slf4j -public class SaveToDbServiceImpl implements SaveToDbService { - - private final VeteranRepository veteranRepository; - private final ClaimRepository claimRepository; - - private final AssessmentResultRepository assessmentResultRepository; - private final EvidenceSummaryDocumentRepository evidenceSummaryDocumentRepository; - - private final ClaimSubmissionRepository claimSubmissionRepository; - private final ExamOrderRepository examOrderRepository; - private final ClaimMapper mapper; - - @Override - @Transactional - public Claim insertClaim(Claim claim) { - VeteranEntity veteranEntity = - findOrCreateVeteran(claim.getVeteranIcn(), claim.getVeteranParticipantId()); - ClaimEntity claimEntity = null; - - if (claim.getBenefitClaimId() == null) { - // v1 endpoints provide a claimSubmissionId (which is stored as reference_id in - // claim_submission) - // instead of a benefitClaimId (vbmsId) - Optional v1ClaimSubmission = - claimSubmissionRepository.findFirstByReferenceIdAndIdTypeOrderByCreatedAtDesc( - claim.getCollectionId(), claim.getIdType()); - if (v1ClaimSubmission.isPresent()) { - claimEntity = v1ClaimSubmission.get().getClaim(); - } else { - claimEntity = createClaim(claim, veteranEntity); - } - } else { - // v2 endpoints provide a benefitClaimId, and collectionId is the reference_id on - // claimSubmission - claimEntity = - claimRepository - .findByVbmsId(claim.getBenefitClaimId()) - .orElseGet(() -> createClaim(claim, veteranEntity)); - } - - ClaimSubmissionEntity claimSubmissionEntity = createClaimSubmission(claim); - ensureContentionExists( - claimEntity, - claim.getDiagnosticCode(), - claim.getConditionName(), - claim.getDisabilityClassificationCode()); - claimEntity.addClaimSubmission(claimSubmissionEntity); - claimSubmissionRepository.save(claimSubmissionEntity); - claimRepository.save(claimEntity); - claim.setRecordId(claimEntity.getId()); - return claim; - } - - private ClaimSubmissionEntity createClaimSubmission(Claim claim) { - ClaimSubmissionEntity claimSubmission = new ClaimSubmissionEntity(); - // For v1 endpoints, PostClaimRequestMapper maps claimSubmissionId to collectionId - claimSubmission.setReferenceId(claim.getCollectionId()); - claimSubmission.setIdType(claim.getIdType()); - claimSubmission.setIncomingStatus(claim.getIncomingStatus()); - claimSubmission.setSubmissionSource(claim.getSubmissionSource()); - claimSubmission.setSubmissionDate(claim.getSubmissionDate()); - claimSubmission.setOffRampReason(claim.getOffRampReason()); - claimSubmission.setInScope(claim.isInScope()); - return claimSubmission; - } - - @Override - public void insertAssessmentResult( - UUID claimId, AbdEvidenceWithSummary evidenceResponse, String diagnosticCode) { - ClaimEntity claimEntity = claimRepository.findById(claimId).orElse(null); - if (claimEntity == null) { - log.warn("Could not match Claim ID in insertAssessmentResult, exiting."); - return; - } - insertAssessmentResult(claimEntity, evidenceResponse, diagnosticCode); - } - - @Override - public void insertAssessmentResult(AbdEvidenceWithSummary evidence, String diagnosticCode) { - // For v1 endpoints, PostClaimRequestMapper maps claimSubmissionId to referenceId - Optional claimSubmission = - claimSubmissionRepository.findFirstByReferenceIdAndIdTypeOrderByCreatedAtDesc( - evidence.getClaimSubmissionId(), evidence.getIdType()); - if (claimSubmission.isEmpty()) { - log.warn( - "Claim Submission not found for claim submission id = {} and id type = {} to insert assessment result", - evidence.getClaimSubmissionId(), - evidence.getIdType()); - return; - } - ClaimEntity claimEntity = claimSubmission.get().getClaim(); - insertAssessmentResult(claimEntity, evidence, diagnosticCode); - } - - private void insertAssessmentResult( - ClaimEntity claimEntity, AbdEvidenceWithSummary evidenceResponse, String diagnosticCode) { - Map summary = convertMap(evidenceResponse.getEvidenceSummary()); - if (summary == null || summary.isEmpty()) { - log.warn("Evidence Summary is empty, exiting."); - return; - } - AssessmentResultEntity assessmentResultEntity = new AssessmentResultEntity(); - assessmentResultEntity.setEvidenceCountSummary(summary); - assessmentResultEntity.setSufficientEvidenceFlag( - evidenceResponse.getSufficientForFastTracking()); - ContentionEntity contention = findContention(claimEntity, diagnosticCode); - if (contention == null) { - log.warn("Could not match contention with diagnostic code"); - return; - } - contention.addAssessmentResult(assessmentResultEntity); - claimRepository.save(claimEntity); - } - - @Override - public void setOffRampReason(Claim claimWithOffRamp) { - Optional claimSubmission = - claimSubmissionRepository.findFirstByReferenceIdAndIdTypeOrderByCreatedAtDesc( - claimWithOffRamp.getCollectionId(), claimWithOffRamp.getIdType()); - if (claimSubmission.isEmpty()) { - log.info( - "Could not find claimsubmission for claim {} for offramp reason {}.", - claimWithOffRamp.getBenefitClaimId(), - claimWithOffRamp.getOffRampReason()); - return; - } - ClaimSubmissionEntity claimSubmissionEntity = claimSubmission.get(); - claimSubmissionEntity.setOffRampReason(claimWithOffRamp.getOffRampReason()); - claimSubmissionRepository.save(claimSubmissionEntity); - } - - @Override - public void insertEvidenceSummaryDocument(GeneratePdfPayload request, String documentName) { - // For v1 endpoints, ClaimSubmissionId = ClaimSubmission.referenceId - Optional claimSubmission = - claimSubmissionRepository.findFirstByReferenceIdAndIdTypeOrderByCreatedAtDesc( - request.getClaimSubmissionId(), request.getIdType()); - if (claimSubmission.isEmpty()) { - log.warn( - "Could not find claim by claimSubmissionId {} from insert evidence summary document, exiting.", - request.getClaimSubmissionId()); - return; - } - ClaimEntity claim = claimSubmission.get().getClaim(); - ContentionEntity contention = findContention(claim, request.getDiagnosticCode()); - if (contention == null) { - log.warn("Could not match the contention with the claim and diagnostic code, exiting."); - return; - } - Map evidenceCount = fillEvidenceCounts(request); - EvidenceSummaryDocumentEntity esdEntity = new EvidenceSummaryDocumentEntity(); - esdEntity.setEvidenceCount(evidenceCount); - esdEntity.setDocumentName(documentName); - contention.addEvidenceSummaryDocument(esdEntity); - claimRepository.save(claim); - } - - @Override - public void updateEvidenceSummaryDocument(UUID eFolderId, MasAutomatedClaimPayload payload) { - var claim = - claimRepository.findByVbmsId(String.valueOf(payload.getClaimDetail().getBenefitClaimId())); - if (claim.isEmpty()) { - log.error( - "Could not find claim with vbmsId: " - + payload.getClaimDetail().getBenefitClaimId() - + ". Could not attach eFolder ID."); - return; - } - if (eFolderId == null) { - log.error("eFolder ID was null, could not attach to claim."); - } - ClaimEntity claimEntity = claim.get(); - ContentionEntity contentionEntity = findContention(claimEntity, payload.getDiagnosticCode()); - if (contentionEntity != null) { - Optional esd = - evidenceSummaryDocumentRepository.findFirstByContentionIdOrderByCreatedAtDesc( - contentionEntity.getId()); - if (esd.isPresent()) { - EvidenceSummaryDocumentEntity esdEntity = esd.get(); - esdEntity.setFolderId(eFolderId); - esdEntity.setUploadedAt(OffsetDateTime.now()); - evidenceSummaryDocumentRepository.save(esdEntity); - - payload.setEvidenceSummaryDocumentId(esdEntity.getId()); - } else { - log.error( - "Could not find evidence summary document by contentionId: " - + contentionEntity.getId()); - } - } else { - log.error( - "Could not find a contention for this claim: " - + claimEntity.getId() - + " and diagnostic code: " - + payload.getDiagnosticCode()); - } - } - - @Override - @Transactional - public void insertOrUpdateExamOrderingStatus(ExamOrder examOrder) { - ExamOrderEntity examOrderEntity = - examOrderRepository - .findByCollectionId(examOrder.getCollectionId()) - .orElseGet(() -> createExamOrder(examOrder)); - if (null != examOrderEntity) { - examOrderEntity.setStatus(examOrder.getStatus()); - examOrderEntity.setOrderedAt(examOrder.getExamOrderDateTime()); - examOrderRepository.save(examOrderEntity); - } - } - - @Override - public void insertFlashIds(List veteranFlashIds, String veteranIcn) { - var veteran = veteranRepository.findByIcn(veteranIcn); - if (veteran.isEmpty()) { - log.error("Could not find a Veteran with this ICN. Could not attach flash IDs."); - return; - } - if (veteranFlashIds == null) { - log.warn("The Veteran Flash ID list was null, could not attach to Veteran."); - return; - } - VeteranEntity entity = veteran.get(); - List flashIdList = createFlashIds(veteranFlashIds, entity); - entity.setFlashIds(flashIdList); - veteranRepository.save(entity); - } - - @Override - public void updateRfdFlag(String benefitClaimId, boolean rfdFlag) { - var claim = claimRepository.findByVbmsId(benefitClaimId); - if (claim.isEmpty()) { - log.error("Could not find claim with id and idType, could not update RFD flag."); - return; - } - ClaimEntity claimEntity = claim.get(); - claimEntity.setRfdFlag(rfdFlag); - claimRepository.save(claimEntity); - } - - @Override - public void updateSufficientEvidenceFlag(AbdEvidenceWithSummary evidence, String diagnosticCode) { - // For v1 endpoints, ClaimSubmissionId = ClaimSubmission.referenceId - Optional claimSubmission = - claimSubmissionRepository.findFirstByReferenceIdAndIdTypeOrderByCreatedAtDesc( - evidence.getClaimSubmissionId(), evidence.getIdType()); - if (claimSubmission.isEmpty()) { - log.error( - "Claim Submission not found for claim submission id = {} and id type = {} in update sufficient evidence flag", - evidence.getClaimSubmissionId(), - evidence.getIdType()); - return; - } - ClaimEntity claim = claimSubmission.get().getClaim(); - ContentionEntity contention = findContention(claim, diagnosticCode); - if (contention == null) { - log.error("Could not find contention with given diagnostic code."); - return; - } - Optional result = - assessmentResultRepository.findFirstByContentionIdOrderByCreatedAtDesc(contention.getId()); - if (result.isEmpty()) { - log.error("Could not match assessment result to this contention id."); - return; - } - if (evidence.getEvidence() == null) { - log.error("No evidence."); - } - AssessmentResultEntity assessmentResult = result.get(); - assessmentResult.setSufficientEvidenceFlag(evidence.getSufficientForFastTracking()); - assessmentResultRepository.save(assessmentResult); - } - - private List createFlashIds( - List veteranFlashIds, VeteranEntity entity) { - List flashIdList = new ArrayList<>(); - for (String flashId : veteranFlashIds) { - VeteranFlashIdEntity id = new VeteranFlashIdEntity(); - id.setFlashId(flashId); - id.setVeteran(entity); - flashIdList.add(id); - } - return flashIdList; - } - - private Map fillEvidenceCounts(GeneratePdfPayload request) { - AbdEvidence evidence = request.getEvidence(); - Map evidenceCount = new HashMap<>(); - if (evidence.getBloodPressures() != null) { - evidenceCount.put("totalBpReadings", String.valueOf(evidence.getBloodPressures().size())); - } - if (evidence.getMedications() != null) { - evidenceCount.put("medicationsCount", String.valueOf(evidence.getMedications().size())); - } - if (evidence.getProcedures() != null) { - evidenceCount.put("proceduresCount", String.valueOf(evidence.getProcedures().size())); - } - return evidenceCount; - } - - private Map convertMap(Map summary) { - if (summary == null) { - return null; - } - Map result = new HashMap<>(); - for (Map.Entry entry : summary.entrySet()) { - Object value = entry.getValue(); - if (value != null) { - result.put(entry.getKey(), value.toString()); - } - } - return result; - } - - private ContentionEntity ensureContentionExists( - ClaimEntity claim, - String diagnosticCode, - String conditionName, - String disabilityClassificationCode) { - var contention = findContention(claim, diagnosticCode); - if (contention == null) { - contention = - createContention(claim, diagnosticCode, conditionName, disabilityClassificationCode); - claimRepository.save(claim); - } - return contention; - } - - private ContentionEntity findContention(ClaimEntity claim, String diagnosticCode) { - for (ContentionEntity contention : claim.getContentions()) { - if (contention.getDiagnosticCode().equals(diagnosticCode)) { - return contention; - } - } - return null; - } - - private ClaimEntity createClaim(Claim claim, VeteranEntity veteranEntity) { - ClaimEntity claimEntity = mapper.toClaimEntity(claim); - claimEntity.setVeteran(veteranEntity); - createContention( - claimEntity, - claim.getDiagnosticCode(), - claim.getConditionName(), - claim.getDisabilityClassificationCode()); - return claimRepository.save(claimEntity); - } - - private ExamOrderEntity createExamOrder(ExamOrder examOrder) { - // Currently ExamOrders only come from MAS or after VRO successfully requests an exam order from - // MAS - Optional claimSubmission = - claimSubmissionRepository.findFirstByReferenceIdAndIdTypeOrderByCreatedAtDesc( - examOrder.getCollectionId(), examOrder.getIdType()); - ExamOrderEntity examOrderEntity = new ExamOrderEntity(); - examOrderEntity.setCollectionId(examOrder.getCollectionId()); - examOrderEntity.setStatus(examOrder.getStatus()); - examOrderEntity.setOrderedAt(examOrder.getExamOrderDateTime()); - if (claimSubmission.isEmpty()) { - log.error( - "Could not find claim submission for collection id {}, will not save connection to exam order.", - examOrder.getCollectionId()); - } else { - examOrderEntity.setClaimSubmission(claimSubmission.get()); - } - return examOrderRepository.save(examOrderEntity); - } - - private ContentionEntity createContention( - ClaimEntity claim, - String diagnosticCode, - String conditionName, - String disabilityClassificationCode) { - ContentionEntity contentionEntity = new ContentionEntity(); - contentionEntity.setDiagnosticCode(diagnosticCode); - contentionEntity.setConditionName(conditionName); - contentionEntity.setClassificationCode(disabilityClassificationCode); - claim.addContention(contentionEntity); - return contentionEntity; - } - - private VeteranEntity findOrCreateVeteran(String veteranIcn, String veteranParticipantId) { - VeteranEntity veteranEntity = - veteranRepository - .findByIcn(veteranIcn) - .orElseGet(() -> createVeteran(veteranIcn, veteranParticipantId)); - Date date = new Date(); - veteranEntity.setIcnTimestamp(date); - return veteranRepository.save(veteranEntity); - } - - private VeteranEntity createVeteran(String veteranIcn, String veteranParticipantId) { - VeteranEntity veteranEntity = new VeteranEntity(); - veteranEntity.setIcn(veteranIcn); - veteranEntity.setParticipantId(veteranParticipantId); - return veteranRepository.save(veteranEntity); - } -} diff --git a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/AssessmentInfoMapper.java b/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/AssessmentInfoMapper.java deleted file mode 100644 index e87642b7bd..0000000000 --- a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/AssessmentInfoMapper.java +++ /dev/null @@ -1,13 +0,0 @@ -package gov.va.vro.service.rrd.db.mapper; - -import gov.va.vro.model.rrd.claimmetrics.AssessmentInfo; -import gov.va.vro.persistence.model.AssessmentResultEntity; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.ReportingPolicy; - -@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) -public interface AssessmentInfoMapper { - @Mapping(target = "evidenceInfo", source = "evidenceCountSummary") - AssessmentInfo toAssessmentInfo(AssessmentResultEntity assessmentResultEntity); -} diff --git a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/AuditEventMapper.java b/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/AuditEventMapper.java deleted file mode 100644 index 12df09481e..0000000000 --- a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/AuditEventMapper.java +++ /dev/null @@ -1,23 +0,0 @@ -package gov.va.vro.service.rrd.db.mapper; - -import gov.va.vro.model.rrd.event.AuditEvent; -import gov.va.vro.persistence.model.AuditEventEntity; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.ReportingPolicy; - -@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) -public interface AuditEventMapper { - - @Mapping(target = "message", expression = "java(String.join(\", \",auditEvent.getMessages()))") - AuditEventEntity toEntity(AuditEvent auditEvent); - - default String className(Class source) { - return source.getSimpleName(); - } - - default String exceptionTrace(Throwable throwable) { - return throwable == null ? null : ExceptionUtils.getStackTrace(throwable); - } -} diff --git a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ClaimInfoResponseMapper.java b/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ClaimInfoResponseMapper.java deleted file mode 100644 index 1114cb23b5..0000000000 --- a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ClaimInfoResponseMapper.java +++ /dev/null @@ -1,68 +0,0 @@ -package gov.va.vro.service.rrd.db.mapper; - -import gov.va.vro.model.rrd.claimmetrics.response.ClaimInfoResponse; -import gov.va.vro.persistence.model.ClaimEntity; -import gov.va.vro.persistence.model.ClaimSubmissionEntity; -import org.mapstruct.InjectionStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.ReportingPolicy; - -@Mapper( - componentModel = "spring", - unmappedTargetPolicy = ReportingPolicy.IGNORE, - uses = ContentionInfoMapper.class, - injectionStrategy = InjectionStrategy.CONSTRUCTOR) -public interface ClaimInfoResponseMapper { - - // Mapper for v1 claims. - @Mapping(target = "veteranIcn", source = "veteran.icn") - @Mapping( - target = "claimSubmissionId", - expression = - "java(claimSubmissionsEntitySetToClaimSubmissionId(claimEntity.getClaimSubmissions()))") - @Mapping( - target = "idType", - expression = "java(claimSubmissionsEntitySetToIdType(claimEntity.getClaimSubmissions()))") - ClaimInfoResponse toClaimInfoResponseV1(ClaimEntity claimEntity); - - // Mapper for v2 claims. - @Mapping(target = "veteranIcn", source = "veteran.icn") - @Mapping( - target = "claimSubmissionId", - expression = - "java(claimSubmissionsEntitySetToBenefitClaimId(claimEntity.getClaimSubmissions()))") - @Mapping( - target = "idType", - expression = "java(claimSubmissionsEntitySetToIdType(claimEntity.getClaimSubmissions()))") - @Mapping( - target = "collectionId", - expression = - "java(claimSubmissionsEntitySetToCollectionId(claimEntity.getClaimSubmissions()))") - ClaimInfoResponse toClaimInfoResponseV2(ClaimEntity claimEntity); - - // List toClaimInfoResponses(Iterable claimEntities); - - // Custom mapper to handle new claim_submission table. The reference_id in claim submission is - // equal to claimSubmissionId to external systems. - default String claimSubmissionsEntitySetToClaimSubmissionId( - Iterable claimSubmissionEntities) { - return claimSubmissionEntities.iterator().next().getReferenceId(); - } - - // Sets the claimInfoResponses claimSubmissionId to VBMS ID(aka benefit claim ID) for v2 claims. - default String claimSubmissionsEntitySetToBenefitClaimId( - Iterable claimSubmissionEntities) { - return claimSubmissionEntities.iterator().next().getClaim().getVbmsId(); - } - - default String claimSubmissionsEntitySetToCollectionId( - Iterable claimSubmissionEntities) { - return claimSubmissionEntities.iterator().next().getReferenceId(); - } - - default String claimSubmissionsEntitySetToIdType( - Iterable claimSubmissionEntities) { - return claimSubmissionEntities.iterator().next().getIdType(); - } -} diff --git a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ClaimMapper.java b/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ClaimMapper.java deleted file mode 100644 index 199633246e..0000000000 --- a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ClaimMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package gov.va.vro.service.rrd.db.mapper; - -import gov.va.vro.persistence.model.ClaimEntity; -import gov.va.vro.persistence.model.ContentionEntity; -import gov.va.vro.service.spi.model.Claim; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.ReportingPolicy; - -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) -public interface ClaimMapper { - - @Mapping(target = "contentions", ignore = true) - @Mapping(target = "vbmsId", source = "benefitClaimId") - ClaimEntity toClaimEntity(Claim claim); - - @Mapping(target = "recordId", source = "id") - @Mapping(target = "veteranIcn", source = "veteran.icn") - @Mapping(target = "benefitClaimId", source = "vbmsId") - Claim toClaim(ClaimEntity claimEntity); - - /*** - *

    Maps list of contention entities to a set of strings.

    - * - * @param contentionEntities contention entities - * @return return set of strings - */ - default Set toContentionSet(List contentionEntities) { - return contentionEntities.stream() - .map(ContentionEntity::getDiagnosticCode) - .collect(Collectors.toSet()); - } -} diff --git a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ContentionInfoMapper.java b/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ContentionInfoMapper.java deleted file mode 100644 index 02d5dc8299..0000000000 --- a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ContentionInfoMapper.java +++ /dev/null @@ -1,19 +0,0 @@ -package gov.va.vro.service.rrd.db.mapper; - -import gov.va.vro.model.rrd.claimmetrics.ContentionInfo; -import gov.va.vro.persistence.model.ContentionEntity; -import org.mapstruct.InjectionStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.ReportingPolicy; - -@Mapper( - componentModel = "spring", - unmappedTargetPolicy = ReportingPolicy.IGNORE, - uses = {AssessmentInfoMapper.class, DocumentInfoMapper.class}, - injectionStrategy = InjectionStrategy.CONSTRUCTOR) -public interface ContentionInfoMapper { - @Mapping(target = "assessments", source = "assessmentResults") - @Mapping(target = "documents", source = "evidenceSummaryDocuments") - ContentionInfo toContentionInfo(ContentionEntity contentionEntity); -} diff --git a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/DocumentInfoMapper.java b/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/DocumentInfoMapper.java deleted file mode 100644 index c0106cfdb6..0000000000 --- a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/DocumentInfoMapper.java +++ /dev/null @@ -1,13 +0,0 @@ -package gov.va.vro.service.rrd.db.mapper; - -import gov.va.vro.model.rrd.claimmetrics.DocumentInfo; -import gov.va.vro.persistence.model.EvidenceSummaryDocumentEntity; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.ReportingPolicy; - -@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) -public interface DocumentInfoMapper { - @Mapping(target = "evidenceInfo", source = "evidenceCount") - DocumentInfo toAssessmentInfo(EvidenceSummaryDocumentEntity entity); -} diff --git a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ExamOrderInfoResponseMapper.java b/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ExamOrderInfoResponseMapper.java deleted file mode 100644 index 1609cf27b0..0000000000 --- a/domain-rrd/service-rrd-db/src/main/java/gov/va/vro/service/rrd/db/mapper/ExamOrderInfoResponseMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package gov.va.vro.service.rrd.db.mapper; - -import gov.va.vro.model.rrd.claimmetrics.response.ExamOrderInfoResponse; -import gov.va.vro.persistence.model.ExamOrderEntity; -import org.mapstruct.InjectionStrategy; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.ReportingPolicy; - -import java.time.LocalDateTime; -import java.time.OffsetDateTime; -import java.util.List; - -@Mapper( - componentModel = "spring", - unmappedTargetPolicy = ReportingPolicy.IGNORE, - uses = ContentionInfoMapper.class, - injectionStrategy = InjectionStrategy.CONSTRUCTOR) -public interface ExamOrderInfoResponseMapper { - - @Mapping( - target = "hasAssociatedClaimSubmission", - expression = "java(examOrderEntity.getClaimSubmission() != null)") - @Mapping( - target = "orderedAt", - expression = "java(convertOrderedAt(examOrderEntity.getOrderedAt()))") - ExamOrderInfoResponse toExamOrderInfoResponse(ExamOrderEntity examOrderEntity); - - List toExamOrderInfoResponses(Iterable examOrderEntities); - - default LocalDateTime convertOrderedAt(OffsetDateTime offsetOrdered) { - if (offsetOrdered != null) { - return offsetOrdered.toLocalDateTime(); - } - return null; - } -} diff --git a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/ClaimMetricsServiceImplTest.java b/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/ClaimMetricsServiceImplTest.java deleted file mode 100644 index 64a8df538c..0000000000 --- a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/ClaimMetricsServiceImplTest.java +++ /dev/null @@ -1,169 +0,0 @@ -package gov.va.vro.service.rrd.db; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import gov.va.vro.model.rrd.claimmetrics.ClaimInfoQueryParams; -import gov.va.vro.model.rrd.claimmetrics.ClaimsInfo; -import gov.va.vro.model.rrd.claimmetrics.ExamOrderInfoQueryParams; -import gov.va.vro.model.rrd.claimmetrics.ExamOrdersInfo; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimInfoResponse; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimMetricsResponse; -import gov.va.vro.model.rrd.claimmetrics.response.ExamOrderInfoResponse; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.persistence.repository.ClaimRepository; -import gov.va.vro.persistence.repository.ClaimSubmissionRepository; -import gov.va.vro.service.rrd.db.util.ClaimMetricsTestCase; -import gov.va.vro.service.spi.model.Claim; -import gov.va.vro.service.spi.model.ExamOrder; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.transaction.annotation.Transactional; - -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.stream.IntStream; - -@SpringBootTest(classes = TestConfig.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) -@Transactional -@ActiveProfiles("test") -@EnableJpaAuditing -public class ClaimMetricsServiceImplTest { - - @Autowired private ClaimMetricsServiceImpl claimMetricsService; - - @Autowired private SaveToDbServiceImpl saveToDbService; - - @Autowired private ClaimRepository claimRepository; - - @Autowired private ClaimSubmissionRepository claimSubmissionRepository; - - private void verifyFindAllClaimInfo( - ClaimInfoQueryParams params, List cases) { - int size = params.getSize(); - int page = params.getPage(); - assertTrue(size > 0); - ClaimsInfo claimsInfo = claimMetricsService.findAllClaimInfo(params); - assertEquals(cases.size(), claimsInfo.getTotal()); - List responses = claimsInfo.getClaimInfoList(); - int expectedResponseSize = - cases.size() < (page + 1) * size ? (page + 1) * size - cases.size() : size; - assertEquals(expectedResponseSize, responses.size()); - IntStream.range(0, expectedResponseSize) - .forEach( - index -> { - ClaimInfoResponse cir = responses.get(index); - ClaimMetricsTestCase c = cases.get(index + page * size); - c.verifyClaimInfoResponse(cir); - }); - } - - private void verifyHappyPathClaimMetrics(int expectedSize) { - ClaimMetricsResponse actual = claimMetricsService.getClaimMetrics(); - ClaimMetricsResponse expected = - new ClaimMetricsResponse(expectedSize, expectedSize, expectedSize); - assertEquals(expected, actual); - } - - @Test - void testAllMethodsHappyPath() { - List cases = - IntStream.range(0, 15).boxed().map(i -> ClaimMetricsTestCase.getInstance()).toList(); - - List secondClaimCases = - cases.stream().limit(5).map(ClaimMetricsTestCase::newCaseForSameVeteran).toList(); - List thirdClaimCases = - cases.stream().limit(2).map(ClaimMetricsTestCase::newCaseForSameVeteran).toList(); - - List allCases = new ArrayList<>(cases); - allCases.addAll(secondClaimCases); - allCases.addAll(thirdClaimCases); - - verifyHappyPathClaimMetrics(0); - allCases.forEach(c -> c.populate(saveToDbService, claimSubmissionRepository)); - verifyHappyPathClaimMetrics(22); - - // The test populate method uses v1 for the claim id Type - allCases.forEach( - c -> { - String claimSubmissionId = c.getClaimSubmissionId(); - ClaimInfoResponse cir = - claimMetricsService.findClaimInfo(claimSubmissionId, Claim.V1_ID_TYPE); - c.verifyClaimInfoResponse(cir); - }); - // Reverse the icnCases to get the last updated claims for that ICN. - List icnCases = - new ArrayList<>(IntStream.of(1, 16, 21).boxed().map(allCases::get).toList()); - String icn = allCases.get(21).getIcn(); - - // We expect the results to be in order of last updated. - Collections.reverse(icnCases); - ClaimInfoQueryParams params0 = ClaimInfoQueryParams.builder().size(2).icn(icn).build(); - verifyFindAllClaimInfo(params0, icnCases); - - ClaimInfoQueryParams params1 = ClaimInfoQueryParams.builder().page(1).size(2).icn(icn).build(); - verifyFindAllClaimInfo(params1, icnCases); - - // We expect the results to be in order of last updated. - Collections.reverse(allCases); - - ClaimInfoQueryParams params2 = ClaimInfoQueryParams.builder().build(); - verifyFindAllClaimInfo(params2, allCases); - - ClaimInfoQueryParams params3 = ClaimInfoQueryParams.builder().size(7).page(1).build(); - verifyFindAllClaimInfo(params3, allCases); - } - - @Test - void testFindClaimInfoInvalidId() { - // Put something in the database so that it is not empty - ClaimMetricsTestCase testCase = ClaimMetricsTestCase.getInstance(); - testCase.populate(saveToDbService, claimSubmissionRepository); - - ClaimInfoResponse cir = claimMetricsService.findClaimInfo("not_id", Claim.V1_ID_TYPE); - assertNull(cir); - } - - @Test - void testFindExamOrderInfo() { - OffsetDateTime examTime = OffsetDateTime.now(); - ExamOrder testExamOrder = new ExamOrder(); - testExamOrder.setCollectionId("123"); - testExamOrder.setIdType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - testExamOrder.setExamOrderDateTime(examTime); - saveToDbService.insertOrUpdateExamOrderingStatus(testExamOrder); - - ExamOrder examOrderNoTimeStamp = new ExamOrder(); - examOrderNoTimeStamp.setCollectionId("124"); - examOrderNoTimeStamp.setIdType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - saveToDbService.insertOrUpdateExamOrderingStatus(examOrderNoTimeStamp); - - ExamOrderInfoQueryParams params = ExamOrderInfoQueryParams.builder().build(); - ExamOrdersInfo eoir = claimMetricsService.findExamOrderInfo(params); - List examOrderResponses = eoir.getExamOrderInfoList(); - - ExamOrderInfoQueryParams notOrderedParams = new ExamOrderInfoQueryParams(0, 10, Boolean.TRUE); - ExamOrdersInfo examsNotOrdered = claimMetricsService.findExamOrderInfo(notOrderedParams); - List examsNotOrderedResponses = examsNotOrdered.getExamOrderInfoList(); - - assertEquals(2, examOrderResponses.size()); - assertEquals( - examOrderNoTimeStamp.getCollectionId(), examOrderResponses.get(0).getCollectionId()); - assertNull(examOrderResponses.get(0).getOrderedAt()); - assertFalse(examOrderResponses.get(0).isHasAssociatedClaimSubmission()); - assertEquals(testExamOrder.getCollectionId(), examOrderResponses.get(1).getCollectionId()); - assertNotNull(examOrderResponses.get(1).getOrderedAt()); - assertFalse(examOrderResponses.get(0).isHasAssociatedClaimSubmission()); - assertEquals(1, examsNotOrderedResponses.size()); - assertEquals( - examOrderNoTimeStamp.getCollectionId(), examsNotOrderedResponses.get(0).getCollectionId()); - } -} diff --git a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/SaveToDbServiceImplTest.java b/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/SaveToDbServiceImplTest.java deleted file mode 100644 index 384c855bb6..0000000000 --- a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/SaveToDbServiceImplTest.java +++ /dev/null @@ -1,298 +0,0 @@ -package gov.va.vro.service.rrd.db; - -import static org.junit.jupiter.api.Assertions.*; - -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.model.rrd.mas.MasAutomatedClaimPayload; -import gov.va.vro.persistence.model.*; -import gov.va.vro.persistence.repository.*; -import gov.va.vro.service.spi.model.Claim; -import gov.va.vro.service.spi.model.ExamOrder; -import gov.va.vro.service.spi.model.GeneratePdfPayload; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.core.io.Resource; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.transaction.annotation.Transactional; - -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.*; - -@SpringBootTest(classes = TestConfig.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) -@Transactional -@ActiveProfiles("test") -@EnableJpaAuditing -class SaveToDbServiceImplTest { - - @Autowired private SaveToDbServiceImpl saveToDbService; - - @Autowired private VeteranRepository veteranRepository; - - @Autowired private ClaimRepository claimRepository; - - @Autowired private ClaimSubmissionRepository claimSubmissionRepository; - - @Autowired private AssessmentResultRepository assessmentResultRepository; - - @Autowired private ExamOrderRepository examOrderRepository; - - @Value("classpath:test-data/evidence-summary-document-data.json") - private Resource esdData; - - @Test - void persistClaimWithV1Data() { - Claim claim = new Claim(); - claim.setCollectionId("collection1"); - claim.setIdType(Claim.V1_ID_TYPE); - claim.setVeteranIcn("v1"); - claim.setDiagnosticCode("1234"); - var result = saveToDbService.insertClaim(claim); - assertNotNull(result.getRecordId()); - // Both of these values should be null, and it should be equal in a v1 path. - assertEquals(claim.getBenefitClaimId(), result.getBenefitClaimId()); - assertEquals(claim.getIdType(), result.getIdType()); - assertEquals(claim.getDiagnosticCode(), result.getDiagnosticCode()); - assertEquals(claim.getVeteranIcn(), result.getVeteranIcn()); - assertEquals(claim.getIncomingStatus(), result.getIncomingStatus()); - - assertEquals(1, veteranRepository.findAll().size()); - assertEquals(1, claimRepository.findAll().size()); - - ClaimSubmissionEntity claimSubmissionEntity = - claimSubmissionRepository - .findFirstByReferenceIdAndIdTypeOrderByCreatedAtDesc( - claim.getCollectionId(), Claim.V1_ID_TYPE) - .orElseThrow(); - ClaimEntity claimEntity = claimSubmissionEntity.getClaim(); - - assertEquals(claim.getVeteranIcn(), claimEntity.getVeteran().getIcn()); - assertNull(claimEntity.getVeteran().getParticipantId()); - assertEquals(1, claimEntity.getContentions().size()); - ContentionEntity contentionEntity = claimEntity.getContentions().get(0); - assertEquals(claim.getDiagnosticCode(), contentionEntity.getDiagnosticCode()); - assertEquals(1, claimEntity.getClaimSubmissions().size()); - ClaimSubmissionEntity submissionsOnClaim = claimEntity.getClaimSubmissions().iterator().next(); - assertNotNull(submissionsOnClaim); - assertEquals(claim.getCollectionId(), submissionsOnClaim.getReferenceId()); - assertEquals(claim.getIdType(), submissionsOnClaim.getIdType()); - } - - @Test - void persistClaimWithV2Data() { - Claim claim = new Claim(); - claim.setBenefitClaimId("claim1"); // Not the same as our claim submission id. - claim.setCollectionId("collection1"); - claim.setIdType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - claim.setVeteranIcn("v1"); - claim.setVeteranParticipantId("vPID1"); - claim.setDiagnosticCode("1234"); - claim.setConditionName("Condition1"); - claim.setDisabilityClassificationCode("DCC1"); - var result = saveToDbService.insertClaim(claim); - assertNotNull(result.getRecordId()); - assertEquals(claim.getBenefitClaimId(), result.getBenefitClaimId()); - assertEquals(claim.getIdType(), result.getIdType()); - assertEquals(claim.getDiagnosticCode(), result.getDiagnosticCode()); - assertEquals(claim.getVeteranIcn(), result.getVeteranIcn()); - assertEquals(claim.getIncomingStatus(), result.getIncomingStatus()); - - assertEquals(1, veteranRepository.findAll().size()); - assertEquals(1, claimRepository.findAll().size()); - ClaimEntity claimEntity = claimRepository.findByVbmsId(claim.getBenefitClaimId()).orElseThrow(); - assertEquals(claim.getBenefitClaimId(), claimEntity.getVbmsId()); - assertEquals(claim.getVeteranIcn(), claimEntity.getVeteran().getIcn()); - assertEquals(claim.getVeteranParticipantId(), claimEntity.getVeteran().getParticipantId()); - assertEquals(1, claimEntity.getContentions().size()); - ContentionEntity contentionEntity = claimEntity.getContentions().get(0); - assertEquals(claim.getDiagnosticCode(), contentionEntity.getDiagnosticCode()); - assertEquals(claim.getConditionName(), contentionEntity.getConditionName()); - assertEquals(claim.getDisabilityClassificationCode(), contentionEntity.getClassificationCode()); - assertEquals(1, claimEntity.getClaimSubmissions().size()); - ClaimSubmissionEntity claimSubmissionEntity = - claimEntity.getClaimSubmissions().iterator().next(); - assertNotNull(claimSubmissionEntity); - assertEquals(claim.getCollectionId(), claimSubmissionEntity.getReferenceId()); - assertEquals(claim.getIdType(), claimSubmissionEntity.getIdType()); - } - - @Test - void persistAssessmentResult() throws Exception { - // Save claim - Claim claim = new Claim(); - claim.setBenefitClaimId("1234"); - claim.setIdType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - claim.setVeteranIcn("v1"); - claim.setDiagnosticCode("7101"); - saveToDbService.insertClaim(claim); - ClaimEntity claimBeforeAssessment = claimRepository.findByVbmsId("1234").orElseThrow(); - Map evidenceMap = new HashMap<>(); - evidenceMap.put("medicationsCount", "10"); - AbdEvidenceWithSummary evidence = new AbdEvidenceWithSummary(); - evidence.setIdType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - evidence.setEvidenceSummary(evidenceMap); - evidence.setSufficientForFastTracking(false); - saveToDbService.insertAssessmentResult(claimBeforeAssessment.getId(), evidence, "7101"); - ClaimEntity result = claimRepository.findByVbmsId("1234").orElseThrow(); - assertNotNull(result); - assertNotNull(result.getContentions().get(0).getAssessmentResults().get(0)); - AssessmentResultEntity assessmentResult = - result.getContentions().get(0).getAssessmentResults().get(0); - assertEquals(assessmentResult.getEvidenceCountSummary(), evidenceMap); - assertEquals(assessmentResult.getSufficientEvidenceFlag(), false); - - long c = assessmentResultRepository.count(); - assertEquals(1, c); - } - - @Test - void persistOffRampReason() { - String vbmsId = "1234"; - Claim claim = new Claim(); - claim.setBenefitClaimId(vbmsId); - claim.setCollectionId("collection1"); - claim.setIdType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - claim.setVeteranIcn("v1"); - claim.setDiagnosticCode("7101"); - saveToDbService.insertClaim(claim); - ClaimEntity result1 = claimRepository.findByVbmsId(vbmsId).orElseThrow(); - assertNotNull(result1); - Set csEntities = result1.getClaimSubmissions(); - assertEquals(1, csEntities.size()); - ClaimSubmissionEntity claimSubmission1 = csEntities.iterator().next(); - assertNull(claimSubmission1.getOffRampReason()); - claim.setOffRampReason("OffRampReason1"); - saveToDbService.setOffRampReason(claim); - ClaimEntity result2 = claimRepository.findByVbmsId(vbmsId).orElseThrow(); - assertNotNull(result2); - Set csEntities2 = result2.getClaimSubmissions(); - assertEquals(1, csEntities2.size()); - ClaimSubmissionEntity claimSubmission2 = csEntities.iterator().next(); - assertEquals(claim.getOffRampReason(), claimSubmission2.getOffRampReason()); - } - - @Test - void persistEvidenceSummaryDocument() throws Exception { - // Save claim - String vbmsId = "787878"; - Claim claim = new Claim(); - claim.setBenefitClaimId(vbmsId); - claim.setIdType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - claim.setCollectionId("1234"); // Match claimSubmissionId in esdData.getInputStream - claim.setVeteranIcn("v1"); - claim.setDiagnosticCode("7101"); - saveToDbService.insertClaim(claim); - // Build evidence - InputStream stream = esdData.getInputStream(); - String inputAsString = new String(stream.readAllBytes(), StandardCharsets.UTF_8); - ObjectMapper mapper = new ObjectMapper(); - GeneratePdfPayload input = mapper.readValue(inputAsString, GeneratePdfPayload.class); - // Payload gives us claimsubmissionId which is the same as the reference_id on the claim - // submission table. Type should match the previously submitted claim. This is normally set by - // the endpoint processing. - input.setIdType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - String diagnosis = "Hypertension"; - String documentName = GeneratePdfPayload.createPdfFilename(diagnosis); - // Save evidence summary document. - saveToDbService.insertEvidenceSummaryDocument(input, documentName); - ClaimEntity result = claimRepository.findByVbmsId(vbmsId).orElseThrow(); - // Verify evidence is correct - assertNotNull(result); - EvidenceSummaryDocumentEntity esd = - result.getContentions().get(0).getEvidenceSummaryDocuments().get(0); - assertNotNull(esd); - assertEquals(esd.getDocumentName(), documentName); - assertEquals(esd.getEvidenceCount().size(), 2); - } - - @Test - void persistExamOrder() { - Claim claim = new Claim(); - claim.setBenefitClaimId("1234"); - claim.setVeteranIcn("v1"); - claim.setDiagnosticCode("7101"); - claim.setCollectionId("collection1"); - claim.setIdType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE); - saveToDbService.insertClaim(claim); - Optional claimSubmission = - claimSubmissionRepository.findFirstByReferenceIdAndIdTypeOrderByCreatedAtDesc( - claim.getCollectionId(), claim.getIdType()); - assert (claimSubmission.isPresent()); - ClaimSubmissionEntity claimSubmissionEntity = claimSubmission.get(); - ExamOrder examOrder1 = new ExamOrder(); - examOrder1.setCollectionId("collection1"); - examOrder1.setIdType(claim.getIdType()); - examOrder1.setStatus("status1"); - saveToDbService.insertOrUpdateExamOrderingStatus(examOrder1); - Optional orderEntity = - examOrderRepository.findByCollectionId(examOrder1.getCollectionId()); - assert (orderEntity.isPresent()); - ExamOrderEntity examOrderEntity = orderEntity.get(); - assertEquals(examOrder1.getStatus(), examOrderEntity.getStatus()); - assertEquals(examOrderEntity.getClaimSubmission().getId(), claimSubmissionEntity.getId()); - ExamOrder examOrder2 = new ExamOrder(); - examOrder2.setCollectionId(examOrder1.getCollectionId()); - examOrder2.setIdType(examOrder1.getIdType()); - examOrder2.setStatus("status2"); - saveToDbService.insertOrUpdateExamOrderingStatus(examOrder2); - Optional updatedOrder = - examOrderRepository.findByCollectionId(examOrder1.getCollectionId()); - assert (updatedOrder.isPresent()); - ExamOrderEntity updatedOrderEntity = updatedOrder.get(); - assertEquals(examOrder2.getStatus(), updatedOrderEntity.getStatus()); - assertEquals(updatedOrderEntity.getClaimSubmission().getId(), claimSubmissionEntity.getId()); - } - - @Test - void persistFlashIds() { - VeteranEntity veteran = new VeteranEntity(); - veteran.setIcn("X"); - veteran.setParticipantId("Y"); - veteranRepository.save(veteran); - List flashIds = new ArrayList<>(); - flashIds.add("123"); - flashIds.add("456"); - saveToDbService.insertFlashIds(flashIds, veteran.getIcn()); - VeteranEntity veteranWithFlashIds = veteranRepository.findByIcn(veteran.getIcn()).orElseThrow(); - assertEquals(veteranWithFlashIds.getFlashIds().get(0).getFlashId(), flashIds.get(0)); - assertEquals(veteranWithFlashIds.getFlashIds().get(1).getFlashId(), flashIds.get(1)); - assertEquals(veteranWithFlashIds.getFlashIds().get(0).getVeteran().getIcn(), veteran.getIcn()); - assertEquals(veteranWithFlashIds.getFlashIds().get(1).getVeteran().getIcn(), veteran.getIcn()); - } - - @Test - void multipleRequests() { - Claim claim1 = - Claim.builder() - .benefitClaimId("1234") - .collectionId("111") - .idType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE) - .veteranIcn("v1") - .diagnosticCode("7101") - .build(); - saveToDbService.insertClaim(claim1); - ClaimEntity claimEntity1 = claimRepository.findByVbmsId("1234").orElseThrow(); - assertEquals(1, claimEntity1.getContentions().size()); - ContentionEntity contentionEntity = claimEntity1.getContentions().get(0); - assertEquals(claim1.getDiagnosticCode(), contentionEntity.getDiagnosticCode()); - Set claimSubmissionEntities = claimEntity1.getClaimSubmissions(); - assertEquals(1, claimSubmissionEntities.size()); - Claim claim2 = - Claim.builder() - .benefitClaimId("1234") - .collectionId("111") - .idType(MasAutomatedClaimPayload.CLAIM_V2_ID_TYPE) - .veteranIcn("v1") - .diagnosticCode("8181") - .build(); - saveToDbService.insertClaim(claim2); - ClaimEntity claimEntity2 = claimRepository.findByVbmsId("1234").orElseThrow(); - assertEquals(2, claimEntity2.getContentions().size()); - Set claimSubmissionEntities2 = claimEntity2.getClaimSubmissions(); - assertEquals(2, claimSubmissionEntities2.size()); - } -} diff --git a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/TestConfig.java b/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/TestConfig.java deleted file mode 100644 index 69f39611e5..0000000000 --- a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/TestConfig.java +++ /dev/null @@ -1,10 +0,0 @@ -package gov.va.vro.service.rrd.db; - -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.domain.EntityScan; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; - -@SpringBootApplication -@EnableJpaRepositories("gov.va.vro.persistence.repository") -@EntityScan("gov.va.vro.persistence.model") -public class TestConfig {} diff --git a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/mapper/ClaimInfoResponseMapperTest.java b/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/mapper/ClaimInfoResponseMapperTest.java deleted file mode 100644 index 258aba286b..0000000000 --- a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/mapper/ClaimInfoResponseMapperTest.java +++ /dev/null @@ -1,95 +0,0 @@ -package gov.va.vro.service.rrd.db.mapper; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import com.tngtech.archunit.thirdparty.com.google.common.collect.ImmutableMap; -import gov.va.vro.model.rrd.claimmetrics.AssessmentInfo; -import gov.va.vro.model.rrd.claimmetrics.ContentionInfo; -import gov.va.vro.model.rrd.claimmetrics.DocumentInfo; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimInfoResponse; -import gov.va.vro.persistence.model.AssessmentResultEntity; -import gov.va.vro.persistence.model.ClaimEntity; -import gov.va.vro.persistence.model.ClaimSubmissionEntity; -import gov.va.vro.persistence.model.ContentionEntity; -import gov.va.vro.persistence.model.EvidenceSummaryDocumentEntity; -import gov.va.vro.persistence.model.VeteranEntity; -import gov.va.vro.service.rrd.db.TestConfig; -import gov.va.vro.service.spi.model.Claim; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Map; - -@SpringBootTest(classes = TestConfig.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) -@Transactional -@ActiveProfiles("test") -@EnableJpaAuditing -public class ClaimInfoResponseMapperTest { - @Autowired ClaimInfoResponseMapper mapper; - - @Test - void testMain() { - final String icn = "icn_test"; - VeteranEntity veteranEntity = new VeteranEntity(); - veteranEntity.setIcn(icn); - - final String diagnosticCode = "7101"; - ContentionEntity contentionEntity = new ContentionEntity(); - contentionEntity.setDiagnosticCode(diagnosticCode); - - final Boolean sufficientEvidence = true; - AssessmentResultEntity assessmentResultEntity = new AssessmentResultEntity(); - Map areEvidenceInfo = ImmutableMap.of("k1", "v1", "k2", "v2"); - assessmentResultEntity.setEvidenceCountSummary(areEvidenceInfo); - assessmentResultEntity.setSufficientEvidenceFlag(sufficientEvidence); - contentionEntity.addAssessmentResult(assessmentResultEntity); - - EvidenceSummaryDocumentEntity esdEntity = new EvidenceSummaryDocumentEntity(); - final String documentName = "document_name_test"; - esdEntity.setDocumentName(documentName); - Map esdEvidenceInfo = ImmutableMap.of("k3", "v3", "k4", "v4"); - esdEntity.setEvidenceCount(esdEvidenceInfo); - contentionEntity.addEvidenceSummaryDocument(esdEntity); - - final String claimSubmissionId = "cs_id_test"; - ClaimSubmissionEntity claimSubmissionEntity = new ClaimSubmissionEntity(); - claimSubmissionEntity.setReferenceId(claimSubmissionId); - claimSubmissionEntity.setIdType(Claim.V1_ID_TYPE); - - ClaimEntity claimEntity = new ClaimEntity(); - claimEntity.setVeteran(veteranEntity); - claimEntity.addContention(contentionEntity); - claimEntity.addClaimSubmission(claimSubmissionEntity); - - ClaimInfoResponse response = mapper.toClaimInfoResponseV1(claimEntity); - - assertEquals(claimSubmissionId, response.getClaimSubmissionId()); - assertEquals(icn, response.getVeteranIcn()); - - List contentions = response.getContentions(); - assertNotNull(contentions); - assertEquals(1, contentions.size()); - ContentionInfo contentionInfo = contentions.get(0); - assertEquals(diagnosticCode, contentionInfo.getDiagnosticCode()); - - List assessments = contentionInfo.getAssessments(); - assertNotNull(assessments); - assertEquals(1, assessments.size()); - AssessmentInfo assessmentInfo = assessments.get(0); - assertEquals(areEvidenceInfo, assessmentInfo.getEvidenceInfo()); - assertEquals(sufficientEvidence, assessmentInfo.getSufficientEvidenceFlag()); - - List documents = contentionInfo.getDocuments(); - assertNotNull(documents); - assertEquals(1, documents.size()); - DocumentInfo documentInfo = documents.get(0); - assertEquals(documentName, documentInfo.getDocumentName()); - assertEquals(esdEvidenceInfo, documentInfo.getEvidenceInfo()); - } -} diff --git a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/mapper/ClaimMapperTest.java b/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/mapper/ClaimMapperTest.java deleted file mode 100644 index b6b61442a5..0000000000 --- a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/mapper/ClaimMapperTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package gov.va.vro.service.rrd.db.mapper; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import gov.va.vro.persistence.model.ClaimEntity; -import gov.va.vro.persistence.model.ContentionEntity; -import gov.va.vro.persistence.model.VeteranEntity; -import gov.va.vro.service.spi.model.Claim; -import org.junit.jupiter.api.Test; -import org.mapstruct.factory.Mappers; - -class ClaimMapperTest { - - @Test - void toClaim() { - VeteranEntity veteranEntity = new VeteranEntity(); - veteranEntity.setIcn("icn2"); - ClaimEntity claimEntity = new ClaimEntity(); - claimEntity.setVbmsId("123"); - claimEntity.setVeteran(veteranEntity); - ContentionEntity contentionEntity1 = new ContentionEntity(); - contentionEntity1.setDiagnosticCode("7101"); - claimEntity.addContention(contentionEntity1); - ContentionEntity contentionEntity2 = new ContentionEntity(); - contentionEntity2.setDiagnosticCode("6202"); - claimEntity.addContention(contentionEntity2); - - ClaimMapper claimMapper = Mappers.getMapper(ClaimMapper.class); - Claim claim = claimMapper.toClaim(claimEntity); - assertEquals(claimEntity.getVbmsId(), claim.getBenefitClaimId()); - assertEquals(claimEntity.getVeteran().getIcn(), claim.getVeteranIcn()); - assertEquals(2, claim.getContentions().size()); - assertTrue(claim.getContentions().contains("7101")); - assertTrue(claim.getContentions().contains("6202")); - } -} diff --git a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/util/AbdEvidenceCase.java b/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/util/AbdEvidenceCase.java deleted file mode 100644 index 3e93e8cc79..0000000000 --- a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/util/AbdEvidenceCase.java +++ /dev/null @@ -1,132 +0,0 @@ -package gov.va.vro.service.rrd.db.util; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -import gov.va.vro.model.rrd.AbdBloodPressure; -import gov.va.vro.model.rrd.AbdCondition; -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.model.rrd.AbdMedication; -import gov.va.vro.model.rrd.AbdProcedure; -import lombok.Getter; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -/** This class contains methods to generate AbdEvidence objects for testing purposes. */ -@Getter -public class AbdEvidenceCase { - private static final AtomicInteger counter = new AtomicInteger(1); - - private static final int MED_OFFSET = 3; - private static final int CONDITION_OFFSET = 5; - private static final int PROCEDURE_OFFSET = 7; - private static final int BP_OFFSET = 1; - - private static final int MOD_LENGTH = 11; - - private Integer medCount; - private Integer conditionCount; - private Integer procedureCount; - private Integer bpCount; - - private static Integer getCount(int index, int offset) { - int count = index + offset; - if (count == MOD_LENGTH) { - return null; - } - return (count - 1) % MOD_LENGTH; - } - - private static List getList(Integer count, Class clazz) { - if (count == null) { - return null; - } - return Collections.nCopies(count.intValue(), (T) null); - } - - private AbdEvidence generateEvidence() { - AbdEvidence evidence = new AbdEvidence(); - - evidence.setBloodPressures(getList(bpCount, AbdBloodPressure.class)); - evidence.setMedications(getList(medCount, AbdMedication.class)); - evidence.setConditions(getList(conditionCount, AbdCondition.class)); - evidence.setProcedures(getList(procedureCount, AbdProcedure.class)); - - return evidence; - } - - private Map generateSummary() { - Map result = new HashMap<>(); - - if (bpCount != null) { - result.put("totalBpReadings", bpCount); - } - if (procedureCount != null) { - result.put("proceduresCount", procedureCount); - } - if (conditionCount != null) { - result.put("conditionsCount", conditionCount); - } - if (medCount != null) { - result.put("medicationsCount", medCount); - } - return result; - } - - /** - * Generates the evidence summary for the test case. - * - * @param claimSubmissionId claim id for the evidence summary - * @return AbdEvidenceWithSummary - */ - public AbdEvidenceWithSummary getEvidenceWithSummary(String claimSubmissionId) { - AbdEvidenceWithSummary result = new AbdEvidenceWithSummary(); - - result.setClaimSubmissionId(claimSubmissionId); - result.setEvidence(generateEvidence()); - result.setEvidenceSummary(generateSummary()); - - return result; - } - - private static void verifyEvidenceField(Integer expected, String actual) { - if (expected == null) { - assertNull(actual); - } else { - assertEquals(expected.toString(), actual); - } - } - - /** - * Verifies the test case has the expected evidence summary. - * - * @param evidenceSummary Actual evidence summary to be verified. - */ - public void verifyEvidenceSummary(Map evidenceSummary) { - verifyEvidenceField(bpCount, evidenceSummary.get("totalBpReadings")); - verifyEvidenceField(procedureCount, evidenceSummary.get("proceduresCount")); - verifyEvidenceField(medCount, evidenceSummary.get("medicationsCount")); - } - - /** - * Generates an evidence summary test case. - * - * @return AbdEvidenceCase - */ - public static AbdEvidenceCase getInstance() { - int index = counter.incrementAndGet(); - - AbdEvidenceCase result = new AbdEvidenceCase(); - result.medCount = getCount(index, MED_OFFSET); - result.conditionCount = getCount(index, CONDITION_OFFSET); - result.procedureCount = getCount(index, PROCEDURE_OFFSET); - result.bpCount = getCount(index, BP_OFFSET); - - return result; - } -} diff --git a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/util/ClaimMetricsTestCase.java b/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/util/ClaimMetricsTestCase.java deleted file mode 100644 index a8655d6433..0000000000 --- a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/util/ClaimMetricsTestCase.java +++ /dev/null @@ -1,179 +0,0 @@ -package gov.va.vro.service.rrd.db.util; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import gov.va.vro.model.rrd.AbdEvidence; -import gov.va.vro.model.rrd.AbdEvidenceWithSummary; -import gov.va.vro.model.rrd.VeteranInfo; -import gov.va.vro.model.rrd.claimmetrics.AssessmentInfo; -import gov.va.vro.model.rrd.claimmetrics.ContentionInfo; -import gov.va.vro.model.rrd.claimmetrics.DocumentInfo; -import gov.va.vro.model.rrd.claimmetrics.response.ClaimInfoResponse; -import gov.va.vro.persistence.model.ClaimEntity; -import gov.va.vro.persistence.model.ClaimSubmissionEntity; -import gov.va.vro.persistence.model.ContentionEntity; -import gov.va.vro.persistence.repository.ClaimSubmissionRepository; -import gov.va.vro.service.spi.db.SaveToDbService; -import gov.va.vro.service.spi.model.Claim; -import gov.va.vro.service.spi.model.GeneratePdfPayload; -import lombok.Getter; - -import java.util.List; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * This class contains the data, database insert methods, and testing assertions for typical - * workflows that populate the database. It is being used as a utility class for Save to Db and - * Claim Metrics functionality. - */ -@Getter -public class ClaimMetricsTestCase { - private static final AtomicInteger counter = new AtomicInteger(0); - - // private ServiceBundle serviceBundle; - - private String claimSubmissionId; - - private String icn; - - private AbdEvidenceCase evidenceCase; - - private String documentName; - - private VeteranInfo veteranInfo; - - private GeneratePdfPayload getPdfPayload(AbdEvidence evidence) { - GeneratePdfPayload result = new GeneratePdfPayload(); - - result.setEvidence(evidence); - result.setDiagnosticCode("7101"); - result.setClaimSubmissionId(claimSubmissionId); - result.setVeteranInfo(veteranInfo); - - return result; - } - - /** - * This populates the database based on the simulation of generating medical assessment and - * evidence summary pdf. - */ - public void populate(SaveToDbService service, ClaimSubmissionRepository csRepo) { - Claim claim = new Claim(); - claim.setCollectionId(claimSubmissionId); - claim.setVeteranIcn(icn); - claim.setDiagnosticCode("7101"); - service.insertClaim(claim); - - ClaimEntity claimEntity; - - // v1 endpoints provide claimSubmissionId, which maps to reference_id on the - // claim_submission table (which is used as collectionId) - ClaimSubmissionEntity csEntity = - csRepo - .findFirstByReferenceIdAndIdTypeOrderByCreatedAtDesc( - claimSubmissionId, claim.getIdType()) - .orElseThrow(); - claimEntity = csEntity.getClaim(); - - Set submissions = claimEntity.getClaimSubmissions(); - assertEquals(1, submissions.size()); - ClaimSubmissionEntity submissionEntity = submissions.iterator().next(); - assertEquals(claimSubmissionId, submissionEntity.getReferenceId()); - List contentions = claimEntity.getContentions(); - assertEquals(1, contentions.size()); - - UUID claimEntityId = claimEntity.getId(); - AbdEvidenceWithSummary evidence = evidenceCase.getEvidenceWithSummary(claimSubmissionId); - service.insertAssessmentResult(claimEntityId, evidence, "7101"); - - GeneratePdfPayload gpp = getPdfPayload(evidence.getEvidence()); - gpp.setIdType(claim.getIdType()); - service.insertEvidenceSummaryDocument(gpp, documentName); - } - - private static VeteranInfo getVeteranInfo(int index) { - VeteranInfo veteranInfo = new VeteranInfo(); - - veteranInfo.setLast("last_" + index); - veteranInfo.setFirst("first_" + index); - - int month = (index % 12) + 1; - int year = 1980 + (index % 20); - int day = index % 28; - veteranInfo.setBirthdate(month + "/" + day + "/" + year); - - return veteranInfo; - } - - /** - * Constructs a new claim test case for the same veteran. - * - * @return newed TestSetup - */ - public ClaimMetricsTestCase newCaseForSameVeteran() { - ClaimMetricsTestCase result = new ClaimMetricsTestCase(); - - int counterValue = counter.getAndIncrement(); - - result.claimSubmissionId = "claim_id_" + counterValue; - result.evidenceCase = AbdEvidenceCase.getInstance(); - result.documentName = "document_" + counterValue; - - result.icn = icn; - result.veteranInfo = getVeteranInfo(counterValue); - - return result; - } - - /** - * Verifies if the actual claim information is as expected. - * - * @param claimInfo - */ - public void verifyClaimInfoResponse(ClaimInfoResponse claimInfo) { - assertEquals(claimSubmissionId, claimInfo.getClaimSubmissionId()); - assertEquals(icn, claimInfo.getVeteranIcn()); - - List contentions = claimInfo.getContentions(); - assertNotNull(contentions); - assertEquals(1, contentions.size()); - ContentionInfo contention = contentions.get(0); - - assertEquals("7101", contention.getDiagnosticCode()); - - List assessments = contention.getAssessments(); - assertNotNull(assessments); - assertEquals(1, assessments.size()); - AssessmentInfo assessment = assessments.get(0); - evidenceCase.verifyEvidenceSummary(assessment.getEvidenceInfo()); - - List documents = contention.getDocuments(); - assertNotNull(documents); - assertEquals(1, documents.size()); - DocumentInfo document = documents.get(0); - assertEquals(documentName, document.getDocumentName()); - evidenceCase.verifyEvidenceSummary(document.getEvidenceInfo()); - } - - /** - * Constructs a new test set that defaults data based on static counter. - * - * @return newed TestSetup - */ - public static ClaimMetricsTestCase getInstance() { - ClaimMetricsTestCase result = new ClaimMetricsTestCase(); - - int counterValue = counter.getAndIncrement(); - - result.claimSubmissionId = "claim_id_" + counterValue; - result.icn = "icn_" + counterValue; - result.evidenceCase = AbdEvidenceCase.getInstance(); - result.documentName = "document_" + counterValue; - result.veteranInfo = getVeteranInfo(counterValue); - - return result; - } -} diff --git a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/util/ServiceBundle.java b/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/util/ServiceBundle.java deleted file mode 100644 index 523cfafe4e..0000000000 --- a/domain-rrd/service-rrd-db/src/test/java/gov/va/vro/service/rrd/db/util/ServiceBundle.java +++ /dev/null @@ -1,17 +0,0 @@ -package gov.va.vro.service.rrd.db.util; - -import gov.va.vro.persistence.repository.ClaimRepository; -import gov.va.vro.service.spi.db.SaveToDbService; -import gov.va.vro.service.spi.services.ClaimMetricsService; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -@AllArgsConstructor -public class ServiceBundle { - private ClaimMetricsService claimMetricsService; - private SaveToDbService saveToDbService; - private ClaimRepository claimRepository; -} diff --git a/domain-rrd/service-rrd-db/src/test/resources/application-test.yml b/domain-rrd/service-rrd-db/src/test/resources/application-test.yml deleted file mode 100644 index 68fdaf91ac..0000000000 --- a/domain-rrd/service-rrd-db/src/test/resources/application-test.yml +++ /dev/null @@ -1,38 +0,0 @@ -# This file is loaded when a test is annotated with @ActiveProfiles("test") -# Spring will load main/resources/application.yml, followed by this file. -# Since we want tests to be as close as possible to the deployed app, don't create test/resources/application.yml. -# If test/resources/application.yml exists, it will override main/resources/application.yml. - -# Since this is for tests, override some main/resources/application.yml Spring settings - -spring: - datasource: - url: jdbc:h2:mem:testdb;MODE=PostgreSQL;INIT=CREATE SCHEMA IF NOT EXISTS example\;SET SCHEMA example; - hikari: - jdbc-url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=PostgreSQL;INIT=RUNSCRIPT FROM 'classpath:init.sql' - username: sa - password: sap - jpa: - show-sql: false - generate-ddl: true - hibernate: - ddl-auto: create-drop - naming: - physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl - database-platform: org.hibernate.dialect.PostgresSQL95Dialect - properties: - hibernate: - generate_statistics: false - jdbc: - lob: - non_contextual_creation=true: - -logging: - register-shutdown-hook: true - level: - org.springframework.jdbc.core: INFO # DEBUG - org.springframework.jdbc.core.JdbcTemplate: INFO # DEBUG - org.springframework.jdbc.core.StatementCreatorUtils: INFO # TRACE - org.hibernate.SQL: INFO # DEBUG - org.type.descriptor.sql.BasicBinder: INFO # TRACE - org.hibernate.type.descriptor.sql.BasicBinder: INFO # TRACE diff --git a/domain-rrd/service-rrd-db/src/test/resources/init.sql b/domain-rrd/service-rrd-db/src/test/resources/init.sql deleted file mode 100644 index a28b803304..0000000000 --- a/domain-rrd/service-rrd-db/src/test/resources/init.sql +++ /dev/null @@ -1,3 +0,0 @@ -CREATE SCHEMA IF NOT EXISTS example; -SET SCHEMA example; -CREATE TYPE "JSONB" AS json; diff --git a/domain-rrd/service-rrd-db/src/test/resources/test-data/evidence-summary-document-data.json b/domain-rrd/service-rrd-db/src/test/resources/test-data/evidence-summary-document-data.json deleted file mode 100644 index 29d2996076..0000000000 --- a/domain-rrd/service-rrd-db/src/test/resources/test-data/evidence-summary-document-data.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "claimSubmissionId": "1234", - "diagnosticCode": "7101", - "veteranInfo": { - "first": "Joe", - "middle": "M", - "last": "Doe", - "suffix": "Jr", - "birthdate": "01/04/1971" - }, - "evidence": { - "medications": [ - { - "status": "Active", - "description": "Hydrochlorothiazide 6.25 MG", - "refills": 0, - "authoredOn": "1950-04-05T23:00:00Z", - "dosageInstructions": [ - "QD" - ], - "route": "ORAL" - }, - { - "status": "Active", - "notes": [ - "Hydrochlorothiazide 6.25 MG" - ], - "description": "Hydrochlorothiazide 6.25 MG", - "refills": 0, - "authoredOn": "1950-04-06T07:24:55Z", - "dosageInstructions": [ - "Once per day.", - "As directed by physician." - ], - "route": "As directed by physician." - } - ], - "bp_readings": [ - { - "date": "2009-03-19", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 83.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 131.0 - }, - "practitioner": "DR. JANE460 DOE922 MD", - "organization": "LYONS VA MEDICAL CENTER" - }, - { - "date": "2010-03-25", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 82.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 138.0 - }, - "practitioner": "DR. THOMAS359 REYNOLDS206 PHD", - "organization": "NEW AMSTERDAM CBOC" - }, - { - "date": "2011-03-31", - "diastolic": { - "code": "8462-4", - "display": "Diastolic blood pressure", - "unit": "mm[Hg]", - "value": 71.0 - }, - "systolic": { - "code": "8480-6", - "display": "Systolic blood pressure", - "unit": "mm[Hg]", - "value": 101.0 - }, - "practitioner": "DR. JOHN248 SMITH811 MD", - "organization": "LYONS VA MEDICAL CENTER" - } - ] - } -} diff --git a/helm/_shared/named_templates/_image.tpl b/helm/_shared/named_templates/_image.tpl index 9c80e42f29..e5be57e546 100644 --- a/helm/_shared/named_templates/_image.tpl +++ b/helm/_shared/named_templates/_image.tpl @@ -4,7 +4,7 @@ imagePullSecrets: {{- end }} {{- define "vro.imageRegistryPath" -}} -ghcr.io/department-of-veterans-affairs/{{ .Values.global.images.repo }}/{{ .Values.global.imagePrefix }} +ghcr.io/department-of-veterans-affairs/{{ .Values.global.images.repo }}/ {{- end }} {{- define "vro.containerSuffix" -}} diff --git a/helm/_shared/values-for-dev.yaml b/helm/_shared/values-for-dev.yaml index fbea946113..d3f198b76e 100644 --- a/helm/_shared/values-for-dev.yaml +++ b/helm/_shared/values-for-dev.yaml @@ -5,7 +5,6 @@ global: # Used by virtual-service's hosts # Refer to https://animated-carnival-57b3e7f5.pages.github.io/container-platform/routing-traffic/ endpoint: dev.lighthouse.va.gov - imagePrefix: dev_ biekafka: envVars: diff --git a/helm/_shared/values-for-prod-test.yaml b/helm/_shared/values-for-prod-test.yaml index bb0f47b440..123dbb7506 100644 --- a/helm/_shared/values-for-prod-test.yaml +++ b/helm/_shared/values-for-prod-test.yaml @@ -3,4 +3,3 @@ global: lhdiCluster: prod environment: prod-test endpoint: prod-test.lighthouse.va.gov - imagePrefix: "" diff --git a/helm/_shared/values-for-prod.yaml b/helm/_shared/values-for-prod.yaml index 71f17445e8..31998e038e 100644 --- a/helm/_shared/values-for-prod.yaml +++ b/helm/_shared/values-for-prod.yaml @@ -1,6 +1,4 @@ - global: lhdiCluster: prod environment: prod endpoint: api.lighthouse.va.gov - imagePrefix: "" diff --git a/helm/_shared/values-for-qa.yaml b/helm/_shared/values-for-qa.yaml index 6dd5b078c9..4644835041 100644 --- a/helm/_shared/values-for-qa.yaml +++ b/helm/_shared/values-for-qa.yaml @@ -3,4 +3,3 @@ global: lhdiCluster: nonprod environment: qa endpoint: qa.lighthouse.va.gov - imagePrefix: dev_ diff --git a/helm/_shared/values-for-sandbox.yaml b/helm/_shared/values-for-sandbox.yaml index 9ed82f8a0b..df23f73fa1 100644 --- a/helm/_shared/values-for-sandbox.yaml +++ b/helm/_shared/values-for-sandbox.yaml @@ -3,4 +3,3 @@ global: lhdiCluster: nonprod environment: sandbox endpoint: sandbox.lighthouse.va.gov - imagePrefix: "" diff --git a/helm/_shared/values.yaml b/helm/_shared/values.yaml index ea2ff5eac9..5a2f3ceff8 100644 --- a/helm/_shared/values.yaml +++ b/helm/_shared/values.yaml @@ -24,3 +24,4 @@ global: targetPort: 5432 databaseName: vro schemaName: claims + domainCcSchemaName: domain-cc diff --git a/helm/deploy.sh b/helm/deploy.sh index 7ed0db834d..1e3a24ba32 100755 --- a/helm/deploy.sh +++ b/helm/deploy.sh @@ -86,6 +86,8 @@ case "$HELM_CHART" in HELM_ARGS="$HELM_ARGS --set-string imageTag=$svcbipapi_VER";; postgres) HELM_ARGS="$HELM_ARGS --set-string imageTag=$postgres_VER";; + dev-tools) + HELM_ARGS="$HELM_ARGS --set-string imageTag=$devtools_VER";; esac set -x diff --git a/helm/dev-tools/templates/named_templates/_image.tpl b/helm/dev-tools/templates/named_templates/_image.tpl index 9c80e42f29..e5be57e546 100644 --- a/helm/dev-tools/templates/named_templates/_image.tpl +++ b/helm/dev-tools/templates/named_templates/_image.tpl @@ -4,7 +4,7 @@ imagePullSecrets: {{- end }} {{- define "vro.imageRegistryPath" -}} -ghcr.io/department-of-veterans-affairs/{{ .Values.global.images.repo }}/{{ .Values.global.imagePrefix }} +ghcr.io/department-of-veterans-affairs/{{ .Values.global.images.repo }}/ {{- end }} {{- define "vro.containerSuffix" -}} diff --git a/helm/domain-cc/templates/_alembicdb.tpl b/helm/domain-cc/templates/_alembicdb.tpl new file mode 100644 index 0000000000..790fc77a19 --- /dev/null +++ b/helm/domain-cc/templates/_alembicdb.tpl @@ -0,0 +1,16 @@ +{{/* + For Alembic to connect to Postgres Domain-cc DB schema +*/}} +{{- define "domainCc.alembic.envVars" -}} +- name: DOMAIN_CC_USER + valueFrom: + secretKeyRef: + name: domain-cc-db + key: DOMAIN_CC_USER +- name: DOMAIN_CC_PW + valueFrom: + secretKeyRef: + name: domain-cc-db + key: DOMAIN_CC_PW +- name: ALEMBIC_SCHEMA + value: {{ .Values.global.service.db.domainCcSchemaName }} \ No newline at end of file diff --git a/helm/domain-cc/templates/deployment.yaml b/helm/domain-cc/templates/deployment.yaml index c86e160b19..2b2599091a 100644 --- a/helm/domain-cc/templates/deployment.yaml +++ b/helm/domain-cc/templates/deployment.yaml @@ -29,6 +29,8 @@ spec: {{- include "vro.commonEnvVars" . | nindent 12 }} {{- include "vro.mqClient.envVars" . | nindent 12 }} {{- include "vro.redisClient.envVars" . | nindent 12 }} + {{- include "domainCc.alembic.envVars" . | nindent 12 }} + {{- include "vro.postgresUrl" . | nindent 12 }} resources: requests: cpu: 150m diff --git a/mocks/mock-bip-claims-api/src/main/resources/mock-claims.json b/mocks/mock-bip-claims-api/src/main/resources/mock-claims.json index db86281ae6..bfd5df05ac 100644 --- a/mocks/mock-bip-claims-api/src/main/resources/mock-claims.json +++ b/mocks/mock-bip-claims-api/src/main/resources/mock-claims.json @@ -791,7 +791,8 @@ "claimId": 10000, "phase": "Claim Received", "tempStationOfJurisdiction": "398", - "endProductCode": "010" + "endProductCode": "010", + "claimLifecycleStatus": "Open" }, "contentions": [ { @@ -1006,7 +1007,8 @@ "claimId": 5001, "phase": "Claim Received", "tempStationOfJurisdiction": "398", - "endProductCode": "010" + "endProductCode": "010", + "claimLifecycleStatus": "Open" }, "contentions": [ { @@ -1085,7 +1087,8 @@ "claimId": 5004, "phase": "Claim Received", "tempStationOfJurisdiction": "398", - "endProductCode": "010" + "endProductCode": "010", + "claimLifecycleStatus": "Open" }, "contentions": [ { @@ -1163,7 +1166,8 @@ "claimId": 5006, "phase": "Claim Received", "tempStationOfJurisdiction": "398", - "endProductCode": "010" + "endProductCode": "010", + "claimLifecycleStatus": "Open" }, "contentions": [ { diff --git a/scripts/svc-bie-kafka-certgen.sh b/scripts/svc-bie-kafka-certgen.sh index 8d26c65de8..78e1c671d1 100755 --- a/scripts/svc-bie-kafka-certgen.sh +++ b/scripts/svc-bie-kafka-certgen.sh @@ -6,23 +6,12 @@ # output.json contains 4 key-value pairs, which should be pasted into to Vault # # Following keys/values are generated -# BIE_KAFKA_KEYSTORE_INBASE64 -# BIE_KAFKA_KEYSTORE_PASSWORD # BIE_KAFKA_TRUSTSTORE_INBASE64 # BIE_KAFKA_TRUSTSTORE_PASSWORD # Pre-requisite: -# - Download certificates locally from the links provided at wiki https://github.com/department-of-veterans-affairs/abd-vro-internal/wiki/VRO-Secrets -# VA-Internal-S2-ICA4.cer -# VA-Internal-S2-ICA19.cer -# VA-Internal-S2-ICA11.cer -# VA-Internal-S2-RCA2.cer -# Input: -# $1 Input environment name like dev, qa, prod -# $2 Input BIE provided certificate file -# $3 Input BIE provided key -# $4 Input BIE Kafka environment prefix like dev, ivv, pr, pp +# - Download all public certificates from http://aia.pki.va.gov/PKI/AIA/VA/ (ignore AllVAInternalCAs.p7b and NewVAInternalCAs.p7b) +# locally before running this script # -# - ---- # Function: generates a random password for keystore and truststore generate_password() { @@ -39,29 +28,32 @@ generate_password() { openssl rand -base64 20 | tr -dc "$all_chars" | head -c 16 } -export KEYSTORE_PWD=$(generate_password) -export TRUSTSTORE_PWD=$(generate_password) +# Generate a password for the keystore +STOREPASS=$(generate_password) +echo "Generated truststore password: $STOREPASS" -# Delete temporary files (if they exist) to avoid issues when re-running script. -# Keeping them will result in password mismatch error. They are safe to delete as they are recreated. -rm -f bip.truststore.jks keystore.p12 bip.truststore.p12 passwd output.json +# Define the truststore file name +TRUSTSTORE="vro-truststore.p12" -openssl pkcs12 -export -in "$2" -inkey "$3" -out keystore.p12 -name kafka-keystore-$4-$1 -CAfile VACACerts.pem -caname root -passout env:KEYSTORE_PWD +# Create or clear the existing truststore +rm -f "$TRUSTSTORE" -keytool -importkeystore -srckeystore keystore.p12 -srcstoretype pkcs12 -destkeystore bip.truststore.jks -deststoretype JKS -srcstorepass "$KEYSTORE_PWD" -deststorepass "$TRUSTSTORE_PWD" +# Loop through the .cer files and import each into the truststore +for certfile in *.cer; do + # Extract alias name by removing the 'VA-Internal-' prefix from the filename + alias=$(echo "$certfile" | sed 's/VA-Internal-//; s/.cer$//') -echo "yes" | keytool -import -alias AllVA1 -file VA-Internal-S2-ICA4.cer -storetype JKS -keystore bip.truststore.jks -storepass "$TRUSTSTORE_PWD" -# shellcheck disable=SC2086 -echo "yes" | keytool -import -alias AllVA2 -file VA-Internal-S2-ICA19.cer -storetype JKS -keystore bip.truststore.jks -storepass "$TRUSTSTORE_PWD" -echo "yes" | keytool -import -alias AllVA3 -file VA-Internal-S2-ICA11.cer -storetype JKS -keystore bip.truststore.jks -storepass "$TRUSTSTORE_PWD" -echo "yes" | keytool -import -alias AllVA4 -file VA-Internal-S2-RCA2.cer -storetype JKS -keystore bip.truststore.jks -storepass "$TRUSTSTORE_PWD" + # Import the certificate into the truststore + keytool -import -noprompt -alias "$alias" -file "$certfile" -keystore "$TRUSTSTORE" -storepass "$STOREPASS" -storetype PKCS12 +done -echo "$KEYSTORE_PWD" | keytool -importkeystore -srckeystore bip.truststore.jks -srcstoretype jks -srcstorepass "$TRUSTSTORE_PWD" -destkeystore bip.truststore.p12 -deststoretype pkcs12 -deststorepass "$TRUSTSTORE_PWD" +# Encode the truststore file to Base64 and print it +echo "Base64 Encoded Truststore:" +base64 -i "$TRUSTSTORE" # Encode the files -keystore=$(cat keystore.p12 | base64 | tr -d '\n') -bip_truststore=$(cat bip.truststore.p12 | base64 | tr -d '\n') +truststore=$(cat "$TRUSTSTORE" | base64 | tr -d '\n') # Create the JSON file -echo -e "{\n\"BIE_KAFKA_KEYSTORE_INBASE64\": \"$keystore\", \n\"BIE_KAFKA_KEYSTORE_PASSWORD\": \"$KEYSTORE_PWD\", \n\"BIE_KAFKA_TRUSTSTORE_INBASE64\": \"$bip_truststore\", \n\"BIE_KAFKA_TRUSTSTORE_PASSWORD\": \"$TRUSTSTORE_PWD\"\n}" > output.json +echo -e "{\n\"BIE_KAFKA_TRUSTSTORE_INBASE64\": \"$truststore\", \n\"BIE_KAFKA_TRUSTSTORE_PASSWORD\": \"$STOREPASS\"\n}" > output.json diff --git a/svc-bie-kafka/build.gradle b/svc-bie-kafka/build.gradle index 9183015993..5bed688d0a 100644 --- a/svc-bie-kafka/build.gradle +++ b/svc-bie-kafka/build.gradle @@ -30,7 +30,7 @@ dependencies { implementation 'io.confluent:kafka-avro-serializer:7.6.0' implementation 'org.apache.kafka:connect-api:7.6.0-ce' implementation 'org.apache.commons:commons-compress:1.26.1' - implementation 'com.google.guava:guava:33.0.0-jre' + implementation 'com.google.guava:guava:33.1.0-jre' // RabbitMQ implementation 'org.springframework.boot:spring-boot-starter-amqp' implementation 'org.springframework.kafka:spring-kafka' diff --git a/svc-lighthouse-api/build.gradle b/svc-lighthouse-api/build.gradle index 38adc511ab..a3092474a8 100644 --- a/svc-lighthouse-api/build.gradle +++ b/svc-lighthouse-api/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation "ca.uhn.hapi.fhir:hapi-fhir-base:${hapi_fhir_version}" implementation "ca.uhn.hapi.fhir:hapi-fhir-server-openapi:${hapi_fhir_version}" - implementation 'org.bouncycastle:bcprov-jdk18on:1.77' + implementation 'org.bouncycastle:bcprov-jdk18on:1.78' implementation 'org.apache.commons:commons-lang3:3.14.0' def jjwt_version="0.12.5" @@ -25,7 +25,7 @@ dependencies { implementation "io.jsonwebtoken:jjwt-impl:${jjwt_version}" implementation "io.jsonwebtoken:jjwt-jackson:${jjwt_version}" - implementation 'org.apache.tomcat.embed:tomcat-embed-core:10.1.19' + implementation 'org.apache.tomcat.embed:tomcat-embed-core:10.1.20' testImplementation "org.apache.camel.springboot:camel-spring-rabbitmq-starter:${camel_version}" }