diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7151dbf962e..21220c65065 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -41,7 +41,7 @@ app/controllers/concerns/vet360 @department-of-veterans-affairs/vfs-authenticate app/controllers/facilities_controller.rb @department-of-veterans-affairs/vfs-facilities-frontend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/flipper_controller.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/gids_controller.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -app/controllers/v0/income_and_assets_claims_controller.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +app/controllers/v0/income_and_assets_claims_controller.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group app/controllers/preneeds_controller.rb @department-of-veterans-affairs/mbs-core-team @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/rx_controller.rb @department-of-veterans-affairs/vfs-mhv-medications @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/sign_in @department-of-veterans-affairs/octo-identity @@ -159,7 +159,7 @@ app/controllers/v1/supplemental_claims @department-of-veterans-affairs/benefits- app/controllers/v1/decision_review_evidences_controller.rb @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/backend-review-group app/controllers/v1/apidocs_controller.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/v1/notice_of_disagreements_controller.rb @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -app/controllers/v1/pension_ipf_callbacks_controller.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +app/controllers/v1/pension_ipf_callbacks_controller.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group app/controllers/v1/sessions_controller.rb @department-of-veterans-affairs/octo-identity app/controllers/v1/supplemental_claims_controller.rb @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/backend-review-group app/controllers/v1/supplemental_claims @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/backend-review-group @@ -247,7 +247,7 @@ app/models/form526_submission_remediation.rb @department-of-veterans-affairs/Dis app/models/form_attachment.rb @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/form_profile.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/form_profiles @department-of-veterans-affairs/my-education-benefits @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -app/models/form_profiles/va_21p527ez.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +app/models/form_profiles/va_21p527ez.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group app/models/form_submission.rb @department-of-veterans-affairs/platform-va-product-forms @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/form_submission_attempt.rb @department-of-veterans-affairs/platform-va-product-forms @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/gi_bill_feedback.rb @department-of-veterans-affairs/my-education-benefits @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -261,7 +261,7 @@ app/models/iam_user.rb @department-of-veterans-affairs/octo-identity app/models/id_card_attributes.rb @department-of-veterans-affairs/backend-review-group app/models/identifier_index.rb @department-of-veterans-affairs/vsa-debt-resolution @department-of-veterans-affairs/backend-review-group app/models/in_progress_form.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/benefits-dependents-management -app/models/intent_to_file_queue_exhaustion.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +app/models/intent_to_file_queue_exhaustion.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group app/models/ivc_champva_form.rb @department-of-veterans-affairs/champva-engineering @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/lighthouse526_document_upload.rb @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/lighthouse_document.rb @department-of-veterans-affairs/backend-review-group @@ -278,10 +278,10 @@ app/models/mpi_data.rb @department-of-veterans-affairs/octo-identity app/models/old_email.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/onsite_notification.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/payment_history.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers -app/models/persistent_attachment.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pensions @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +app/models/persistent_attachment.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/persistent_attachments/dependency_claim.rb @department-of-veterans-affairs/benefits-dependents-management @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/persistent_attachments/lgy_claim.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -app/models/persistent_attachments/pension_burial.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pensions @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +app/models/persistent_attachments/pension_burial.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/persistent_attachments/va_form.rb @department-of-veterans-affairs/platform-va-product-forms @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/personal_information_log.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/power_of_attorney.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -296,9 +296,9 @@ app/models/saved_claim/education_benefits/va_10203.rb @department-of-veterans-af app/models/saved_claim/disability_compensation.rb @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/saved_claim/dependency_claim.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/session.rb @department-of-veterans-affairs/octo-identity -app/models/saved_claim/burial.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pensions @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +app/models/saved_claim/burial.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/saved_claim/disability_compensation.rb @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/backend-review-group -app/models/saved_claim/income_and_assets.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +app/models/saved_claim/income_and_assets.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group app/models/saved_claim/veteran_readiness_employment_claim.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/saved_claim/education_career_counseling_claim.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/models/saved_claim/higher_level_review.rb @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/backend-review-group @@ -398,7 +398,7 @@ app/serializers/messaging_preference_serializer.rb @department-of-veterans-affai app/serializers/mhv_user_account_serializer.rb @department-of-veterans-affairs/octo-identity app/serializers/onsite_notification_serializer.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/serializers/payment_history_serializer.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers -app/serializers/persistent_attachment_serializer.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pensions @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +app/serializers/persistent_attachment_serializer.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/serializers/persistent_attachment_va_form_serializer.rb @department-of-veterans-affairs/platform-va-product-forms @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/serializers/personal_information_serializer.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/serializers/post911_gi_bill_status_serializer.rb @department-of-veterans-affairs/govcio-vfep-codereviewers @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -484,7 +484,7 @@ app/swagger/swagger/requests/health_care_applications.rb @department-of-veterans app/swagger/swagger/requests/form1010_ezr_attachments.rb @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/swagger/swagger/requests/form1010_ezrs.rb @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/swagger/swagger/requests/in_progress_forms.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -app/swagger/swagger/requests/income_and_assets_claims.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +app/swagger/swagger/requests/income_and_assets_claims.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group app/swagger/swagger/requests/maintenance_windows.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/swagger/swagger/requests/mdot @department-of-veterans-affairs/va-cto-health-products @department-of-veterans-affairs/backend-review-group app/swagger/swagger/requests/medical_copays.rb @department-of-veterans-affairs/vsa-debt-resolution @department-of-veterans-affairs/backend-review-group @@ -641,8 +641,8 @@ app/sidekiq/in_progress_form_cleaner.rb @department-of-veterans-affairs/vfs-auth app/sidekiq/kms_key_rotation @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/sidekiq/lighthouse @department-of-veterans-affairs/backend-review-group app/sidekiq/lighthouse/submit_career_counseling_job.rb @department-of-veterans-affairs/my-education-benefits @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -app/sidekiq/lighthouse/create_intent_to_file_job.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group -app/sidekiq/lighthouse/income_and_assets_intake_job.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +app/sidekiq/lighthouse/create_intent_to_file_job.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group +app/sidekiq/lighthouse/income_and_assets_intake_job.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group app/sidekiq/load_average_days_for_claim_completion_job.rb @department-of-veterans-affairs/benefits-microservices @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/sidekiq/mhv @department-of-veterans-affairs/vfs-mhv-medical-records @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/sidekiq/mhv/account_creator_job.rb @department-of-veterans-affairs/octo-identity @@ -684,9 +684,9 @@ config/form_profile_mappings/20-0995.yml @department-of-veterans-affairs/benefit config/form_profile_mappings/20-0996.yml @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group config/form_profile_mappings/21-526EZ.yml @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group config/form_profile_mappings/21-686C.yml @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -config/form_profile_mappings/21P-527EZ.yml @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group -config/form_profile_mappings/21P-527EZ-military.yml @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group -config/form_profile_mappings/21P-0969.yml @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +config/form_profile_mappings/21P-527EZ.yml @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group +config/form_profile_mappings/21P-527EZ-military.yml @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group +config/form_profile_mappings/21P-0969.yml @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group config/form_profile_mappings/21P-530.yml @department-of-veterans-affairs/disability-experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group config/form_profile_mappings/21P-530V2.yml @department-of-veterans-affairs/disability-experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group config/form_profile_mappings/22-0993.yml @department-of-veterans-affairs/govcio-vfep-codereviewers @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -731,7 +731,7 @@ config/initializers/combine_pdf_log_patch.rb @department-of-veterans-affairs/bac config/initializers/config.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group config/initializers/cookie_rotation.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group config/initializers/core_extensions.rb @department-of-veterans-affairs/backend-review-group -config/initializers/covid_vaccine_facilities.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/long-covid +config/initializers/covid_vaccine_facilities.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group config/initializers/datadog.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group config/initializers/date_formats.rb @department-of-veterans-affairs/octo-identity config/initializers/faraday_middleware.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -795,6 +795,7 @@ docs/deployment @department-of-veterans-affairs/va-api-engineers @department-of- docs/deployment/information.md @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group docs/HISTORY.md @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group docs/index.md @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +docs/modules @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group docs/setup/betamocks.md @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group docs/setup/binstubs.md @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group docs/setup/docker.md @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers @@ -910,7 +911,7 @@ lib/http_method_not_allowed.rb @department-of-veterans-affairs/va-api-engineers lib/iam_ssoe_oauth @department-of-veterans-affairs/octo-identity lib/identity @department-of-veterans-affairs/octo-identity lib/ihub @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -lib/income_and_assets @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +lib/income_and_assets @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group lib/json_marshal @department-of-veterans-affairs/vsa-healthcare-health-quest-1-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/json_schema @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/lgy @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -919,8 +920,8 @@ lib/lgy/service.rb @department-of-veterans-affairs/benefits-non-disability @depa lib/lgy/tag_sentry.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/lighthouse @department-of-veterans-affairs/backend-review-group lib/lighthouse/benefit_claims @department-of-veterans-affairs/disability-experience @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -lib/lighthouse/benefit_claims/monitor.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group -lib/lighthouse/benefits_intake @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +lib/lighthouse/benefit_claims/monitor.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group +lib/lighthouse/benefits_intake @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group lib/lighthouse/letters_generator @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/mail_automation @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/map @department-of-veterans-affairs/octo-identity @@ -934,8 +935,8 @@ lib/okta/directory_service.rb @department-of-veterans-affairs/lighthouse-pivot lib/olive_branch_patch.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/pagerduty @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/pdf_fill @department-of-veterans-affairs/vsa-debt-resolution @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/vfs-1095-b -lib/pdf_fill/forms/pdfs/21P-0969.pdf @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group -lib/pdf_fill/forms/va21p0969.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +lib/pdf_fill/forms/pdfs/21P-0969.pdf @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group +lib/pdf_fill/forms/va21p0969.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group lib/pdf_fill/forms/pdfs/28-1900.pdf @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/pdf_fill/forms/va281900.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/pdf_fill/forms/pdfs/28-8832.pdf @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -951,7 +952,7 @@ lib/pdf_fill/forms/va21674.rb @department-of-veterans-affairs/benefits-dependent lib/pdf_info.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/pdf_utilities @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/pension_burial @department-of-veterans-affairs/mbs-core-team @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -lib/pension_21p527ez @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +lib/pension_21p527ez @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group lib/periodic_jobs.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/preneeds @department-of-veterans-affairs/mbs-core-team @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/rubocop/cops/ams_serializer.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -1004,6 +1005,7 @@ modules/appeals_api @department-of-veterans-affairs/lighthouse-banana-peels @dep modules/apps_api @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/lighthouse-pivot modules/ask_va_api @department-of-veterans-affairs/ask-va-team @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group modules/avs @department-of-veterans-affairs/after-visit-summary @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +modules/burials @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group modules/check_in @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/vsa-healthcare-health-quest-1-backend @department-of-veterans-affairs/patient-check-in @department-of-veterans-affairs/backend-review-group modules/claims_api @department-of-veterans-affairs/lighthouse-dash modules/covid_research @department-of-veterans-affairs/long-covid @@ -1016,6 +1018,7 @@ modules/income_limits @department-of-veterans-affairs/vfs-public-websites-fronte modules/ivc_champva @department-of-veterans-affairs/champva-engineering @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group modules/meb_api @department-of-veterans-affairs/my-education-benefits modules/mobile @department-of-veterans-affairs/mobile-api-team +modules/mobile/app/assets/translations @department-of-veterans-affairs/flagship-mobile-content @department-of-veterans-affairs/backend-review-group modules/mocked_authentication @department-of-veterans-affairs/octo-identity modules/my_health @department-of-veterans-affairs/vfs-mhv-secure-messaging @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group modules/representation_management @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/accredited-representation-management @@ -1027,7 +1030,7 @@ modules/vaos @department-of-veterans-affairs/vfs-vaos @department-of-veterans-af modules/vaos/app/services/vaos/v2 @department-of-veterans-affairs/vfs-vaos @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group modules/vba_documents @department-of-veterans-affairs/lighthouse-banana-peels @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group modules/veteran @department-of-veterans-affairs/lighthouse-dash @department-of-veterans-affairs/lighthouse-pivot @department-of-veterans-affairs/accredited-representation-management -modules/pensions @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +modules/pensions @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group modules/veteran_confirmation @department-of-veterans-affairs/lighthouse-ninjapigs @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group modules/travel_pay @department-of-veterans-affairs/travel-pay-integration @department-of-veterans-affairs/backend-review-group modules/vye @department-of-veterans-affairs/backend-review-group #@department-of-veterans-affairs/govcio-vye-codereviewers @@ -1094,7 +1097,7 @@ spec/controllers/v0/forms_controller_spec.rb @department-of-veterans-affairs/va- spec/controllers/v0/gi_bill_feedbacks_controller_spec.rb @department-of-veterans-affairs/my-education-benefits @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/controllers/v0/hca_attachments_controller_spec.rb @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers spec/controllers/v0/health_care_applications_controller_spec.rb @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -spec/controllers/v0/income_and_assets_claims_controller_spec.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +spec/controllers/v0/income_and_assets_claims_controller_spec.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group spec/controllers/v0/mdot @department-of-veterans-affairs/va-cto-health-products @department-of-veterans-affairs/backend-review-group spec/controllers/v0/mdot/supplies_controller_spec.rb @department-of-veterans-affairs/va-cto-health-products @department-of-veterans-affairs/backend-review-group spec/controllers/v0/medical_copays_controller_spec.rb @department-of-veterans-affairs/vsa-debt-resolution @department-of-veterans-affairs/backend-review-group @@ -1180,7 +1183,7 @@ spec/factories/iam_introspection_responses.rb @department-of-veterans-affairs/oc spec/factories/iam_user_identities.rb @department-of-veterans-affairs/octo-identity spec/factories/iam_users.rb @department-of-veterans-affairs/octo-identity spec/factories/ihub/models/appointments.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -spec/factories/income_and_assets_claim.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +spec/factories/income_and_assets_claim.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group spec/factories/in_progress_forms @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/factories/ivc_champva_forms.rb @department-of-veterans-affairs/champva-engineering @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/factories/lighthouse @department-of-veterans-affairs/vfs-facilities-frontend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -1198,7 +1201,7 @@ spec/factories/mvi_profiles.rb @department-of-veterans-affairs/octo-identity spec/factories/onsite_notifications.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/factories/organizations.rb @department-of-veterans-affairs/accredited-representation-management @department-of-veterans-affairs/backend-review-group spec/factories/pagerduty_services.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -spec/factories/persistent_attachments @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pensions @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +spec/factories/persistent_attachments @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/factories/ppiu_payment_account.rb @department-of-veterans-affairs/vfs-health-modernization-initiative @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/factories/ppiu_payment_information_responses.rb @department-of-veterans-affairs/vfs-health-modernization-initiative @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/factories/ppms @department-of-veterans-affairs/vfs-facilities-frontend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -1238,6 +1241,7 @@ spec/factories/va5495.rb @department-of-veterans-affairs/govcio-vfep-codereviewe spec/factories/va_profile @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/factories/veteran_readiness_employment_claim.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/factories/veteran_onboardings.rb @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-iir +spec/factories/persistent_attachments.rb @department-of-veterans-affairs/platform-va-product-forms @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/fixtures/ask @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/fixtures/ask/minimal.json @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/fixtures/bgs @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -1282,7 +1286,7 @@ spec/fixtures/pdf_fill/21-0781 @department-of-veterans-affairs/va-api-engineers spec/fixtures/pdf_fill/21-4142 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/fixtures/pdf_fill/21-674 @department-of-veterans-affairs/benefits-dependents-management @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/fixtures/pdf_fill/21-8940 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -spec/fixtures/pdf_fill/21P-0969 @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +spec/fixtures/pdf_fill/21P-0969 @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group spec/fixtures/pdf_fill/21P-530 @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/fixtures/pdf_fill/21P-530V2 @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/fixtures/pdf_fill/26-1880 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -1292,7 +1296,7 @@ spec/fixtures/pdf_fill/5655 @department-of-veterans-affairs/vsa-debt-resolution spec/fixtures/pdf_fill/686C-674 @department-of-veterans-affairs/benefits-dependents-management @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/fixtures/pdf_fill/extras.pdf @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/fixtures/pdf_utilities @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -spec/fixtures/pension @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +spec/fixtures/pension @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group spec/fixtures/preneeds @department-of-veterans-affairs/mbs-core-team @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/fixtures/sign_in @department-of-veterans-affairs/octo-identity spec/fixtures/supplemental_claims @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/backend-review-group @@ -1415,7 +1419,7 @@ spec/lib/va1010_forms @department-of-veterans-affairs/vfs-10-10 @department-of-v spec/lib/iam_ssoe_oauth @department-of-veterans-affairs/octo-identity spec/lib/identity @department-of-veterans-affairs/octo-identity spec/lib/ihub @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -spec/lib/income_and_assets @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +spec/lib/income_and_assets @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group spec/lib/json_marshal @department-of-veterans-affairs/vsa-healthcare-health-quest-1-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/json_schema @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/lgy @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -1424,7 +1428,7 @@ spec/lib/lighthouse/auth @department-of-veterans-affairs/benefits-management-too spec/lib/lighthouse/benefits_claims @department-of-veterans-affairs/disability-experience @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/lighthouse/benefits_documents @department-of-veterans-affairs/backend-review-group spec/lib/lighthouse/benefits_documents/service_spec.rb @department-of-veterans-affairs/backend-review-group -spec/lib/lighthouse/benefits_intake @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +spec/lib/lighthouse/benefits_intake @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group spec/lib/lighthouse/direct_deposit @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/dbex-trex @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/lighthouse/direct_deposit/payment_account_spec.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/lighthouse/facilities @department-of-veterans-affairs/vfs-facilities @@ -1449,7 +1453,7 @@ spec/lib/pdf_fill @department-of-veterans-affairs/backend-review-group spec/lib/pdf_info/metadata_spec.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/pdf_utilities @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/pension_burial @department-of-veterans-affairs/mbs-core-team @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -spec/lib/pension21p527ez/pension_military_information_spec.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +spec/lib/pension21p527ez/pension_military_information_spec.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/preneeds @department-of-veterans-affairs/mbs-core-team @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/rx @department-of-veterans-affairs/vfs-mhv-medications spec/lib/rx/client_request_spec.rb @department-of-veterans-affairs/vfs-mhv-medications @department-of-veterans-affairs/mobile-api-team @@ -1546,7 +1550,7 @@ spec/models/gids_redis_spec.rb @department-of-veterans-affairs/va-api-engineers spec/models/health_care_application_spec.rb @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/models/iam_user_identity_spec.rb @department-of-veterans-affairs/octo-identity spec/models/in_progress_form_spec.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/benefits-dependents-management -spec/models/intent_to_file_queue_exhaustion_spec.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +spec/models/intent_to_file_queue_exhaustion_spec.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group spec/models/ivc_champva_forms_spec.rb @department-of-veterans-affairs/champva-engineering @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/models/lighthouse526_document_upload_spec.rb @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/models/message_spec.rb @department-of-veterans-affairs/vfs-mhv-secure-messaging @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -1554,7 +1558,7 @@ spec/models/mhv_opt_in_flag_spec.rb @department-of-veterans-affairs/vfs-mhv-secu spec/models/mhv_user_account_spec.rb @department-of-veterans-affairs/octo-identity spec/models/mpi_data_spec.rb @department-of-veterans-affairs/octo-identity spec/models/onsite_notification_spec.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -spec/models/persistent_attachments @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pensions @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +spec/models/persistent_attachments @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/models/personal_information_log_spec.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/models/preneeds @department-of-veterans-affairs/mbs-core-team @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/models/prescription_spec.rb @department-of-veterans-affairs/vfs-mhv-medications @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -1564,7 +1568,7 @@ spec/models/redis_caching_spec.rb @department-of-veterans-affairs/va-api-enginee spec/models/schema_contract @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/models/saml_request_tracker_spec.rb @department-of-veterans-affairs/octo-identity spec/models/saved_claim @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -spec/models/saved_claim/income_and_assets_spec.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +spec/models/saved_claim/income_and_assets_spec.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group spec/models/session_spec.rb @department-of-veterans-affairs/octo-identity @department-of-veterans-affairs/octo-identity spec/models/sign_in @department-of-veterans-affairs/octo-identity spec/models/single_logout_request_spec.rb @department-of-veterans-affairs/octo-identity @@ -1625,7 +1629,7 @@ spec/requests/v0/health_care_applications_spec.rb @department-of-veterans-affair spec/requests/v0/form1010_ezrs_spec.rb @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/requests/v0/health_records_spec.rb @department-of-veterans-affairs/vfs-vaos @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/requests/http_method_not_allowed_spec.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -spec/requests/v0/form0969_spec.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group +spec/requests/v0/form0969_spec.rb @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group spec/requests/v0/id_card/announcement_subscription_spec.rb @department-of-veterans-affairs/backend-review-group spec/requests/v0/id_card/attributes_spec.rb @department-of-veterans-affairs/backend-review-group spec/requests/v0/in_progress_forms_controller_spec.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -1730,7 +1734,7 @@ spec/serializers/messaging_preference_serializer_spec.rb @department-of-veterans spec/serializers/mhv_user_account_serializer_spec.rb @department-of-veterans-affairs/octo-identity spec/serializers/onsite_notification_serializer_spec.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/serializers/payment_history_serializer_spec.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers -spec/serializers/persistent_attachment_serializer_spec.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pensions @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +spec/serializers/persistent_attachment_serializer_spec.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/serializers/persistent_attachment_va_form_serializer_spec.rb @department-of-veterans-affairs/platform-va-product-forms @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/serializers/personal_information_serializer_spec.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/serializers/post911_gi_bill_status_serializer_spec.rb @department-of-veterans-affairs/govcio-vfep-codereviewers @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group diff --git a/.github/workflows/be_review_prs.yml b/.github/workflows/be_review_prs.yml index 6b0c8e1d80e..b0bf256d2f1 100644 --- a/.github/workflows/be_review_prs.yml +++ b/.github/workflows/be_review_prs.yml @@ -57,8 +57,16 @@ jobs: if: contains(github.event.pull_request.labels.*.name, 'require-backend-approval') id: verify_approval run: | - BACKEND_REVIEWERS=$(echo '${{ steps.get_team_members.outputs.data }}' | jq -r '.[].login' | tr '\n' '|' | sed 's/|$//') - APPROVALS=$(echo '${{ steps.check_backend_review_group_approval_status.outputs.data }}' | jq -r '.[] | select(.state == "APPROVED") | .user.login' | grep -iE "$BACKEND_REVIEWERS" | wc -l) + BACKEND_REVIEWERS=$(cat <<'EOF' | jq -r '.[].login' | tr '\n' '|' | sed 's/|$//' + ${{ steps.get_team_members.outputs.data }} + EOF + ) + + APPROVALS=$(cat <<'EOF' | jq -r '.[] | select(.state == "APPROVED") | .user.login' | grep -iE "$BACKEND_REVIEWERS" | wc -l + ${{ steps.check_backend_review_group_approval_status.outputs.data }} + EOF + ) + echo "Number of backend-review-group approvals: $APPROVALS" if [ "$APPROVALS" -eq 0 ]; then echo "approval_status=required" >> $GITHUB_OUTPUT diff --git a/.github/workflows/ready_for_review.yml b/.github/workflows/ready_for_review.yml index 13d8ca2d14e..35a76b6e6fc 100644 --- a/.github/workflows/ready_for_review.yml +++ b/.github/workflows/ready_for_review.yml @@ -25,6 +25,7 @@ jobs: ssm_parameter: /devops/VA_VSP_BOT_GITHUB_TOKEN env_variable_name: VA_VSP_BOT_GITHUB_TOKEN + # If no failures, no_failures=true - name: Audit PR Labels id: audit_pr_labels if: | @@ -36,6 +37,7 @@ jobs: run: | echo "no_failures=true" >> $GITHUB_OUTPUT + # If test-passing label is present, ready_for_review=true - name: Audit Test Passing Label id: audit_passing_labels if: | @@ -43,6 +45,7 @@ jobs: run: | echo "ready_for_review=true" >> $GITHUB_OUTPUT + # If require-backend-approval label is present, get reviews - name: Check backend-review-group approval status if: contains(github.event.pull_request.labels.*.name, 'require-backend-approval') id: check_backend_review_group_approval_status @@ -52,6 +55,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # - name: Get backend-review-group members if: contains(github.event.pull_request.labels.*.name, 'require-backend-approval') id: get_team_members @@ -65,8 +69,16 @@ jobs: if: contains(github.event.pull_request.labels.*.name, 'require-backend-approval') id: verify_approval run: | - BACKEND_REVIEWERS=$(echo '${{ steps.get_team_members.outputs.data }}' | jq -r '.[].login' | tr '\n' '|' | sed 's/|$//') - APPROVALS=$(echo '${{ steps.check_backend_review_group_approval_status.outputs.data }}' | jq -r '.[] | select(.state == "APPROVED") | .user.login' | grep -iE "$BACKEND_REVIEWERS" | wc -l) + BACKEND_REVIEWERS=$(cat <<'EOF' | jq -r '.[].login' | tr '\n' '|' | sed 's/|$//' + ${{ steps.get_team_members.outputs.data }} + EOF + ) + + APPROVALS=$(cat <<'EOF' | jq -r '.[] | select(.state == "APPROVED") | .user.login' | grep -iE "$BACKEND_REVIEWERS" | wc -l + ${{ steps.check_backend_review_group_approval_status.outputs.data }} + EOF + ) + echo "Number of backend-review-group approvals: $APPROVALS" if [ "$APPROVALS" -eq 0 ]; then echo "approval_status=required" >> $GITHUB_OUTPUT diff --git a/Gemfile b/Gemfile index 5e2db9f169d..6092e450b52 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ path 'modules' do gem 'apps_api' gem 'ask_va_api' gem 'avs' + gem 'burials' gem 'check_in' gem 'claims_api' gem 'covid_research' @@ -62,7 +63,7 @@ gem 'connect_vbms', git: 'https://github.com/adhocteam/connect_vbms', tag: 'v2.1 gem 'csv' gem 'date_validator' gem 'ddtrace' -gem 'dogstatsd-ruby', '5.6.1' +gem 'dogstatsd-ruby', '5.6.2' gem 'dry-struct' gem 'dry-types' gem 'ethon', '>=0.13.0' @@ -137,6 +138,7 @@ gem 'rails-session_cookie' gem 'redis' gem 'redis-namespace' gem 'request_store' +gem 'require_all' gem 'restforce' gem 'rgeo-geojson' gem 'roo' @@ -179,7 +181,7 @@ group :development do end group :test do - gem 'apivore', git: 'https://github.com/department-of-veterans-affairs/apivore', tag: 'v2.0.0.vsp' + gem 'apivore', git: 'https://github.com/department-of-veterans-affairs/apivore', tag: 'v2.1.0.vsp' gem 'mock_redis' gem 'pdf-inspector' gem 'rspec_junit_formatter' diff --git a/Gemfile.lock b/Gemfile.lock index d1bc0cab0ef..64f5d994697 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -14,13 +14,13 @@ GIT GIT remote: https://github.com/department-of-veterans-affairs/apivore - revision: f8ccd476f6c5301f5ebe4e2dd5b30ff0e567ffc1 - tag: v2.0.0.vsp + revision: 1c7d19c4a52f71a3ef07940697ad9520f1872dd6 + tag: v2.1.0.vsp specs: - apivore (2.0.0.vsp) + apivore (2.1.0.vsp) actionpack (>= 4) hashie (~> 5.0) - json-schema (~> 4.0) + json-schema (~> 5.0) rspec (~> 3) rspec-expectations (~> 3.1) rspec-mocks (~> 3.1) @@ -93,6 +93,7 @@ PATH sidekiq ask_va_api (0.1.0) avs (0.1.0) + burials (0.1.0) check_in (0.1.0) claims_api (0.0.1) dry-schema @@ -363,7 +364,7 @@ GEM thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.5.1) docile (1.4.0) - dogstatsd-ruby (5.6.1) + dogstatsd-ruby (5.6.2) domain_name (0.6.20240107) down (5.4.2) addressable (~> 2.8) @@ -511,7 +512,7 @@ GEM google-apis-core (>= 0.15.0, < 2.a) google-apis-discovery_v1 (~> 0.18) thor (>= 0.20, < 2.a) - google-cloud-env (2.1.1) + google-cloud-env (2.2.1) faraday (>= 1.0, < 3.a) google-protobuf (4.28.2) bigdecimal @@ -521,7 +522,7 @@ GEM ffi (~> 1) ffi-compiler (~> 1) rake (>= 13) - googleauth (1.11.0) + googleauth (1.11.1) faraday (>= 1.0, < 3.a) google-cloud-env (~> 2.1) jwt (>= 1.4, < 3.0) @@ -550,7 +551,7 @@ GEM builder (>= 2.1.2) rexml (~> 3.0) hana (1.3.7) - hashdiff (1.1.0) + hashdiff (1.1.1) hashery (2.1.2) hashie (5.0.0) hexapdf (0.47.0) @@ -590,8 +591,8 @@ GEM jruby-openssl (0.15.0-java) json (2.7.2) json (2.7.2-java) - json-schema (4.3.1) - addressable (>= 2.8) + json-schema (5.0.1) + addressable (~> 2.8) json_schemer (2.3.0) bigdecimal hana (~> 1.3) @@ -855,6 +856,7 @@ GEM uber (< 0.2.0) request_store (1.7.0) rack (>= 1.4) + require_all (3.0.0) restforce (7.5.0) faraday (>= 1.1.0, < 2.12.0) faraday-follow_redirects (<= 0.3.0, < 1.0.0) @@ -863,7 +865,7 @@ GEM hashie (>= 1.2.0, < 6.0) jwt (>= 1.5.6) retriable (3.1.2) - rexml (3.3.7) + rexml (3.3.8) rgeo (3.0.1) rgeo-activerecord (7.0.1) activerecord (>= 5.0) @@ -889,7 +891,7 @@ GEM rspec-its (1.3.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) - rspec-mocks (3.13.1) + rspec-mocks (3.13.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-rails (7.0.1) @@ -910,9 +912,9 @@ GEM rspec-support (3.13.1) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rswag-specs (2.14.0) + rswag-specs (2.15.0) activesupport (>= 5.2, < 8.0) - json-schema (>= 2.2, < 5.0) + json-schema (>= 2.2, < 6.0) railties (>= 5.2, < 8.0) rspec-core (>= 2.14) rswag-ui (2.15.0) @@ -1021,7 +1023,7 @@ GEM staccato (0.5.3) statsd-instrument (3.9.2) stringio (3.1.1) - strong_migrations (2.0.0) + strong_migrations (2.0.1) activerecord (>= 6.1) super_diff (0.13.0) attr_extras (>= 6.2.4) @@ -1071,7 +1073,7 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webmock (3.23.1) + webmock (3.24.0) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) @@ -1128,6 +1130,7 @@ DEPENDENCIES brakeman breakers bundler-audit + burials! byebug carrierwave carrierwave-aws @@ -1147,7 +1150,7 @@ DEPENDENCIES ddtrace debts_api! dhp_connected_devices! - dogstatsd-ruby (= 5.6.1) + dogstatsd-ruby (= 5.6.2) dry-struct dry-types ethon (>= 0.13.0) @@ -1246,6 +1249,7 @@ DEPENDENCIES redis-namespace representation_management! request_store + require_all restforce rgeo-geojson roo diff --git a/app/controllers/flipper_controller.rb b/app/controllers/flipper_controller.rb index f6aa7927a40..9853fc63543 100644 --- a/app/controllers/flipper_controller.rb +++ b/app/controllers/flipper_controller.rb @@ -3,6 +3,12 @@ class FlipperController < ApplicationController service_tag 'feature-flag' skip_before_action :authenticate + + def login + # Swallow auth token and redirect to /flipper/features with a param for redirecting + redirect_to "/flipper/features?redirect=#{params[:feature_name]}" + end + def logout cookies.delete :api_session redirect_to '/flipper/features' diff --git a/app/controllers/v0/caregivers_assistance_claims_controller.rb b/app/controllers/v0/caregivers_assistance_claims_controller.rb index fb3f082c5e2..dde10aa9648 100644 --- a/app/controllers/v0/caregivers_assistance_claims_controller.rb +++ b/app/controllers/v0/caregivers_assistance_claims_controller.rb @@ -43,13 +43,15 @@ def download_pdf client_file_name = file_name_for_pdf(@claim.veteran_data) file_contents = File.read(source_file_path) - # rubocop:disable Lint/NonAtomicFileOperation - File.delete(source_file_path) if File.exist?(source_file_path) - # rubocop:enable Lint/NonAtomicFileOperation + File.delete(source_file_path) if !Flipper.enabled?(:caregiver1010) && File.exist?(source_file_path) auditor.record(:pdf_download) send_data file_contents, filename: client_file_name, type: 'application/pdf', disposition: 'attachment' + ensure + if Flipper.enabled?(:caregiver1010) && (source_file_path && File.exist?(source_file_path)) + File.delete(source_file_path) + end end def facilities diff --git a/app/controllers/v0/my_va/submission_statuses_controller.rb b/app/controllers/v0/my_va/submission_statuses_controller.rb index 538a413d0fd..07c4feff161 100644 --- a/app/controllers/v0/my_va/submission_statuses_controller.rb +++ b/app/controllers/v0/my_va/submission_statuses_controller.rb @@ -28,7 +28,7 @@ def controller_enabled? end def allowed_forms - %w[20-10206 20-10207 21-0845 21-0966 21-0972 21-10210 21-4142 21-4142a 21P-0847] + %w[20-10206 20-10207 21-0845 21-0972 21-10210 21-4142 21-4142a 21P-0847] end def serializable_from(result) diff --git a/app/models/saved_claim/caregivers_assistance_claim.rb b/app/models/saved_claim/caregivers_assistance_claim.rb index 4424b9055de..f21b0a0a783 100644 --- a/app/models/saved_claim/caregivers_assistance_claim.rb +++ b/app/models/saved_claim/caregivers_assistance_claim.rb @@ -24,7 +24,13 @@ def process_attachments! def to_pdf(filename = nil, **) # We never save the claim, so we don't have an id to provide for the filename. # Instead we'll create a filename with this format "10-10cg_{uuid}" - PdfFill::Filler.fill_form(self, filename || guid, **) + name = filename || guid + PdfFill::Filler.fill_form(self, name, **) + rescue => e + Rails.logger.error("Failed to generate PDF: #{e.message}") + PersonalInformationLog.create(data: { form: parsed_form, file_name: name }, + error_class: '1010CGPdfGenerationError') + raise end # SavedClaims require regional_office to be defined, CaregiversAssistanceClaim has no purpose for it. diff --git a/app/models/user.rb b/app/models/user.rb index d17c67ce799..5d89ccdec56 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -48,6 +48,10 @@ def account_id @account_id ||= account&.id end + def initial_sign_in + user_account.created_at + end + def credential_lock return @credential_lock unless @credential_lock.nil? diff --git a/app/services/login/after_login_actions.rb b/app/services/login/after_login_actions.rb index f66508e9526..b4963b50af5 100644 --- a/app/services/login/after_login_actions.rb +++ b/app/services/login/after_login_actions.rb @@ -20,6 +20,7 @@ def perform Login::UserAcceptableVerifiedCredentialUpdater.new(user_account: @current_user.user_account).perform update_account_login_stats(login_type) id_mismatch_validations + create_mhv_account if Settings.test_user_dashboard.env == 'staging' TestUserDashboard::UpdateUser.new(current_user).call(Time.current) @@ -53,5 +54,11 @@ def check_id_mismatch(identity_value, mpi_value, error_message) Rails.logger.warn("[SessionsController version:v1] #{error_message}", error_data) end end + + def create_mhv_account + return unless Settings.mhv.account_creation.create_after_login + + MHV::AccountCreatorJob.perform_async(current_user.user_verification.id) + end end end diff --git a/app/services/sign_in/user_code_map_creator.rb b/app/services/sign_in/user_code_map_creator.rb index 8bf4d1a3d29..03aceeea36a 100644 --- a/app/services/sign_in/user_code_map_creator.rb +++ b/app/services/sign_in/user_code_map_creator.rb @@ -33,6 +33,7 @@ def perform create_user_acceptable_verified_credential create_terms_code_container if needs_accepted_terms_of_use? create_code_container + create_mhv_account user_code_map end @@ -61,6 +62,12 @@ def create_code_container device_sso:).save! end + def create_mhv_account + return unless Settings.mhv.account_creation.create_after_login + + MHV::AccountCreatorJob.perform_async(user_verification.id) + end + def device_sso state_payload.scope == Constants::Auth::DEVICE_SSO end diff --git a/app/services/users/profile.rb b/app/services/users/profile.rb index ca08cef49e4..8b98ecf2630 100644 --- a/app/services/users/profile.rb +++ b/app/services/users/profile.rb @@ -87,7 +87,8 @@ def profile sec_id: user.sec_id, logingov_uuid: user.logingov_uuid, idme_uuid: user.idme_uuid, - id_theft_flag: user.id_theft_flag + id_theft_flag: user.id_theft_flag, + initial_sign_in: user.initial_sign_in } end # rubocop:enable Metrics/MethodLength diff --git a/app/sidekiq/benefits_intake_status_job.rb b/app/sidekiq/benefits_intake_status_job.rb index 9ee83009afb..ae0aef53e61 100644 --- a/app/sidekiq/benefits_intake_status_job.rb +++ b/app/sidekiq/benefits_intake_status_job.rb @@ -108,6 +108,8 @@ def log_result(result, form_id, uuid, time_to_transition = nil, error_message = StatsD.increment("#{STATS_KEY}.#{form_id}.#{result}") StatsD.increment("#{STATS_KEY}.all_forms.#{result}") if result == 'failure' + tags = [service: 'veteran-facing-forms', function: "#{form_id} form submission to Lighthouse"] + statsd.increment('silent_failure', tags:) Rails.logger.error('BenefitsIntakeStatusJob', result:, form_id:, uuid:, time_to_transition:, error_message:) else Rails.logger.info('BenefitsIntakeStatusJob', result:, form_id:, uuid:, time_to_transition:) diff --git a/app/sidekiq/evss/disability_compensation_form/upload_bdd_instructions.rb b/app/sidekiq/evss/disability_compensation_form/upload_bdd_instructions.rb index e8694295586..ce750abebaf 100644 --- a/app/sidekiq/evss/disability_compensation_form/upload_bdd_instructions.rb +++ b/app/sidekiq/evss/disability_compensation_form/upload_bdd_instructions.rb @@ -8,6 +8,9 @@ class UploadBddInstructions < Job extend Logging::ThirdPartyTransaction::MethodWrapper STATSD_KEY_PREFIX = 'worker.evss.submit_form526_bdd_instructions' + # 'Other Correspondence' document type + BDD_INSTRUCTIONS_DOCUMENT_TYPE = 'L023' + BDD_INSTRUCTIONS_FILE_NAME = 'BDD_Instructions.pdf' # retry for one day sidekiq_options retry: 14 @@ -35,6 +38,13 @@ class UploadBddInstructions < Job bgjob_errors: bgjob_errors.merge(new_error) ) + if Flipper.enabled?(:disability_compensation_use_api_provider_for_bdd_instructions) + submission = Form526Submission.find(form526_submission_id) + + provider = api_upload_provider(submission) + provider.log_uploading_job_failure(self, error_class, error_message) + end + StatsD.increment("#{STATSD_KEY_PREFIX}.exhausted") ::Rails.logger.warn( @@ -67,6 +77,21 @@ class UploadBddInstructions < Job } ) + def self.api_upload_provider(submission) + user = User.find(submission.user_uuid) + + ApiProviderFactory.call( + type: ApiProviderFactory::FACTORIES[:supplemental_document_upload], + options: { + form526_submission: submission, + document_type: BDD_INSTRUCTIONS_DOCUMENT_TYPE, + statsd_metric_prefix: STATSD_KEY_PREFIX + }, + current_user: user, + feature_toggle: ApiProviderFactory::FEATURE_TOGGLE_UPLOAD_BDD_INSTRUCTIONS + ) + end + # Submits a BDD instruction PDF in to EVSS # # @param submission_id [Integer] The {Form526Submission} id @@ -89,21 +114,20 @@ def perform(submission_id) private def upload_bdd_instructions - client.upload(file_body, document_data) + if Flipper.enabled?(:disability_compensation_use_api_provider_for_bdd_instructions) + provider = self.class.api_upload_provider(submission) + + upload_document = provider.generate_upload_document(BDD_INSTRUCTIONS_FILE_NAME) + provider.submit_upload_document(upload_document, file_body) + else + EVSS::DocumentsService.new(submission.auth_headers).upload(file_body, document_data) + end end def file_body @file_body ||= File.read('lib/evss/disability_compensation_form/bdd_instructions.pdf') end - def client - @client ||= if Flipper.enabled?(:disability_compensation_lighthouse_document_service_provider) - # TODO: create client from lighthouse document service - else - EVSS::DocumentsService.new(submission.auth_headers) - end - end - def retryable_error_handler(error) super(error) raise error @@ -112,10 +136,10 @@ def retryable_error_handler(error) def document_data @document_data ||= EVSSClaimDocument.new( evss_claim_id: submission.submitted_claim_id, - file_name: 'BDD_Instructions.pdf', + file_name: BDD_INSTRUCTIONS_FILE_NAME, tracked_item_id: nil, - document_type: 'L023' - ) # 'Other Correspondence' + document_type: BDD_INSTRUCTIONS_DOCUMENT_TYPE + ) end end end diff --git a/app/sidekiq/form1010cg/submission_job.rb b/app/sidekiq/form1010cg/submission_job.rb index 6b323b8e9e8..ad689d318d3 100644 --- a/app/sidekiq/form1010cg/submission_job.rb +++ b/app/sidekiq/form1010cg/submission_job.rb @@ -16,17 +16,10 @@ class SubmissionJob end def retry_limits_for_notification - return [1, 10] if Flipper.enabled?(:caregiver1010) - - [10] + [1, 10] end def notify(params) - unless Flipper.enabled?(:caregiver1010) - StatsD.increment("#{STATSD_KEY_PREFIX}failed_ten_retries", tags: ["params:#{params}"]) - return - end - # Add 1 to retry_count to match retry_monitoring logic retry_count = Integer(params['retry_count']) + 1 @@ -50,21 +43,7 @@ def perform(claim_id) log_exception_to_sentry(e) StatsD.increment("#{STATSD_KEY_PREFIX}retries") - increment_applications_retried(claim_id) unless Flipper.enabled?(:caregiver1010) - raise end - - private - - # TODO: @coope93 to remove increment method and feature (:caregiver1010) after validating functionality - def increment_applications_retried(claim_id) - redis_key = "Form1010cg::SubmissionJob:#{claim_id}" - return if $redis.get(redis_key).present? - - StatsD.increment("#{STATSD_KEY_PREFIX}applications_retried") - - $redis.set(redis_key, 't') - end end end diff --git a/app/sidekiq/terms_of_use/sign_up_service_updater_job.rb b/app/sidekiq/terms_of_use/sign_up_service_updater_job.rb index e7621ae601a..0dd8770d114 100644 --- a/app/sidekiq/terms_of_use/sign_up_service_updater_job.rb +++ b/app/sidekiq/terms_of_use/sign_up_service_updater_job.rb @@ -33,7 +33,7 @@ def perform(user_account_uuid, version) @user_account_uuid = user_account_uuid @version = version - return unless sec_id? + return if missing_sec_id? || agreement_unchanged? log_updated_icn terms_of_use_agreement.accepted? ? accept : decline @@ -48,23 +48,42 @@ def log_updated_icn end end + def map_client + @map_client ||= MAP::SignUp::Service.new + end + + def map_status + @map_status ||= map_client.status(icn: mpi_profile.icn) + end + + def agreement_unchanged? + if terms_of_use_agreement.declined? != map_status[:opt_out] || + terms_of_use_agreement.accepted? != map_status[:agreement_signed] + return false + end + + Rails.logger.info("#{LOG_TITLE} Not updating Sign Up Service due to unchanged agreement", + { icn: user_account.icn }) + true + end + def accept - MAP::SignUp::Service.new.agreements_accept(icn: mpi_profile.icn, signature_name:, version:) + map_client.agreements_accept(icn: mpi_profile.icn, signature_name:, version:) end def decline - MAP::SignUp::Service.new.agreements_decline(icn: mpi_profile.icn) + map_client.agreements_decline(icn: mpi_profile.icn) end - def sec_id? + def missing_sec_id? if mpi_profile.sec_id.present? validate_multiple_sec_ids - return true + return false end Rails.logger.info("#{LOG_TITLE} Sign Up Service not updated due to user missing sec_id", { icn: user_account.icn }) - false + true end def validate_multiple_sec_ids diff --git a/app/uploaders/simple_forms_api/form_remediation/uploader.rb b/app/uploaders/simple_forms_api/form_remediation/uploader.rb index b764a78d500..01e013ca71a 100644 --- a/app/uploaders/simple_forms_api/form_remediation/uploader.rb +++ b/app/uploaders/simple_forms_api/form_remediation/uploader.rb @@ -7,24 +7,6 @@ module FormRemediation class Uploader < CarrierWave::Uploader::Base include UploaderVirusScan - class << self - def s3_settings - config = Configuration::Base.new - config.s3_settings - end - - def new_s3_resource - client = Aws::S3::Client.new(region: s3_settings.region) - Aws::S3::Resource.new(client:) - end - - def get_s3_link(file_path) - new_s3_resource.bucket(s3_settings.bucket) - .object(file_path) - .presigned_url(:get, expires_in: 30.minutes.to_i) - end - end - def size_range (1.byte)...(150.megabytes) end @@ -34,7 +16,7 @@ def extension_allowlist %w[bmp csv gif jpeg jpg json pdf png tif tiff txt zip] end - def initialize(directory:, config: Configuration::Base.new) + def initialize(directory:, config:) raise 'The S3 directory is missing.' if directory.blank? raise 'The configuration is missing.' unless config @@ -49,10 +31,30 @@ def store_dir @directory end + def get_s3_link(file_path) + s3_obj(file_path).presigned_url(:get, expires_in: 30.minutes.to_i) + end + + def get_s3_file(from_path, to_path) + s3_obj(from_path).get(response_target: to_path) + rescue Aws::S3::Errors::NoSuchKey + nil + rescue => e + config.handle_error('An error occured while downloading the file.', e) + end + private + attr_reader :config + + def s3_obj(file_path) + client = Aws::S3::Client.new(region: config.s3_settings.region) + resource = Aws::S3::Resource.new(client:) + resource.bucket(config.s3_settings.bucket).object(file_path) + end + def set_storage_options! - settings = @config.s3_settings + settings = config.s3_settings self.aws_credentials = { region: settings.region } self.aws_acl = 'private' diff --git a/config/features.yml b/config/features.yml index 48d5f481381..65d35b828ed 100644 --- a/config/features.yml +++ b/config/features.yml @@ -71,7 +71,7 @@ features: description: Enables sending CARMA the creation timestamp of a claim as a metadata submitted_at value caregiver1010: actor_type: user - description: Enables exposing job object in caregiver submission job + description: Enables new features while investigating 1010CG errors hca_browser_monitoring_enabled: actor_type: user description: Enables browser monitoring for the health care application. @@ -1545,9 +1545,12 @@ features: disability_compensation_lighthouse_generate_pdf: actor_type: user description: If enabled uses the lighthouse Benefits Claims service to generate a 526 pdf - disability_compensation_lighthouse_upload_supplemental_document: + disability_compensation_use_api_provider_for_bdd_instructions: actor_type: user - description: If enabled uses the Lighthouse Benefits Documents API to submit Form 526 documents + description: Provide a temporary killswitch for using the ApiProviderFactory to select an API for uploading BDD instructions + disability_compensation_upload_bdd_instructions_to_lighthouse: + actor_type: user + description: If enabled uploads BDD instructions to Lighthouse Benefits Documents API instead of EVSS disablity_benefits_browser_monitoring_enabled: actor_type: user description: Datadog RUM monitoring for disability benefits applications diff --git a/config/initializers/flipper.rb b/config/initializers/flipper.rb index a92b39d119d..37392431ce4 100644 --- a/config/initializers/flipper.rb +++ b/config/initializers/flipper.rb @@ -4,8 +4,7 @@ require 'flipper/adapters/active_record' require 'active_support/cache' require 'flipper/adapters/active_support_cache_store' -require 'flipper/action_patch' -require 'flipper/configuration_patch' +require 'flipper/ui/action_patch' require 'flipper/instrumentation/event_subscriber' FLIPPER_FEATURE_CONFIG = YAML.safe_load(File.read(Rails.root.join('config', 'features.yml'))) @@ -16,6 +15,12 @@ end Rails.application.reloader.to_prepare do + FLIPPER_ACTOR_USER = 'user' + FLIPPER_ACTOR_STRING = 'cookie_id' + + # Modify Flipper::UI::Action to use our custom views + Flipper::UI::Action.prepend(Flipper::UI::ActionPatch) + Flipper.configure do |config| config.default do activerecord_adapter = Flipper::Adapters::ActiveRecord.new @@ -30,17 +35,17 @@ end end - # Modify Flipper::UI::Configuration to accept a custom view path. - Flipper::UI::Configuration.prepend(FlipperExtensions::ConfigurationPatch) - Flipper::UI.configure do |config| - config.custom_views_path = Rails.root.join('lib', 'flipper', 'views') + config.feature_creation_enabled = false + config.feature_removal_enabled = false + config.show_feature_description_in_list = true + config.confirm_disable = true + config.confirm_fully_enable = true + config.descriptions_source = lambda do |_keys| + FLIPPER_FEATURE_CONFIG['features'].transform_values { |value| value['description'] } + end end - FLIPPER_ACTOR_USER = 'user' - FLIPPER_ACTOR_STRING = 'cookie_id' - - Flipper::UI.configuration.feature_creation_enabled = false # Make sure that each feature we reference in code is present in the UI, as long as we have a Database already added_flippers = [] begin @@ -69,8 +74,4 @@ # make sure we can still run rake tasks before table has been created nil end - - # Modify Flipper::UI::Action to use custom views if they exist - # and to add descriptions and types for features. - Flipper::UI::Action.prepend(FlipperExtensions::ActionPatch) end diff --git a/config/initializers/warden_github.rb b/config/initializers/warden_github.rb index 0c9ad66ab9f..60d8a19ec2f 100644 --- a/config/initializers/warden_github.rb +++ b/config/initializers/warden_github.rb @@ -8,18 +8,32 @@ def authenticate! elsif scope == :coverband && session[:coverband_user].present? success!(session[:coverband_user]) redirect!(request.url) - elsif scope == :flipper && session[:flipper_user].present? - success!(session[:flipper_user]) - redirect!(request.url) else super end end + def begin_flow! + # We want this redirect value for later in the flow + if request.path.include?('/flipper') + redirect = request.env['QUERY_STRING']&.split('=')&.[](1) + custom_session[:redirect] = redirect if redirect.present? + end + + super + end + def finalize_flow! session[:sidekiq_user] = load_user if scope == :sidekiq session[:coverband_user] = load_user if scope == :coverband - session[:flipper_user] = load_user if scope == :flipper + if scope == :flipper + # now we can grab the actual URL without the redirect param and redirect to the intended page + session[:flipper_user] = load_user + url = custom_session['return_to'].split('?').first + url += "/#{custom_session[:redirect]}" if custom_session[:redirect] + custom_session['return_to'] = url + end + super end end diff --git a/config/routes.rb b/config/routes.rb index 50caf0846b4..e0f84b38003 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'flipper/admin_user_constraint' +require 'flipper/route_authorization_constraint' Rails.application.routes.draw do match '/v0/*path', to: 'application#cors_preflight', via: [:options] @@ -485,8 +485,9 @@ mount MockedAuthentication::Engine, at: '/mocked_authentication' end - get '/flipper/features/logout', to: 'flipper#logout' - mount Flipper::UI.app(Flipper.instance) => '/flipper', constraints: Flipper::AdminUserConstraint + get '/flipper/logout', to: 'flipper#logout' + get '/flipper/login', to: 'flipper#login' + mount Flipper::UI.app(Flipper.instance) => '/flipper', constraints: Flipper::RouteAuthorizationConstraint unless Rails.env.test? mount Coverband::Reporters::Web.new, at: '/coverband', constraints: GithubAuthentication::CoverbandReportersWeb.new diff --git a/config/settings.yml b/config/settings.yml index b61313327bd..9f6f33c3fae 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -549,6 +549,7 @@ mhv: mock: true host: https://apigw-intb.aws.myhealth.va.gov access_key: some-access-key + create_after_login: false sts: service_account_id: c34b86f2130ff3cd4b1d309bc09d8740 issuer: http://localhost:3000 diff --git a/config/ssoe_idp_int_metadata_isam.xml b/config/ssoe_idp_int_metadata_isam.xml index 2b76e04d64d..8f316c7dbba 100644 --- a/config/ssoe_idp_int_metadata_isam.xml +++ b/config/ssoe_idp_int_metadata_isam.xml @@ -1,22 +1,22 @@ - + - + - fpyWojHjtLWgNWHWg6BTQwPqD3o= + MJZSH3Y8rgJKCZHOQPLQRtZxt8c= - ptoRQevsybKxh5JedE/2OAOmmOdoPboSA/gA5RcnFIgajLJjFc4jYryxQFqNaiR9ZDbpylevBucchd12RFzbBePEPjKLnxJrXXH/YkXnhhmYwWESCC/gxBRkEy64VIIf3A4fALacgAErisjeztR2zzXgb+ukLTZq9O5j9/7+1obnZ3/hFb8XylrXjSYbPEQ7WAatSGrm2nL+2A3P/oiG0AjypU+CtCPBxXrZGRD1d3725rKW7MzK61n6oAE23pPxloqHgJKY/DF3ryXc3T/5r7mUkD6FX/RQvLV6L/DviL7Lfhsqoy8otOaqwfet2xTen/To2WA2aAC5gcDzpQfofTPt0KlMdhFbWkdJJyIDWdSz/hoIZ9kaZO6RZwhe7e+YS2VIIWrD+W8R9oODlpvl1gvEZUOpQYS+bJZJt3FGliubZW+lTuRB8GHDn87g/UGO/yn9NGFT5dsKIjhlxxlEBjMPVfowxetv4P30wZ8A/KzPYNC/edAe6vuCZ+xhewGSymQiU0Kdzpif/KOpllus49GecCOfenMkWIhNHJr7awOr7LjHaSqLwhJcqaQKBuaNHjzB6Z/vCtmRvqXDnHdoTlKSOGWQgkZYAB+6C1iL6ajFpLplVZ9XbLpFcqoAj+mw0p0acIFTcXSRw0yV5xa0f2HXPXS6+hlaX06U0oSABZM= + i7sp5Yk4tWndUoZdqfNJ2fFnUHVoxFWnPXj3kOxzsWsdvYz/+DJdpJPlzWIyXgBvUsSrr6hUDRubrAlIS6E+SzNuhJldFCPfq0v1cwtX0xrsBxeF/de5vXR5A3PM//o41Ab+qnya8szKjevq92t4fKhFMcav5uIMA94qdrxQc+sSAo8reZXqAI5cV6iaesv9gG5zH8O0yOtTHqQdbnDyhSYFUQsTZMmli8qFBjb1YQ7sPkHnqL5SuJejxuE2mR42d0+34ubl62lW6Sk2wIXDokCtRsKiEcbloBiaWFzZqAO3xxtcO91klr5wxKkaCQwETTD8OSYppgTpGPKHFngpnayLilpbD8t7dTsrZoKUPev4BiyRDycgnIjIr7lJzgjTI6ASFeCNeCbJmvxXIbatRmDYyhdEj+XlS8gANnkevc43UpimTDYEelCjixeTZe4kqOmB6hIQ1ptda7/F0021kWap+vQAFBNneHMCO50hd1Fh8ZYrclQzk1gILmta8K6kwwP2wVKsMCHC9B8GsIYhg/ZB4pMm4C84qtG8gbkHwljA4cibSpKxLakxiuxkSkFsPj0XaPU5+UK+Icn1qXHz90X7/ImsmVCql1U7qG4jqLeiLNSxicbli1hMYli2MCDaAw4OWL5+q4SdwEi1mDndrggrs5S4s+txoFXixJXG9e0= - MIIH+jCCBuKgAwIBAgIQATN2LGZN6zApJ43rOeq+EjANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIgVExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjMwOTIwMDAwMDAwWhcNMjQxMDA5MjM1OTU5WjCBijELMAkGA1UEBhMCVVMxHTAbBgNVBAgTFERpc3RyaWN0IG9mIENvbHVtYmlhMRMwEQYDVQQHEwpXYXNoaW5ndG9uMSwwKgYDVQQKEyNVLlMuIERlcGFydG1lbnQgb2YgVmV0ZXJhbnMgQWZmYWlyczEZMBcGA1UEAxMQZGV2LmVhdXRoLnZhLmdvdjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2aLI8bOrETcYVXvez1TIgTSdGcqt6TfHH9LOp4I5QvUB+J093LOzO7pC2zNX/hffLTiA/FEBY6ZH9mQLupq9oMyCKRUJfs9YgoksMqpoAAG/k0Gptx+zFIruVqGUWDNVCJ2yf8qdP5i8lQy+t6f5ILoBlbupgvGoHppYrkSMJF4B4L5hBYWy/b4EloWWpTmCRK51DqkQZp95eeT8zvScEEhXsDXBXHUIoSHdkN+/nGSYUuF6JKKVvFI1WTWIT9N56xIjm209AMvsV5dn7VXHBlqR5UEW2tz0VQWBy4tB2/eUCWIJ3QADmT+XzJcDFk9ffGpdbSHECsV6mcq9DYZ9OcE9Y2YVSz5WCxuZy8nhnLfWicehz67lgY/bJlB0NxYPhjKif4Wh9b8T8B9fZ738xPcW9/5hk0DRU3u61BeMavt20EUOfRp8Oz5HvMCGkrTR7eI0gwblb74VgXzEhEY/6/tBBM4JVPVoPQ+qhLQqJ1yvayJesr0NO01knBO/bRQhXiNiMjeoublbHJCX1IMgpcFUWmJsBpzFw2O1sYo3qvJrSiTa/Bzdd8qh8aWKipMklY7RgC+N+X3c3PLV5pH2mOuy2iR7qBi45ww2SjBFPo+1iNGehTZx3fjmEHyA+kiTvkeOwPeX2HRVC22wOCWAKSkRso4V5AXJCfl2absLAFAgMBAAGjggOKMIIDhjAfBgNVHSMEGDAWgBR0hYDAZsffN97PvSk3qgMdvu3NFzAdBgNVHQ4EFgQURgYkVZOloSagvssqZwolgE0zty4wGwYDVR0RBBQwEoIQZGV2LmVhdXRoLnZhLmdvdjA+BgNVHSAENzA1MDMGBmeBDAECAjApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjCBnwYDVR0fBIGXMIGUMEigRqBEhkJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHMlRMU1JTQVNIQTI1NjIwMjBDQTEtMS5jcmwwSKBGoESGQmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNybDCBhwYIKwYBBQUHAQEEezB5MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wUQYIKwYBBQUHMAKGRWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNydDAMBgNVHRMBAf8EAjAAMIIBfAYKKwYBBAHWeQIEAgSCAWwEggFoAWYAdgB2/4g/Crb7lVHCYcz1h7o0tKTNuyncaEIKn+ZnTFo6dAAAAYq0W1BeAAAEAwBHMEUCICDzD04088p0Hi1vk8ffZPqqr89toO2MH7HsFzulEO5VAiEA0i1c5qycL1aRAVp8N9nbIzORORZghEnYYsRfmQWMn4sAdQBIsONr2qZHNA/lagL6nTDrHFIBy1bdLIHZu7+rOdiEcwAAAYq0W1AnAAAEAwBGMEQCIQCH+ftpruo2Ijj05VZIQu3V47LOeqP/SA8o0GeFQzjrLQIfJ00xVwQdbBkiWdSp7BT9yQ5T49js6xSiNscItF9+kQB1ANq2v2s/tbYin5vCu1xr6HCRcWy7UYSFNL2kPTBI1/urAAABirRbUBcAAAQDAEYwRAIgE/kR/q0hJj0EusxBvU3TfFDiT2BIsb6GKRcSK9fBuXICIGZVaGWjPaiZi5X08rWQ9B1w8+N5bRfbRoJYPWTHXgXLMA0GCSqGSIb3DQEBCwUAA4IBAQAd3cgFfrI/wjyKDx4SbQEuqMX1pCSoOwQnxvfuNq1PsDttJlNYrWkgzj27t9Sm4nqbAc5pqxRyx6/D0tFiJYs8QaBvIhSLKx9fhu3l7SHvqXPKjCCi+pBjLChu8fKH1G6dvl8YrjuTw+4G0nmzTKwBRf61loVc/zBz4f1+lxvkLYdQGUTYV7zyBNFqlt1SbW252kLFSGtTHoIp7x8eAmh6k1qoOWK4FSEmK1wzt+yNJlxg0n8s0wDcGwGcdVCV81YT5OEU4C34cPb9+DLW4nAH/c10bbTGyVqnl7CTV+6VVFDB46bJErBT4Z3VOp2zPI/5GTdl+eeb4hkIHI0ytxCg + MIIH/zCCBuegAwIBAgIQBcL35cC7wMJpntbZ9IogNDANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIgVExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjQwOTIzMDAwMDAwWhcNMjUxMDA5MjM1OTU5WjCBijELMAkGA1UEBhMCVVMxHTAbBgNVBAgTFERpc3RyaWN0IG9mIENvbHVtYmlhMRMwEQYDVQQHEwpXYXNoaW5ndG9uMSwwKgYDVQQKEyNVLlMuIERlcGFydG1lbnQgb2YgVmV0ZXJhbnMgQWZmYWlyczEZMBcGA1UEAxMQZGV2LmVhdXRoLnZhLmdvdjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2aLI8bOrETcYVXvez1TIgTSdGcqt6TfHH9LOp4I5QvUB+J093LOzO7pC2zNX/hffLTiA/FEBY6ZH9mQLupq9oMyCKRUJfs9YgoksMqpoAAG/k0Gptx+zFIruVqGUWDNVCJ2yf8qdP5i8lQy+t6f5ILoBlbupgvGoHppYrkSMJF4B4L5hBYWy/b4EloWWpTmCRK51DqkQZp95eeT8zvScEEhXsDXBXHUIoSHdkN+/nGSYUuF6JKKVvFI1WTWIT9N56xIjm209AMvsV5dn7VXHBlqR5UEW2tz0VQWBy4tB2/eUCWIJ3QADmT+XzJcDFk9ffGpdbSHECsV6mcq9DYZ9OcE9Y2YVSz5WCxuZy8nhnLfWicehz67lgY/bJlB0NxYPhjKif4Wh9b8T8B9fZ738xPcW9/5hk0DRU3u61BeMavt20EUOfRp8Oz5HvMCGkrTR7eI0gwblb74VgXzEhEY/6/tBBM4JVPVoPQ+qhLQqJ1yvayJesr0NO01knBO/bRQhXiNiMjeoublbHJCX1IMgpcFUWmJsBpzFw2O1sYo3qvJrSiTa/Bzdd8qh8aWKipMklY7RgC+N+X3c3PLV5pH2mOuy2iR7qBi45ww2SjBFPo+1iNGehTZx3fjmEHyA+kiTvkeOwPeX2HRVC22wOCWAKSkRso4V5AXJCfl2absLAFAgMBAAGjggOPMIIDizAfBgNVHSMEGDAWgBR0hYDAZsffN97PvSk3qgMdvu3NFzAdBgNVHQ4EFgQURgYkVZOloSagvssqZwolgE0zty4wGwYDVR0RBBQwEoIQZGV2LmVhdXRoLnZhLmdvdjA+BgNVHSAENzA1MDMGBmeBDAECAjApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjCBnwYDVR0fBIGXMIGUMEigRqBEhkJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHMlRMU1JTQVNIQTI1NjIwMjBDQTEtMS5jcmwwSKBGoESGQmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNybDCBhwYIKwYBBQUHAQEEezB5MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wUQYIKwYBBQUHMAKGRWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNydDAMBgNVHRMBAf8EAjAAMIIBgQYKKwYBBAHWeQIEAgSCAXEEggFtAWsAdwAS8U40vVNyTIQGGcOPP3oT+Oe1YoeInG0wBYTr5YYmOgAAAZIfsrgNAAAEAwBIMEYCIQCOtP/IYo8spdSjpTyoFknFBiJDBGWb5LgQkDWs/X+AEgIhAMAp/I9GYj1Go9nyeOM+UmXVI920iIL7i9ha0Rgr3nrIAHcAfVkeEuF4KnscYWd8Xv340IdcFKBOlZ65Ay/ZDowuebgAAAGSH7K3wQAABAMASDBGAiEA/hi0zVbIniP97LM+AK3WxbxXAbTiZrgV9GZvcRcMimECIQCwK2qSJtOyCkjD7j7mHeEyD82+JlbRGS5ex1QdW6o5MwB3AObSMWNAd4zBEEEG13G5zsHSQPaWhIb7uocyHf0eN45QAAABkh+yt9kAAAQDAEgwRgIhAMBO8WF+YiV1UqfWUYVMiOZdaDN9pGWMoEY8mxZKHm9VAiEAvMNmRSAbfctAUWb+iHwLPHeiFP8gplxoGyeWLukur/kwDQYJKoZIhvcNAQELBQADggEBAKRTS8KmQc/olPb1czBdqetfQW/c4B9hq6+Wu9HKHrq3Z7/ETarE5V6cY6WS+OYEpy2YVTRQsIp0x41RDGlaG91l6zYDQGSoiTe2iilsdNC8z1JzBMrMC/oMzYy5PTBYBxTtq5XbpagN5mhShPXPhQm45dh8u5LmRj4y3A7+NTEHhGFJJy0Pdm3EEN3A1kZY34pml3E7lIskulIF81IqFNnmPoPw6fuub3+cdmWKM9PgVkegF106DgJyUJ9oiYk5BJjKDLhHk1GEBz6A9+rctbFdGmKfYBGAPDBoCe3hAtv46WETTbBB72u7cNcLGhR3nNWPtGwRYAfvnuMtBc+sL5Q= @@ -24,19 +24,21 @@ - MIIH+jCCBuKgAwIBAgIQATN2LGZN6zApJ43rOeq+EjANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIgVExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjMwOTIwMDAwMDAwWhcNMjQxMDA5MjM1OTU5WjCBijELMAkGA1UEBhMCVVMxHTAbBgNVBAgTFERpc3RyaWN0IG9mIENvbHVtYmlhMRMwEQYDVQQHEwpXYXNoaW5ndG9uMSwwKgYDVQQKEyNVLlMuIERlcGFydG1lbnQgb2YgVmV0ZXJhbnMgQWZmYWlyczEZMBcGA1UEAxMQZGV2LmVhdXRoLnZhLmdvdjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2aLI8bOrETcYVXvez1TIgTSdGcqt6TfHH9LOp4I5QvUB+J093LOzO7pC2zNX/hffLTiA/FEBY6ZH9mQLupq9oMyCKRUJfs9YgoksMqpoAAG/k0Gptx+zFIruVqGUWDNVCJ2yf8qdP5i8lQy+t6f5ILoBlbupgvGoHppYrkSMJF4B4L5hBYWy/b4EloWWpTmCRK51DqkQZp95eeT8zvScEEhXsDXBXHUIoSHdkN+/nGSYUuF6JKKVvFI1WTWIT9N56xIjm209AMvsV5dn7VXHBlqR5UEW2tz0VQWBy4tB2/eUCWIJ3QADmT+XzJcDFk9ffGpdbSHECsV6mcq9DYZ9OcE9Y2YVSz5WCxuZy8nhnLfWicehz67lgY/bJlB0NxYPhjKif4Wh9b8T8B9fZ738xPcW9/5hk0DRU3u61BeMavt20EUOfRp8Oz5HvMCGkrTR7eI0gwblb74VgXzEhEY/6/tBBM4JVPVoPQ+qhLQqJ1yvayJesr0NO01knBO/bRQhXiNiMjeoublbHJCX1IMgpcFUWmJsBpzFw2O1sYo3qvJrSiTa/Bzdd8qh8aWKipMklY7RgC+N+X3c3PLV5pH2mOuy2iR7qBi45ww2SjBFPo+1iNGehTZx3fjmEHyA+kiTvkeOwPeX2HRVC22wOCWAKSkRso4V5AXJCfl2absLAFAgMBAAGjggOKMIIDhjAfBgNVHSMEGDAWgBR0hYDAZsffN97PvSk3qgMdvu3NFzAdBgNVHQ4EFgQURgYkVZOloSagvssqZwolgE0zty4wGwYDVR0RBBQwEoIQZGV2LmVhdXRoLnZhLmdvdjA+BgNVHSAENzA1MDMGBmeBDAECAjApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjCBnwYDVR0fBIGXMIGUMEigRqBEhkJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHMlRMU1JTQVNIQTI1NjIwMjBDQTEtMS5jcmwwSKBGoESGQmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNybDCBhwYIKwYBBQUHAQEEezB5MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wUQYIKwYBBQUHMAKGRWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNydDAMBgNVHRMBAf8EAjAAMIIBfAYKKwYBBAHWeQIEAgSCAWwEggFoAWYAdgB2/4g/Crb7lVHCYcz1h7o0tKTNuyncaEIKn+ZnTFo6dAAAAYq0W1BeAAAEAwBHMEUCICDzD04088p0Hi1vk8ffZPqqr89toO2MH7HsFzulEO5VAiEA0i1c5qycL1aRAVp8N9nbIzORORZghEnYYsRfmQWMn4sAdQBIsONr2qZHNA/lagL6nTDrHFIBy1bdLIHZu7+rOdiEcwAAAYq0W1AnAAAEAwBGMEQCIQCH+ftpruo2Ijj05VZIQu3V47LOeqP/SA8o0GeFQzjrLQIfJ00xVwQdbBkiWdSp7BT9yQ5T49js6xSiNscItF9+kQB1ANq2v2s/tbYin5vCu1xr6HCRcWy7UYSFNL2kPTBI1/urAAABirRbUBcAAAQDAEYwRAIgE/kR/q0hJj0EusxBvU3TfFDiT2BIsb6GKRcSK9fBuXICIGZVaGWjPaiZi5X08rWQ9B1w8+N5bRfbRoJYPWTHXgXLMA0GCSqGSIb3DQEBCwUAA4IBAQAd3cgFfrI/wjyKDx4SbQEuqMX1pCSoOwQnxvfuNq1PsDttJlNYrWkgzj27t9Sm4nqbAc5pqxRyx6/D0tFiJYs8QaBvIhSLKx9fhu3l7SHvqXPKjCCi+pBjLChu8fKH1G6dvl8YrjuTw+4G0nmzTKwBRf61loVc/zBz4f1+lxvkLYdQGUTYV7zyBNFqlt1SbW252kLFSGtTHoIp7x8eAmh6k1qoOWK4FSEmK1wzt+yNJlxg0n8s0wDcGwGcdVCV81YT5OEU4C34cPb9+DLW4nAH/c10bbTGyVqnl7CTV+6VVFDB46bJErBT4Z3VOp2zPI/5GTdl+eeb4hkIHI0ytxCg + MIIH/zCCBuegAwIBAgIQBcL35cC7wMJpntbZ9IogNDANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIgVExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjQwOTIzMDAwMDAwWhcNMjUxMDA5MjM1OTU5WjCBijELMAkGA1UEBhMCVVMxHTAbBgNVBAgTFERpc3RyaWN0IG9mIENvbHVtYmlhMRMwEQYDVQQHEwpXYXNoaW5ndG9uMSwwKgYDVQQKEyNVLlMuIERlcGFydG1lbnQgb2YgVmV0ZXJhbnMgQWZmYWlyczEZMBcGA1UEAxMQZGV2LmVhdXRoLnZhLmdvdjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2aLI8bOrETcYVXvez1TIgTSdGcqt6TfHH9LOp4I5QvUB+J093LOzO7pC2zNX/hffLTiA/FEBY6ZH9mQLupq9oMyCKRUJfs9YgoksMqpoAAG/k0Gptx+zFIruVqGUWDNVCJ2yf8qdP5i8lQy+t6f5ILoBlbupgvGoHppYrkSMJF4B4L5hBYWy/b4EloWWpTmCRK51DqkQZp95eeT8zvScEEhXsDXBXHUIoSHdkN+/nGSYUuF6JKKVvFI1WTWIT9N56xIjm209AMvsV5dn7VXHBlqR5UEW2tz0VQWBy4tB2/eUCWIJ3QADmT+XzJcDFk9ffGpdbSHECsV6mcq9DYZ9OcE9Y2YVSz5WCxuZy8nhnLfWicehz67lgY/bJlB0NxYPhjKif4Wh9b8T8B9fZ738xPcW9/5hk0DRU3u61BeMavt20EUOfRp8Oz5HvMCGkrTR7eI0gwblb74VgXzEhEY/6/tBBM4JVPVoPQ+qhLQqJ1yvayJesr0NO01knBO/bRQhXiNiMjeoublbHJCX1IMgpcFUWmJsBpzFw2O1sYo3qvJrSiTa/Bzdd8qh8aWKipMklY7RgC+N+X3c3PLV5pH2mOuy2iR7qBi45ww2SjBFPo+1iNGehTZx3fjmEHyA+kiTvkeOwPeX2HRVC22wOCWAKSkRso4V5AXJCfl2absLAFAgMBAAGjggOPMIIDizAfBgNVHSMEGDAWgBR0hYDAZsffN97PvSk3qgMdvu3NFzAdBgNVHQ4EFgQURgYkVZOloSagvssqZwolgE0zty4wGwYDVR0RBBQwEoIQZGV2LmVhdXRoLnZhLmdvdjA+BgNVHSAENzA1MDMGBmeBDAECAjApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjCBnwYDVR0fBIGXMIGUMEigRqBEhkJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHMlRMU1JTQVNIQTI1NjIwMjBDQTEtMS5jcmwwSKBGoESGQmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNybDCBhwYIKwYBBQUHAQEEezB5MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wUQYIKwYBBQUHMAKGRWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNydDAMBgNVHRMBAf8EAjAAMIIBgQYKKwYBBAHWeQIEAgSCAXEEggFtAWsAdwAS8U40vVNyTIQGGcOPP3oT+Oe1YoeInG0wBYTr5YYmOgAAAZIfsrgNAAAEAwBIMEYCIQCOtP/IYo8spdSjpTyoFknFBiJDBGWb5LgQkDWs/X+AEgIhAMAp/I9GYj1Go9nyeOM+UmXVI920iIL7i9ha0Rgr3nrIAHcAfVkeEuF4KnscYWd8Xv340IdcFKBOlZ65Ay/ZDowuebgAAAGSH7K3wQAABAMASDBGAiEA/hi0zVbIniP97LM+AK3WxbxXAbTiZrgV9GZvcRcMimECIQCwK2qSJtOyCkjD7j7mHeEyD82+JlbRGS5ex1QdW6o5MwB3AObSMWNAd4zBEEEG13G5zsHSQPaWhIb7uocyHf0eN45QAAABkh+yt9kAAAQDAEgwRgIhAMBO8WF+YiV1UqfWUYVMiOZdaDN9pGWMoEY8mxZKHm9VAiEAvMNmRSAbfctAUWb+iHwLPHeiFP8gplxoGyeWLukur/kwDQYJKoZIhvcNAQELBQADggEBAKRTS8KmQc/olPb1czBdqetfQW/c4B9hq6+Wu9HKHrq3Z7/ETarE5V6cY6WS+OYEpy2YVTRQsIp0x41RDGlaG91l6zYDQGSoiTe2iilsdNC8z1JzBMrMC/oMzYy5PTBYBxTtq5XbpagN5mhShPXPhQm45dh8u5LmRj4y3A7+NTEHhGFJJy0Pdm3EEN3A1kZY34pml3E7lIskulIF81IqFNnmPoPw6fuub3+cdmWKM9PgVkegF106DgJyUJ9oiYk5BJjKDLhHk1GEBz6A9+rctbFdGmKfYBGAPDBoCe3hAtv46WETTbBB72u7cNcLGhR3nNWPtGwRYAfvnuMtBc+sL5Q= - MIIH+jCCBuKgAwIBAgIQATN2LGZN6zApJ43rOeq+EjANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIgVExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjMwOTIwMDAwMDAwWhcNMjQxMDA5MjM1OTU5WjCBijELMAkGA1UEBhMCVVMxHTAbBgNVBAgTFERpc3RyaWN0IG9mIENvbHVtYmlhMRMwEQYDVQQHEwpXYXNoaW5ndG9uMSwwKgYDVQQKEyNVLlMuIERlcGFydG1lbnQgb2YgVmV0ZXJhbnMgQWZmYWlyczEZMBcGA1UEAxMQZGV2LmVhdXRoLnZhLmdvdjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2aLI8bOrETcYVXvez1TIgTSdGcqt6TfHH9LOp4I5QvUB+J093LOzO7pC2zNX/hffLTiA/FEBY6ZH9mQLupq9oMyCKRUJfs9YgoksMqpoAAG/k0Gptx+zFIruVqGUWDNVCJ2yf8qdP5i8lQy+t6f5ILoBlbupgvGoHppYrkSMJF4B4L5hBYWy/b4EloWWpTmCRK51DqkQZp95eeT8zvScEEhXsDXBXHUIoSHdkN+/nGSYUuF6JKKVvFI1WTWIT9N56xIjm209AMvsV5dn7VXHBlqR5UEW2tz0VQWBy4tB2/eUCWIJ3QADmT+XzJcDFk9ffGpdbSHECsV6mcq9DYZ9OcE9Y2YVSz5WCxuZy8nhnLfWicehz67lgY/bJlB0NxYPhjKif4Wh9b8T8B9fZ738xPcW9/5hk0DRU3u61BeMavt20EUOfRp8Oz5HvMCGkrTR7eI0gwblb74VgXzEhEY/6/tBBM4JVPVoPQ+qhLQqJ1yvayJesr0NO01knBO/bRQhXiNiMjeoublbHJCX1IMgpcFUWmJsBpzFw2O1sYo3qvJrSiTa/Bzdd8qh8aWKipMklY7RgC+N+X3c3PLV5pH2mOuy2iR7qBi45ww2SjBFPo+1iNGehTZx3fjmEHyA+kiTvkeOwPeX2HRVC22wOCWAKSkRso4V5AXJCfl2absLAFAgMBAAGjggOKMIIDhjAfBgNVHSMEGDAWgBR0hYDAZsffN97PvSk3qgMdvu3NFzAdBgNVHQ4EFgQURgYkVZOloSagvssqZwolgE0zty4wGwYDVR0RBBQwEoIQZGV2LmVhdXRoLnZhLmdvdjA+BgNVHSAENzA1MDMGBmeBDAECAjApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjCBnwYDVR0fBIGXMIGUMEigRqBEhkJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHMlRMU1JTQVNIQTI1NjIwMjBDQTEtMS5jcmwwSKBGoESGQmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNybDCBhwYIKwYBBQUHAQEEezB5MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wUQYIKwYBBQUHMAKGRWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNydDAMBgNVHRMBAf8EAjAAMIIBfAYKKwYBBAHWeQIEAgSCAWwEggFoAWYAdgB2/4g/Crb7lVHCYcz1h7o0tKTNuyncaEIKn+ZnTFo6dAAAAYq0W1BeAAAEAwBHMEUCICDzD04088p0Hi1vk8ffZPqqr89toO2MH7HsFzulEO5VAiEA0i1c5qycL1aRAVp8N9nbIzORORZghEnYYsRfmQWMn4sAdQBIsONr2qZHNA/lagL6nTDrHFIBy1bdLIHZu7+rOdiEcwAAAYq0W1AnAAAEAwBGMEQCIQCH+ftpruo2Ijj05VZIQu3V47LOeqP/SA8o0GeFQzjrLQIfJ00xVwQdbBkiWdSp7BT9yQ5T49js6xSiNscItF9+kQB1ANq2v2s/tbYin5vCu1xr6HCRcWy7UYSFNL2kPTBI1/urAAABirRbUBcAAAQDAEYwRAIgE/kR/q0hJj0EusxBvU3TfFDiT2BIsb6GKRcSK9fBuXICIGZVaGWjPaiZi5X08rWQ9B1w8+N5bRfbRoJYPWTHXgXLMA0GCSqGSIb3DQEBCwUAA4IBAQAd3cgFfrI/wjyKDx4SbQEuqMX1pCSoOwQnxvfuNq1PsDttJlNYrWkgzj27t9Sm4nqbAc5pqxRyx6/D0tFiJYs8QaBvIhSLKx9fhu3l7SHvqXPKjCCi+pBjLChu8fKH1G6dvl8YrjuTw+4G0nmzTKwBRf61loVc/zBz4f1+lxvkLYdQGUTYV7zyBNFqlt1SbW252kLFSGtTHoIp7x8eAmh6k1qoOWK4FSEmK1wzt+yNJlxg0n8s0wDcGwGcdVCV81YT5OEU4C34cPb9+DLW4nAH/c10bbTGyVqnl7CTV+6VVFDB46bJErBT4Z3VOp2zPI/5GTdl+eeb4hkIHI0ytxCg + MIIH/zCCBuegAwIBAgIQBcL35cC7wMJpntbZ9IogNDANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIgVExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjQwOTIzMDAwMDAwWhcNMjUxMDA5MjM1OTU5WjCBijELMAkGA1UEBhMCVVMxHTAbBgNVBAgTFERpc3RyaWN0IG9mIENvbHVtYmlhMRMwEQYDVQQHEwpXYXNoaW5ndG9uMSwwKgYDVQQKEyNVLlMuIERlcGFydG1lbnQgb2YgVmV0ZXJhbnMgQWZmYWlyczEZMBcGA1UEAxMQZGV2LmVhdXRoLnZhLmdvdjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2aLI8bOrETcYVXvez1TIgTSdGcqt6TfHH9LOp4I5QvUB+J093LOzO7pC2zNX/hffLTiA/FEBY6ZH9mQLupq9oMyCKRUJfs9YgoksMqpoAAG/k0Gptx+zFIruVqGUWDNVCJ2yf8qdP5i8lQy+t6f5ILoBlbupgvGoHppYrkSMJF4B4L5hBYWy/b4EloWWpTmCRK51DqkQZp95eeT8zvScEEhXsDXBXHUIoSHdkN+/nGSYUuF6JKKVvFI1WTWIT9N56xIjm209AMvsV5dn7VXHBlqR5UEW2tz0VQWBy4tB2/eUCWIJ3QADmT+XzJcDFk9ffGpdbSHECsV6mcq9DYZ9OcE9Y2YVSz5WCxuZy8nhnLfWicehz67lgY/bJlB0NxYPhjKif4Wh9b8T8B9fZ738xPcW9/5hk0DRU3u61BeMavt20EUOfRp8Oz5HvMCGkrTR7eI0gwblb74VgXzEhEY/6/tBBM4JVPVoPQ+qhLQqJ1yvayJesr0NO01knBO/bRQhXiNiMjeoublbHJCX1IMgpcFUWmJsBpzFw2O1sYo3qvJrSiTa/Bzdd8qh8aWKipMklY7RgC+N+X3c3PLV5pH2mOuy2iR7qBi45ww2SjBFPo+1iNGehTZx3fjmEHyA+kiTvkeOwPeX2HRVC22wOCWAKSkRso4V5AXJCfl2absLAFAgMBAAGjggOPMIIDizAfBgNVHSMEGDAWgBR0hYDAZsffN97PvSk3qgMdvu3NFzAdBgNVHQ4EFgQURgYkVZOloSagvssqZwolgE0zty4wGwYDVR0RBBQwEoIQZGV2LmVhdXRoLnZhLmdvdjA+BgNVHSAENzA1MDMGBmeBDAECAjApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjCBnwYDVR0fBIGXMIGUMEigRqBEhkJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHMlRMU1JTQVNIQTI1NjIwMjBDQTEtMS5jcmwwSKBGoESGQmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNybDCBhwYIKwYBBQUHAQEEezB5MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wUQYIKwYBBQUHMAKGRWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNydDAMBgNVHRMBAf8EAjAAMIIBgQYKKwYBBAHWeQIEAgSCAXEEggFtAWsAdwAS8U40vVNyTIQGGcOPP3oT+Oe1YoeInG0wBYTr5YYmOgAAAZIfsrgNAAAEAwBIMEYCIQCOtP/IYo8spdSjpTyoFknFBiJDBGWb5LgQkDWs/X+AEgIhAMAp/I9GYj1Go9nyeOM+UmXVI920iIL7i9ha0Rgr3nrIAHcAfVkeEuF4KnscYWd8Xv340IdcFKBOlZ65Ay/ZDowuebgAAAGSH7K3wQAABAMASDBGAiEA/hi0zVbIniP97LM+AK3WxbxXAbTiZrgV9GZvcRcMimECIQCwK2qSJtOyCkjD7j7mHeEyD82+JlbRGS5ex1QdW6o5MwB3AObSMWNAd4zBEEEG13G5zsHSQPaWhIb7uocyHf0eN45QAAABkh+yt9kAAAQDAEgwRgIhAMBO8WF+YiV1UqfWUYVMiOZdaDN9pGWMoEY8mxZKHm9VAiEAvMNmRSAbfctAUWb+iHwLPHeiFP8gplxoGyeWLukur/kwDQYJKoZIhvcNAQELBQADggEBAKRTS8KmQc/olPb1czBdqetfQW/c4B9hq6+Wu9HKHrq3Z7/ETarE5V6cY6WS+OYEpy2YVTRQsIp0x41RDGlaG91l6zYDQGSoiTe2iilsdNC8z1JzBMrMC/oMzYy5PTBYBxTtq5XbpagN5mhShPXPhQm45dh8u5LmRj4y3A7+NTEHhGFJJy0Pdm3EEN3A1kZY34pml3E7lIskulIF81IqFNnmPoPw6fuub3+cdmWKM9PgVkegF106DgJyUJ9oiYk5BJjKDLhHk1GEBz6A9+rctbFdGmKfYBGAPDBoCe3hAtv46WETTbBB72u7cNcLGhR3nNWPtGwRYAfvnuMtBc+sL5Q= + + urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified diff --git a/db/migrate/20241008231122_add_column_failure_notification_sent_at_to_appeal_submission_and_upload.rb b/db/migrate/20241008231122_add_column_failure_notification_sent_at_to_appeal_submission_and_upload.rb new file mode 100644 index 00000000000..dda914ce4ab --- /dev/null +++ b/db/migrate/20241008231122_add_column_failure_notification_sent_at_to_appeal_submission_and_upload.rb @@ -0,0 +1,9 @@ +class AddColumnFailureNotificationSentAtToAppealSubmissionAndUpload < ActiveRecord::Migration[7.1] + def change + # appeal_submissions + add_column :appeal_submissions, :failure_notification_sent_at, :datetime + + # appeal_submission_uploads + add_column :appeal_submission_uploads, :failure_notification_sent_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 12cb1e07990..bd125f59dd0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,8 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_10_07_180915) do + +ActiveRecord::Schema[7.1].define(version: 2024_10_10_144821) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gin" enable_extension "fuzzystrmatch" @@ -165,6 +166,7 @@ t.string "lighthouse_upload_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.datetime "failure_notification_sent_at" end create_table "appeal_submissions", force: :cascade do |t| @@ -177,6 +179,7 @@ t.text "upload_metadata_ciphertext" t.text "encrypted_kms_key" t.uuid "user_account_id" + t.datetime "failure_notification_sent_at" t.index ["user_account_id"], name: "index_appeal_submissions_on_user_account_id" end @@ -1306,6 +1309,22 @@ t.index ["user_account_id", "form_id"], name: "index_in_progress_reminders_sent_user_account_form_id", unique: true end + create_table "va_notify_notifications", force: :cascade do |t| + t.uuid "notification_id", null: false + t.text "reference" + t.text "to" + t.text "status" + t.datetime "completed_at" + t.datetime "sent_at" + t.text "notification_type" + t.text "status_reason" + t.text "provider" + t.text "source_location" + t.text "callback" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "vba_documents_monthly_stats", force: :cascade do |t| t.integer "month", null: false t.integer "year", null: false diff --git a/docs/setup/hybrid.md b/docs/setup/hybrid.md index 661c254b0c0..6e715c91c74 100644 --- a/docs/setup/hybrid.md +++ b/docs/setup/hybrid.md @@ -1,6 +1,6 @@ # Developer Setup -In hybrid mode, you will run vets-api natively, but run Postgres and Redis in Docker. By doing so you avoid any challenges of installing these two software packages and keeping them upgraded to the appropriate version. +In hybrid mode, you'll run vets-api natively, but run Postgres and Redis in Docker. By doing so, you avoid the challenges of installing these two software packages and having to keep them upgraded to the appropriate version. ## Base Setup @@ -28,13 +28,13 @@ redis: ## Running Deps 1. To start Postgres and Redis: run `docker-compose -f docker-compose-deps.yml up` in one terminal window. -2. In another terminal window, start `vets-api` as per the [native running instructions](running_natively.md). +2. In another terminal window, start `vets-api` as per the [native running instructions](running_natively.md). * Run `bin/setup` first to create the needed database tables. 3. Confirm the API is successfully running by seeing if you can visit [the local Flipper page.](http://localhost:3000/flipper/features) ### Mock ClamAV -If you wish to mock ClamAV, please set the clamav mock setting to true in settings.local.yml. This will mock the clamav response in the [virus_scan code](https://github.com/department-of-veterans-affairs/vets-api/blob/master/lib/common/virus_scan.rb#L14-L23). +If you wish to mock ClamAV, please set the clamav mock setting to true in settings.local.yml. This will mock the clamav response in the [virus_scan code](https://github.com/department-of-veterans-affairs/vets-api/blob/master/lib/common/virus_scan.rb#L14-L23). ``` clamav: diff --git a/lib/decision_review_v1/appeals/supplemental_claim_services.rb b/lib/decision_review_v1/appeals/supplemental_claim_services.rb index 6dba51c47d1..ed07637ba0a 100644 --- a/lib/decision_review_v1/appeals/supplemental_claim_services.rb +++ b/lib/decision_review_v1/appeals/supplemental_claim_services.rb @@ -60,7 +60,7 @@ def create_supplemental_claim(request_body:, user:) end ## - # Creates a new 4142(a) PDF, and sends to central mail + # Creates a new 4142(a) PDF, and sends to Lighthouse # # @param appeal_submission_id # @param rejiggered_payload @@ -249,24 +249,18 @@ def queue_form4142(appeal_submission_id:, rejiggered_payload:, submitted_appeal_ def submit_form4142(form_data:) processor = DecisionReviewV1::Processor::Form4142Processor.new(form_data:) + service = BenefitsIntake::Service.new + service.request_upload - if Flipper.enabled? :decision_review_sc_use_lighthouse_api_for_form4142 - service = BenefitsIntake::Service.new - service.request_upload - - payload = { - metadata: processor.request_body['metadata'], - document: processor.request_body['document'], - upload_url: service.location - } + payload = { + metadata: processor.request_body['metadata'], + document: processor.request_body['document'], + upload_url: service.location + } - response = service.perform_upload(**payload) + response = service.perform_upload(**payload) - [response, service.uuid] - else - response = CentralMail::Service.new.upload(processor.request_body) - [response, nil] - end + [response, service.uuid] end end # rubocop:enable Metrics/ModuleLength diff --git a/lib/disability_compensation/factories/api_provider_factory.rb b/lib/disability_compensation/factories/api_provider_factory.rb index 5a0e06f0f79..172da3c7515 100644 --- a/lib/disability_compensation/factories/api_provider_factory.rb +++ b/lib/disability_compensation/factories/api_provider_factory.rb @@ -56,7 +56,7 @@ class UndefinedFactoryTypeError < StandardError; end FEATURE_TOGGLE_BRD = 'disability_compensation_lighthouse_brd' FEATURE_TOGGLE_GENERATE_PDF = 'disability_compensation_lighthouse_generate_pdf' - FEATURE_TOGGLE_UPLOAD_SUPPLEMENTAL_DOCUMENT = 'disability_compensation_lighthouse_upload_supplemental_document' + FEATURE_TOGGLE_UPLOAD_BDD_INSTRUCTIONS = 'disability_compensation_upload_bdd_instructions_to_lighthouse' attr_reader :type diff --git a/lib/flipper/README.md b/lib/flipper/README.md new file mode 100644 index 00000000000..1fe4ebb70d5 --- /dev/null +++ b/lib/flipper/README.md @@ -0,0 +1,37 @@ +# Flipper + +## Description +Flipper is a gem used for managing unreleased features in vets-api by placing features behind "feature toggles" that can be enabled/disabled via the Flipper UI in each environment. + +[Flipper Documentation](https://www.flippercloud.io/docs/introduction) +[Flipper UI Documentation](https://www.flippercloud.io/docs/ui) + +## Developing with Flipper in Vets API +Please see the [Feature Toggles Guide](https://depo-platform-documentation.scrollhelp.site/developer-docs/feature-toggles-guide) in the Platform Docs for information on how we use Flipper in Vets API. + +## Local Development on Vets API Flipper Implementation + +By default, engineers will be authorized when developing locally. If you're a Platform Engineer working on the Flipper implementation, and need to mimic production authentication/authorization, read the following. + +### Requirements + +Add the following to your `settings.local.yml` +```yaml +flipper: + github_organization: department-of-veterans-affairs + github_team: + github_oauth_key: + github_oauth_secret: + github_api_key: +``` + +`github_team` - to give yourself access, provide the id of a team that you belong to (i.e. `backend-review-group`). You can retrieve the id via the github API: +``` +curl -H "Authorization: token " https://api.github.com/orgs/department-of-veterans-affairs/teams/backend-review-group +``` + +[Creating a Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) + +`github_oauth_key`/`github_oauth_secret` - These reference the Client ID and Client Secret for the associated Github OAuth App. There are separate apps for each app using github authentication (Flipper, Sidekiq, Coverband, etc) AND for each environment INCLUDING a Test App for use with localhost, `va.gov-flipper-oauth-local-test`. The credentials are stored in the parameter store under `/dsva-vagov/vets-api/local-dev/flipper/github-oauth-key` and `/github-oauth-secret`, respectively. + +`github_api_key` - This is the API key used across all OAuth apps. You can retrieve this from the Parameter store, located at `/dsva-vagov/vets-api/common/sidekiq/github-api-key` diff --git a/lib/flipper/action_patch.rb b/lib/flipper/action_patch.rb deleted file mode 100644 index 960c250aed9..00000000000 --- a/lib/flipper/action_patch.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module FlipperExtensions - module ActionPatch - def view(name) - # Use custom views if enabled in configuration. - path = custom_views_path.join("#{name}.erb") unless custom_views_path.nil? - - # Fall back to default views if custom views haven't been enabled - # or if the custom view cannot be found. - path = views_path.join("#{name}.erb") if path.nil? || !path.exist? - - raise "Template does not exist: #{path}" unless path.exist? - - # rubocop:disable Security/Eval - eval(Erubi::Engine.new(path.read, escape: true).src) - # rubocop:enable Security/Eval - end - - def custom_views_path - Flipper::UI.configuration.custom_views_path - end - - # This is where we store the feature descriptions. - # You can choose to store this where it makes sense for you. - def yaml_features - @yaml_features ||= FLIPPER_FEATURE_CONFIG['features'] - end - end -end diff --git a/lib/flipper/configuration_patch.rb b/lib/flipper/configuration_patch.rb deleted file mode 100644 index 5b521ef5c37..00000000000 --- a/lib/flipper/configuration_patch.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -module FlipperExtensions - module ConfigurationPatch - attr_accessor :custom_views_path - - def initialize - super - @custom_views_path = nil - end - end -end diff --git a/lib/flipper/admin_user_constraint.rb b/lib/flipper/route_authorization_constraint.rb similarity index 71% rename from lib/flipper/admin_user_constraint.rb rename to lib/flipper/route_authorization_constraint.rb index ed65f5cd0e0..47a13436c72 100644 --- a/lib/flipper/admin_user_constraint.rb +++ b/lib/flipper/route_authorization_constraint.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true module Flipper - class AdminUserConstraint + class RouteAuthorizationConstraint def self.matches?(request) # Confirm that requests to toggle (POST to /boolean) are authorized - url_pattern = %r{\A/flipper/features/[^/]+/boolean\z} + url_pattern = %r{\A/flipper/features/[^/]+/(boolean|actors|groups|percentage_of_actors|percentage_of_time)\z} if request.method == 'POST' && request.path.match?(url_pattern) return true if authorized?(request.session[:flipper_user]) @@ -21,8 +21,10 @@ def self.matches?(request) return true end - # allow GET requests (minus the callback, which needs to pass through to finish auth flow) - return true if (request.method == 'GET' && request.path.exclude?('/callback')) || Rails.env.development? + # allow GET requests (minus the oauth/callback requests, which need to pass through to finish oauth workflow) + return true if ( + request.method == 'GET' && request.path.exclude?('/callback') && request.params.exclude?('redirect') + ) || Settings.flipper.github_oauth_key.blank? authenticate(request) true @@ -35,7 +37,7 @@ def self.authenticate(request) end def self.authorized?(user) - return true if Rails.env.development? + return true if Settings.flipper.github_oauth_key.blank? org_name = Settings.flipper.github_organization team_id = Settings.flipper.github_team diff --git a/lib/flipper/ui/action_patch.rb b/lib/flipper/ui/action_patch.rb new file mode 100644 index 00000000000..306d6a4bbc7 --- /dev/null +++ b/lib/flipper/ui/action_patch.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Flipper + module UI + module ActionPatch + def view(name) + # Use custom views if enabled in configuration. + path = custom_views_path.join("#{name}.erb") unless custom_views_path.nil? + + # Fall back to default views if custom views haven't been enabled + # or if the custom view cannot be found. + path = views_path.join("#{name}.erb") if path.nil? || !path.exist? + + raise "Template does not exist: #{path}" unless path.exist? + + # rubocop:disable Security/Eval + eval(Erubi::Engine.new(path.read, escape: true).src) + # rubocop:enable Security/Eval + end + + def custom_views_path + Rails.root.join('lib', 'flipper', 'ui', 'views') + end + end + end +end diff --git a/lib/flipper/ui/views/layout.erb b/lib/flipper/ui/views/layout.erb new file mode 100644 index 00000000000..e657cf8620a --- /dev/null +++ b/lib/flipper/ui/views/layout.erb @@ -0,0 +1,95 @@ + + + + <%= @page_title ? "#{@page_title} // " : "" %>Flipper + + + + + + + + +
+
+ +
+
+ + + + + + + + + + + diff --git a/lib/flipper/views/feature.erb b/lib/flipper/views/feature.erb deleted file mode 100644 index e138d1be11a..00000000000 --- a/lib/flipper/views/feature.erb +++ /dev/null @@ -1,234 +0,0 @@ -
- <% if RequestStore.store[:flipper_user_email_for_log].blank? && !Rails.env.development? %> -

If you'd like to modify feature toggles, please sign in with GitHub.

-
method="post" class="usa-form"> - -
- <% elsif !RequestStore.store[:flipper_authorized] && !Rails.env.development? %> -

You are not authorized to perform any actions. Please see Platform Documentation for more information.

-
- -
- <% else %> - <% actor_type = FLIPPER_FEATURE_CONFIG['features'].dig(feature_name, 'actor_type')%> - <% actor_name = actor_type == FLIPPER_ACTOR_STRING ? 'FLIPPER_ID cookie' : 'Logged in Users' %> - <% actor_id_name = actor_type == FLIPPER_ACTOR_STRING ? 'ID from FLIPPER_ID cookie' : "email address associated with their login"%> - - <% if params.key?("error") %> -
- <%= params["error"] %> -
- <% end %> - -
-
-
-

- <%= @feature.key %> -

- -

- <%= yaml_features.dig(@feature.key,'description') %> -

- -
-

- <% if @feature.on? %> - This feature is enabled for everyone. - <% elsif @feature.off? %> - This feature is disabled. - <% else %> - This feature is enabled with certain conditions. - <% end %> -

- - <% if @feature.boolean_value %> -

Conditional toggles are currently disabled. If you want to conditionally enable this feature, you must first disable the feature for everyone.

- <% end %> - -
- <%== csrf_input_tag %> - <% if @feature.off? %> - - <% else %> - - <% end %> -
-
-
-
- -

- Conditional Toggles -

- -
-
-
-
-
disabled<% end %>> - <%== csrf_input_tag %> - - 0 %>value="<%= @feature.percentage_of_actors_value %>"<% end %>> - - -
-
-

- <% if @feature.percentage_of_actors_value > 0 && !@feature.boolean_value %> - This feature is enabled for <%= @feature.percentage_of_actors_value %>% of <%= actor_name %>. - <% else %> - This feature is not enabled by percentage of <%= actor_name %>. - <% end %> -

-
-
-
-
-
-
disabled<% end %>> - <%== csrf_input_tag %> - - 0 %>value="<%= @feature.percentage_of_time_value %>"<% end %>> - - -
-
-

- <% if @feature.percentage_of_time_value > 0 && !@feature.boolean_value %> - This feature is enabled <%= @feature.percentage_of_time_value %>% of the time for everyone. - <% else %> - This feature is not enabled by percentage of time. - <% end %> -

-
-
-
- -
-
-
-
- Percentage of <%= actor_name %> functions independently of percentage of time. If you enable 50% of <%= actor_name %> and 25% of time, then the feature will always be enabled for 50% of <%= actor_name %> and occasionally enabled 25% of the time for everyone. -
-
-
-
- -
-
-
- <% if @feature.boolean_value || Flipper.groups.empty? || @feature.disabled_groups.empty? %> -
Groups
- <% else %> -
- <%== csrf_input_tag %> - - - -
- <% end %> -

- <% if Flipper.groups.empty? %> - There are no groups available. Register groups in Flipper initializer. - <% elsif @feature.groups_value.empty? || @feature.boolean_value %> - This feature is not enabled by groups. - <% elsif @feature.disabled_groups.empty? %> - This feature is enabled for all available groups (listed below). - <% else %> - This feature is enabled for the following groups. - <% end %> -

- <% unless @feature.groups_value.empty? %> -
    - <% @feature.groups_value.each do |item| %> -
  • -
    -
    <%= item %>
    -
    -
    - <%== csrf_input_tag %> - - -
    -
    -
    -
  • - <% end %> -
- <% end %> -
-
-
-
-
-
disabled<% end %>> - <%== csrf_input_tag %> - - - -
-
- <% if @feature.actors_value.empty? %> -

- <%= "This feature is not enabled for specific users. To enable for a user, add the user's #{actor_id_name}."%> -

- <% else %> -

- This feature is enabled for the following <%= actor_name %>. -

-
    - <% @feature.actors_value.each do |item| %> -
  • -
    -
    <%= item %>
    -
    -
    - <%== csrf_input_tag %> - - -
    -
    -
    -
  • - <% end %> -
- <% end %> -
-
-
- -
- -
-
- <% end %> -
diff --git a/lib/flipper/views/features.erb b/lib/flipper/views/features.erb deleted file mode 100644 index b73abeaa527..00000000000 --- a/lib/flipper/views/features.erb +++ /dev/null @@ -1,71 +0,0 @@ -
-
- <% if RequestStore.store[:flipper_user_email_for_log].blank? && !Rails.env.development? %> -

If you'd like to modify feature toggles, please sign in with GitHub.

-
- -
- <% elsif !RequestStore.store[:flipper_authorized] && !Rails.env.development? %> -

You are not authorized to perform any actions. Please see Platform Documentation for more information.

-
- -
- <% end %> - - - - - - - - - - - - - <% @features.each do |feature| %> - - - - - - - <% end %> - -
Features
StatusFeatureDescriptionEnabled Gates
- <%= feature.state.capitalize %> - - <% if RequestStore.store[:flipper_authorized] || Rails.env.development? %> - "> - <%= feature.key %> - - <%else%> - <%= feature.key %> - <% end %> - - <%= yaml_features.dig(feature.key,'description') %> - - <%= feature.pretty_enabled_gate_names %> -
- <% if RequestStore.store[:flipper_authorized] %> -
- -
- <% end %> -
-
diff --git a/lib/flipper/views/layout.erb b/lib/flipper/views/layout.erb deleted file mode 100644 index 2cdfdc37d47..00000000000 --- a/lib/flipper/views/layout.erb +++ /dev/null @@ -1,63 +0,0 @@ - - - - <%= @page_title ? "#{@page_title} // " : "" %>Flipper - - - - - - - - - - - - - -
- <% unless Flipper::UI.configuration.banner_text.nil? %> -
-
- <%= Flipper::UI.configuration.banner_text %> -
-
- <% end %> - -
- -
- -
- <%== yield %> -
-
- - diff --git a/lib/mhv/account_creation/service.rb b/lib/mhv/account_creation/service.rb index 8290c174b16..7ed23fe0c57 100644 --- a/lib/mhv/account_creation/service.rb +++ b/lib/mhv/account_creation/service.rb @@ -16,7 +16,7 @@ def create_account(icn:, email:, tou_occurred_at:, break_cache: false) end rescue Common::Client::Errors::ParsingError, Common::Client::Errors::ClientError => e Rails.logger.error("#{config.logging_prefix} create_account #{e.class.name.demodulize.underscore}", - { error_message: e.message, body: e.body, icn: }) + { error_message: e.message, body: e.body, status: e.status, icn: }) raise end diff --git a/lib/sidekiq/form526_backup_submission_process/processor.rb b/lib/sidekiq/form526_backup_submission_process/processor.rb index f78aba2bfa0..64f737b9b03 100644 --- a/lib/sidekiq/form526_backup_submission_process/processor.rb +++ b/lib/sidekiq/form526_backup_submission_process/processor.rb @@ -69,8 +69,7 @@ class Processor def initialize(submission_id, docs = [], get_upload_location_on_instantiation: true, ignore_expiration: false) @submission_id = submission_id @submission = Form526Submission.find(submission_id) - @user_account = UserAccount.find_by(id: submission.user_uuid) || - Account.lookup_by_user_uuid(submission.user_uuid) + @user_account = submission_account(@submission) @docs = docs @docs_gathered = false @initial_upload_fetched = false @@ -84,6 +83,10 @@ def initialize(submission_id, docs = [], get_upload_location_on_instantiation: t determine_zip end + def submission_account(submission) + UserAccount.find_by(id: submission.user_account_id) || Account.lookup_by_user_uuid(submission.user_uuid) + end + def process! # Generates or makes calls to get, all PDFs, adds all to self.docs obj gather_docs! unless @docs_gathered diff --git a/lib/simple_forms_api/form_remediation/configuration/base.rb b/lib/simple_forms_api/form_remediation/configuration/base.rb index f1505918829..18a856a7957 100644 --- a/lib/simple_forms_api/form_remediation/configuration/base.rb +++ b/lib/simple_forms_api/form_remediation/configuration/base.rb @@ -10,7 +10,7 @@ def initialize @id_type = :benefits_intake_uuid # The field to query the FormSubmission by @include_manifest = true # Include a CSV file containing manifest data @include_metadata = false # Include a JSON file containing form submission metadata - @parent_dir = '/' # The base directory in the S3 bucket where the archive will be stored + @parent_dir = '' # The base directory in the S3 bucket where the archive will be stored @presign_s3_url = true # Once archived to S3, the service should generate & return a presigned_url end @@ -49,7 +49,7 @@ def attachment_type # hydrated and stored. This directory will automatically # be deleted once the archive process completes def temp_directory_path - @temp_directory_path ||= Rails.root.join("tmp/#{SecureRandom.hex}-archive/").to_s + Rails.root.join("tmp/#{SecureRandom.hex}-archive/").to_s end # Used in the SimpleFormsApi::FormRemediation::Uploader S3 uploader @@ -57,24 +57,14 @@ def s3_settings raise NotImplementedError, 'Class must implement s3_settings method' end - # The base S3 resource used for all S3 manipulations - def s3_resource - @s3_resource ||= uploader.new_s3_resource - end - - # The bucket where payloads will be uploaded on S3 - def target_bucket - @target_bucket ||= uploader.s3_bucket - end - # Utility method, override to add your own team's preferred logging approach def log_info(message, **details) - Rails.logger.info(message, details) + Rails.logger.info({ message: }.merge(details)) end # Utility method, override to add your own team's preferred logging approach def log_error(message, error, **details) - Rails.logger.error(message, details.merge(error: error.message, backtrace: error.backtrace.first(5))) + Rails.logger.error({ message:, error: error.message, backtrace: error.backtrace.first(5) }.merge(details)) end # Utility method, override to add your own team's preferred logging approach diff --git a/modules/burials/.adr-dir b/modules/burials/.adr-dir new file mode 100644 index 00000000000..469b5222fd3 --- /dev/null +++ b/modules/burials/.adr-dir @@ -0,0 +1 @@ +documentation/adr diff --git a/modules/burials/.gitignore b/modules/burials/.gitignore new file mode 100644 index 00000000000..9561900a83a --- /dev/null +++ b/modules/burials/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +.bundle +.envrc + +# Ignore all logfiles and tempfiles. +/log/* +!/log/.keep +/tmp/* +!/tmp/.keep + +# Ignore generated directories +/coverage +/reports + +# ignore yardoc generation +.yardoc/ diff --git a/modules/burials/.irbrc b/modules/burials/.irbrc new file mode 100644 index 00000000000..c8d7196216a --- /dev/null +++ b/modules/burials/.irbrc @@ -0,0 +1,5 @@ +# Disable autocomplete in deployed environments +# to help prevent running unintended commands +if ENV['RAILS_ENV'] == 'production' + IRB.conf[:USE_AUTOCOMPLETE] = false +end diff --git a/modules/burials/.rspec b/modules/burials/.rspec new file mode 100644 index 00000000000..683eea9e1a6 --- /dev/null +++ b/modules/burials/.rspec @@ -0,0 +1,7 @@ +--color +--require spec_helper +--format progress +<% if ENV['CI'] %> +--format RspecJunitFormatter +--out log/rspec.xml +<% end %> diff --git a/modules/burials/Gemfile b/modules/burials/Gemfile new file mode 100644 index 00000000000..a2af83a5bbd --- /dev/null +++ b/modules/burials/Gemfile @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +# Declare your gem's dependencies in simple_forms_api.gemspec. +# Bundler will treat runtime dependencies like base dependencies, and +# development dependencies will be added by default to the :development group. +gemspec + +# Declare any dependencies that are still in development here instead of in +# your gemspec. These might include edge Rails or gems from your path or +# Git. Remember to move these dependencies to your gemspec before releasing +# your gem to rubygems.org. + +# To use a debugger +# gem 'byebug', group: [:development, :test] diff --git a/modules/burials/README.md b/modules/burials/README.md new file mode 100644 index 00000000000..00eaf5a6af5 --- /dev/null +++ b/modules/burials/README.md @@ -0,0 +1,5 @@ +# Burials + +Pension & Burial Program (PBP) + +Engineering related documentation can be found under [/documentation/](./documentation/) diff --git a/modules/burials/Rakefile b/modules/burials/Rakefile new file mode 100644 index 00000000000..0433dd142ed --- /dev/null +++ b/modules/burials/Rakefile @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +begin + require 'bundler/setup' +rescue LoadError + puts 'You must `gem install bundler` and `bundle install` to run rake tasks' +end + +require 'bundler/gem_tasks' + +unless Rails.env.production? + require 'rspec/core/rake_task' + task(spec: :environment).clear + RSpec::Core::RakeTask.new(:spec) do |t| + t.pattern = Dir.glob(['spec/**/*_spec.rb']) + t.verbose = false + end +end diff --git a/modules/burials/app/controllers/burials/v0/.gitkeep b/modules/burials/app/controllers/burials/v0/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/modules/burials/app/models/burials/.gitkeep b/modules/burials/app/models/burials/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/modules/burials/app/sidekiq/burials/.gitkeep b/modules/burials/app/sidekiq/burials/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/modules/burials/app/swagger/swagger/requests/.gitkeep b/modules/burials/app/swagger/swagger/requests/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/modules/burials/bin/rails b/modules/burials/bin/rails new file mode 100755 index 00000000000..8f9430795e2 --- /dev/null +++ b/modules/burials/bin/rails @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# This command will automatically be run when you run "rails" with Rails gems +# installed from the root of your application. + +ENGINE_ROOT = File.expand_path('..', __dir__) +ENGINE_PATH = File.expand_path('../lib/burials/engine', __dir__) +APP_PATH = File.expand_path('../test/dummy/config/application', __dir__) + +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) + +require 'rails/all' +require 'rails/engine/commands' diff --git a/modules/burials/burials.gemspec b/modules/burials/burials.gemspec new file mode 100644 index 00000000000..2ac4d9202ef --- /dev/null +++ b/modules/burials/burials.gemspec @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +$LOAD_PATH.push File.expand_path('lib', __dir__) + +require 'burials/version' + +# Describe your gem and declare its dependencies: +Gem::Specification.new do |spec| + spec.name = 'burials' + spec.version = Burials::VERSION + spec.authors = ['Benefits Burials'] + spec.email = [''] + spec.homepage = 'https://api.va.gov' + spec.summary = 'An api.va.gov module' + spec.description = 'This module was auto-generated please update this description' + spec.license = 'CC0-1.0' + + spec.files = Dir['{app,config,db,lib}/**/*', 'Rakefile', 'README.md'] +end diff --git a/modules/burials/config/routes.rb b/modules/burials/config/routes.rb new file mode 100644 index 00000000000..39d2a9c9d21 --- /dev/null +++ b/modules/burials/config/routes.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +Burials::Engine.routes.draw do + namespace :v0, defaults: { format: :json } do + resources :claims, only: %i[create show] + end +end diff --git a/modules/burials/documentation/adr/0001-record-architecture-decisions.md b/modules/burials/documentation/adr/0001-record-architecture-decisions.md new file mode 100644 index 00000000000..907b08bf929 --- /dev/null +++ b/modules/burials/documentation/adr/0001-record-architecture-decisions.md @@ -0,0 +1,41 @@ +# 1. Record architecture decisions + +Date: 2024-06-14 + +## Status + +Accepted + +## Context + +We need to record the architectural decisions made on this project. + +## Decision Documentation + +We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions). + +### Using adr-tools + +This repository makes use of [adr-tools](https://github.com/npryce/adr-tools/tree/master) to record architectural decisions as part of the code base. + +There are two uses for this, recording a new decision and superseding an existing decision. + +#### Recording a new decision + +To create a new decision use the adr new command: + +```bash + adr new +``` + +#### Superseding an existing decision + +To overwrite an existing decision you can add the -s flag followed by which is getting overwritten. In this example we are overwriting decision 9 with an updated decision: + +```bash +adr new -s 9 +``` + +## Consequences + +See Michael Nygard's article, linked above. For a lightweight ADR toolset, see Nat Pryce's [adr-tools](https://github.com/npryce/adr-tools). diff --git a/modules/burials/documentation/adr/0002-use-modules-folder-for-burials-code.md b/modules/burials/documentation/adr/0002-use-modules-folder-for-burials-code.md new file mode 100644 index 00000000000..fb8329b1291 --- /dev/null +++ b/modules/burials/documentation/adr/0002-use-modules-folder-for-burials-code.md @@ -0,0 +1,22 @@ +# 2. Move burials application to modules folder + +Date: 2024-10-10 + +## Status + +Accepted + +## Context + +The vets-api is a large monorepo with many overlapping forms. The tangle of code between applications has made it difficult for teams to iterate without impacting others. + +## Decision + +In an effort to isolate code, the PBP team has decided to take advantage of [Ruby on Rails Engines](https://guides.rubyonrails.org/engines.html) to create a separate application for the 21P-530EZ form (burials). Engines can be isolated from their host applications which will allow for us to: + +- Isolate the code pertinent to Burials +- Work toward running a CI/CD that can be applied only to Burial code + +## Consequences + +The result of this change will allow for the PBP team to more quickly iterate and innovate on future changes. There is a risk that isolating burial code will result in a lot of duplication of code. The longer term goal would be to move common benefits logic into a module of its own as is being done for burial code. diff --git a/modules/burials/documentation/readme.md b/modules/burials/documentation/readme.md new file mode 100644 index 00000000000..2affdf75810 --- /dev/null +++ b/modules/burials/documentation/readme.md @@ -0,0 +1,58 @@ +# Burials Documentation + +Pension & Burial Program (PBP) + +## ADR + +The PBP team uses [ADR Tools](https://github.com/npryce/adr-tools/tree/master) to document important engineering related decisions for the vets-api repo. The goal is to capture the technical decisions our group makes so that anyone new to our team or following behind will be able to understand the reasons for the decisions. + +Additional architectural decisions made by other teams can be found here: +https://github.com/department-of-veterans-affairs/va.gov-team-sensitive/tree/master/teams/benefits/architectural-decision-records + +| Decision | +| ----------------------------------------------------------------------------------------------------------- | +| [Use ADR to document important engineering decisions](./adr/0001-record-architecture-decisions.md) | +| [Move the burials specific code to the modules folder](./adr/0002-use-modules-folder-for-burials-code.md) | +| | + +## Folder structure + +For more information on the Ruby on Rails directory structure, please refer to https://github.com/jwipeout/rails-directory-structure-guide + +The current folder structure generally follows the default directory structure that **Ruby on Rails** comes with. + +##### App Folder + +- At a high level, within the app folder, there are [controllers](https://guides.rubyonrails.org/action_controller_overview.html) and [models](https://guides.rubyonrails.org/active_record_basics.html). Ruby on Rails uses a MVC (model, view, controller) architecture pattern. There is little historical context or documentation on the choice of V0 or V1 for the controllers. +- There are also a [sidekiq](https://github.com/sidekiq/sidekiq) and [swagger](https://swagger.io/) folders. + +##### DB Folder + +- The db folder contains the schema and migrations used for the application. + +##### Lib Folder + +- The lib folder is intended for common code or code that can be reused by other teams. It is also where the code for interfacing with external APIs lives. + +##### Config Folder + +- The config folder is where most of the configuration files for the main rails app, plugins, etc. are housed + +##### Spec Folder + +- Contains the tests for vets-api + +## Team + +| Name | Email Address | +| ------------ | ------------------------- | +| Matt Knight | matt.knight@coforma.io | +| Wayne Weibel | wayne.weibel@adhocteam.us | +| Tai Wilkin | tai.wilkin@coforma.io | +| Todd Rizzolo | todd.rizzolo@adhocteam.us | +| Daniel Lim | daniel.lim@adhocteam.us | +| Bryan Alexander | bryan.alexander@adhocteam.us | + +## Troubleshooting + +## diff --git a/modules/burials/lib/burials.rb b/modules/burials/lib/burials.rb new file mode 100644 index 00000000000..6be4909b114 --- /dev/null +++ b/modules/burials/lib/burials.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'burials/engine' + +## +# Burial 21P-530EZ Module +# +module Burials + # API Version 0 + module V0 + end + + # ZeroSilentFailures + # @see lib/zero_silent_failures + module ZeroSilentFailures + end +end diff --git a/modules/burials/lib/burials/engine.rb b/modules/burials/lib/burials/engine.rb new file mode 100644 index 00000000000..65ca73b39ff --- /dev/null +++ b/modules/burials/lib/burials/engine.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Burials + # @see https://api.rubyonrails.org/classes/Rails/Engine.html + class Engine < ::Rails::Engine + isolate_namespace Burials + config.generators.api_only = true + + initializer 'burials.factories', after: 'factory_bot.set_factory_paths' do + FactoryBot.definition_file_paths << File.expand_path('../../spec/factories', __dir__) if defined?(FactoryBot) + end + + initializer 'burials.zero_silent_failures' do |app| + app.config.to_prepare do + require_all "#{__dir__}/../zero_silent_failures" + end + end + + # TODO: move PDFFill library to this module + # initializer 'burials.register_form' do |app| + # app.config.to_prepare do + # require 'pdf_fill/filler' + # require_relative '../pdf_fill/va21p530v2' + + # # Register our Burial Pdf Fill form + # ::PdfFill::Filler.register_form(Burials::PdfFill::Va21p530v2::FORM_ID, Burials::PdfFill::Va21p530v2) + # end + # end + end +end diff --git a/modules/burials/lib/burials/version.rb b/modules/burials/lib/burials/version.rb new file mode 100644 index 00000000000..9da0a5a9a12 --- /dev/null +++ b/modules/burials/lib/burials/version.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Burials + ## + # The module path + # + MODULE_PATH = 'modules/burials' + + ## + # The module version + # + VERSION = '0.1.0' +end diff --git a/modules/burials/lib/zero_silent_failures/manual_remediation.rb b/modules/burials/lib/zero_silent_failures/manual_remediation.rb new file mode 100644 index 00000000000..48bd352248f --- /dev/null +++ b/modules/burials/lib/zero_silent_failures/manual_remediation.rb @@ -0,0 +1,142 @@ +# frozen_string_literal: true + +require 'common/file_helpers' +require 'pdf_utilities/datestamp_pdf' + +module Burials + module ZeroSilentFailures + class ManualRemediation + def package_claim(saved_claim_id) + @claim = SavedClaim::Burial.find(saved_claim_id) + + generate_metadata + + generate_form_pdf + + generate_attachment_pdfs + + zipfile = zip_files(files) + Rails.logger.info("Packaged #{claim.form_id} #{claim.id} - #{zipfile}") + + if Settings.vsp_environment == 'production' + link = aws_upload_zipfile(zipfile) + Rails.logger.info("Download #{link}") + Common::FileHelpers.delete_file_if_exists(zipfile) + end + end + + private + + attr_reader :claim + + def files + @files ||= [] + end + + def generate_metadata + form = claim.parsed_form + address = form['claimantAddress'] || form['veteranAddress'] + + lighthouse_benefit_intake_submission = FormSubmission.where(saved_claim_id: claim.id).order(id: :asc).last + + metadata = { + claimId: claim.id, + docType: claim.form_id, + formStartDate: claim.form_start_date, + claimSubmissionDate: claim.created_at, + claimConfirmation: claim.guid, + veteranFirstName: form['veteranFullName']['first'], + veteranLastName: form['veteranFullName']['last'], + fileNumber: form['vaFileNumber'] || form['veteranSocialSecurityNumber'], + zipCode: address['postalCode'], + businessLine: claim.business_line, + lighthouseBenefitIntakeSubmissionUUID: lighthouse_benefit_intake_submission&.benefits_intake_uuid, + lighthouseBenefitIntakeSubmissionDate: lighthouse_benefit_intake_submission&.created_at + } + + metafile = Common::FileHelpers.generate_random_file(metadata.to_json) + files << { name: "#{claim.form_id}_#{claim.id}-metadata.json", path: metafile } + end + + def generate_form_pdf + filepath = claim.to_pdf + Rails.logger.info "Stamping #{claim.form_id} #{claim.id} - #{filepath}" + stamped = stamp_pdf(filepath, claim.created_at) + if ['21P-530V2'].include?(claim.form_id) + stamped = stamped_pdf_with_form(claim.form_id, stamped, + claim.created_at) + end + files << { name: File.basename(filepath), path: stamped } + end + + def generate_attachment_pdfs + claim.persistent_attachments.each do |pa| + filename = "#{claim.form_id}_#{claim.id}-attachment_#{pa.id}.pdf" + filepath = pa.to_pdf + Rails.logger.info "Stamping #{claim.form_id} #{claim.id} Attachment #{pa.id} - #{filepath}" + stamped = stamp_pdf(filepath, claim.created_at) + if ['21P-530V2'].include?(claim.form_id) + stamped = stamped_pdf_with_form(claim.form_id, stamped, + claim.created_at) + end + files << { name: filename, path: stamped } + end + end + + def stamp_pdf(pdf_path, timestamp = nil) + begin + datestamp = PDFUtilities::DatestampPdf.new(pdf_path).run(text: 'VA.GOV', x: 5, y: 5, timestamp:) + watermark = PDFUtilities::DatestampPdf.new(datestamp).run( + text: 'FDC Reviewed - VA.gov Submission', + x: 400, + y: 770, + text_only: true, + timestamp: + ) + rescue + Rails.logger.error "Error stamping pdf: #{pdf_path}" + end + + watermark || pdf_path + end + + def stamped_pdf_with_form(form_id, path, timestamp) + PDFUtilities::DatestampPdf.new(path).run( + text: 'Application Submitted on va.gov', + x: 425, + y: 675, + text_only: true, # passing as text only because we override how the date is stamped in this instance + timestamp:, + page_number: 5, + size: 9, + template: "lib/pdf_fill/forms/pdfs/#{form_id}.pdf", + multistamp: true + ) + end + + def zip_files(files) + zip_file_path = "#{Common::FileHelpers.random_file_path}.zip" + Zip::File.open(zip_file_path, Zip::File::CREATE) do |zipfile| + files.each do |file| + Rails.logger.info(file) + begin + zipfile.add(file[:name], file[:path]) + rescue + Rails.logger.error "Error adding to zip: #{file}" + end + end + end + zip_file_path + end + + def aws_upload_zipfile(zipfile) + s3_resource = Aws::S3::Resource.new(region: Settings.vba_documents.s3.region, + access_key_id: Settings.vba_documents.s3.aws_access_key_id, + secret_access_key: Settings.vba_documents.s3.aws_secret_access_key) + obj = s3_resource.bucket(Settings.vba_documents.s3.bucket).object(File.basename(zipfile)) + obj.upload_file(zipfile, content_type: Mime[:zip].to_s) + obj.presigned_url(:get, expires_in: 1.day.to_i) + end + end + end +end diff --git a/modules/burials/spec/spec_helper.rb b/modules/burials/spec/spec_helper.rb new file mode 100644 index 00000000000..61f0ddb7886 --- /dev/null +++ b/modules/burials/spec/spec_helper.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'rspec/rails' + +RSpec.configure { |config| config.use_transactional_fixtures = true } + +# By default run SimpleCov, but allow an environment variable to disable. +unless ENV['NOCOVERAGE'] + require 'simplecov' + + SimpleCov.start 'rails' do + track_files '**/{app,lib}/**/*.rb' + + add_filter 'app/swagger' + + if ENV['CI'] + SimpleCov.minimum_coverage 90 + SimpleCov.refuse_coverage_drop + end + end +end diff --git a/modules/check_in/app/services/travel_claim/service.rb b/modules/check_in/app/services/travel_claim/service.rb index e9b5d49f03d..7fa01e25333 100644 --- a/modules/check_in/app/services/travel_claim/service.rb +++ b/modules/check_in/app/services/travel_claim/service.rb @@ -12,7 +12,7 @@ module TravelClaim # @!attribute [r] redis_client # @return [RedisClient] class Service - attr_reader :check_in, :appointment_date, :client, :redis_client, :response + attr_reader :check_in, :appointment_date, :redis_client, :response, :facility_type, :settings ## # Builds a Service instance @@ -27,9 +27,10 @@ def self.build(opts = {}) end def initialize(opts = {}) + @settings = Settings.check_in.travel_reimbursement_api_v2 @check_in = opts[:check_in] @appointment_date = opts.dig(:params, :appointment_date) - @client = Client.build(check_in:) + @facility_type = opts.dig(:params, :facility_type) || '' @redis_client = RedisClient.build @response = Response end @@ -86,6 +87,11 @@ def claim_status private + def client + client_number = facility_type.downcase == 'oh' ? settings.client_number_oh : settings.client_number + @client ||= Client.build(check_in:, client_number:) + end + def patient_icn redis_client.icn(uuid: check_in.uuid) end diff --git a/modules/claims_api/app/controllers/claims_api/v2/veterans/power_of_attorney/request_controller.rb b/modules/claims_api/app/controllers/claims_api/v2/veterans/power_of_attorney/request_controller.rb index 1bed3c12d0f..b3bd11b09e0 100644 --- a/modules/claims_api/app/controllers/claims_api/v2/veterans/power_of_attorney/request_controller.rb +++ b/modules/claims_api/app/controllers/claims_api/v2/veterans/power_of_attorney/request_controller.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require 'bgs_service/manage_representative_service' require 'claims_api/v2/error/lighthouse_error_handler' require 'claims_api/v2/json_format_validation' @@ -9,6 +10,26 @@ module Veterans class PowerOfAttorney::RequestController < ClaimsApi::V2::Veterans::PowerOfAttorney::BaseController FORM_NUMBER = 'POA_REQUEST' + def index + poa_codes = form_attributes['poaCodes'] + + unless poa_codes.is_a?(Array) && poa_codes.size.positive? + raise ::Common::Exceptions::ParameterMissing.new('poaCodes', + detail: 'poaCodes is required and cannot be empty') + end + + service = ManageRepresentativeService.new(external_uid: 'power_of_attorney_request_uid', + external_key: 'power_of_attorney_request_key') + + res = service.read_poa_request(poa_codes:) + + poa_list = res[:poa_request_respond_return_vo_list] + + raise ::Common::Exceptions::Lighthouse::BadGateway unless poa_list + + render json: poa_list, status: :ok + end + def request_representative # validate target veteran exists target_veteran diff --git a/modules/claims_api/app/models/claims_api/auto_established_claim.rb b/modules/claims_api/app/models/claims_api/auto_established_claim.rb index 4487220c98d..da0eea02c3d 100644 --- a/modules/claims_api/app/models/claims_api/auto_established_claim.rb +++ b/modules/claims_api/app/models/claims_api/auto_established_claim.rb @@ -430,13 +430,17 @@ def transform_service_branch end form_data['serviceInformation']['servicePeriods'] = transformed_service_periods - transformed_reserves_national_guard_service + + unit_phone = form_data&.dig('serviceInformation', 'reservesNationalGuardService', 'unitPhone') + transformed_reserves_national_guard_service(unit_phone) if unit_phone.present? + form_data['serviceInformation'] end - def transformed_reserves_national_guard_service - unit_phone = form_data&.dig('serviceInformation', 'reservesNationalGuardService', 'unitPhone') - unit_phone['phoneNumber'].delete!('-') if unit_phone.present? && unit_phone['phoneNumber'].include?('-') + def transformed_reserves_national_guard_service(unit_phone) + # both of the below are required in the schema for unitPhone + unit_phone['phoneNumber'].gsub!(/[-\s]/, '') + unit_phone['areaCode'].gsub!(/\s/, '') end # Legacy claimsApi code previously allowed servicePay-related service branch diff --git a/modules/claims_api/app/services/claims_api/disability_compensation/disability_document_service.rb b/modules/claims_api/app/services/claims_api/disability_compensation/disability_document_service.rb new file mode 100644 index 00000000000..68310912032 --- /dev/null +++ b/modules/claims_api/app/services/claims_api/disability_compensation/disability_document_service.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module ClaimsApi + module DisabilityCompensation + class DisabilityDocumentService < DocumentServiceBase + LOG_TAG = '526_v2_Disability_Document_service' + + def create_upload(claim:, pdf_path:, doc_type: 'L122', original_filename: nil) + unless File.exist? pdf_path + ClaimsApi::Logger.log('benefits_documents', detail: "Error creating upload doc: #{file_path} doesn't exist, + claim_id: #{claim.id}") + raise Errno::ENOENT, pdf_path + end + + body = generate_body(claim:, doc_type:, pdf_path:, original_filename:) + doc_type_name = doc_type == 'L122' ? 'claim' : 'supporting' + ClaimsApi::BD.new.upload_document(claim_id: claim.id, doc_type_name:, body:) + end + + private + + ## + # Generate form body to upload a document + # + # @return {parameters, file} + def generate_body(claim:, doc_type:, pdf_path:, original_filename: nil) + auth_headers = claim.auth_headers + veteran_name = compact_veteran_name(auth_headers['va_eauth_firstName'], + auth_headers['va_eauth_lastName']) + birls_file_number = auth_headers['va_eauth_birlsfilenumber'] + claim_id = claim.evss_id + form_name = doc_type == 'L122' ? '526EZ' : 'supporting' + file_name = generate_file_name(veteran_name:, claim_id:, form_name:, original_filename:) + system_name = 'VA.gov' + tracked_item_ids = claim.tracked_items&.map(&:to_i) if claim&.has_attribute?(:tracked_items) + + generate_upload_body(claim_id:, system_name:, doc_type:, pdf_path:, file_name:, birls_file_number:, + participant_id: nil, tracked_item_ids:) + end + + def generate_file_name(veteran_name:, claim_id:, form_name:, original_filename:) + if form_name == '526EZ' + build_file_name(veteran_name:, identifier: claim_id, suffix: form_name) + elsif form_name == 'supporting' + file_name = get_original_supporting_doc_file_name(original_filename) + build_file_name(veteran_name:, identifier: claim_id, suffix: file_name) + end + end + + ## + # DisabilityCompensationDocuments method create_unique_filename adds a random 11 digit + # hex string to the original filename, so we remove that to yield the user-submitted + # filename to use as part of the filename uploaded to the BD service. + def get_original_supporting_doc_file_name(original_filename) + file_extension = File.extname(original_filename) + base_filename = File.basename(original_filename, file_extension) + base_filename[0...-12] + end + end + end +end diff --git a/modules/claims_api/app/services/claims_api/document_service_base.rb b/modules/claims_api/app/services/claims_api/document_service_base.rb new file mode 100644 index 00000000000..938e1fc5789 --- /dev/null +++ b/modules/claims_api/app/services/claims_api/document_service_base.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module ClaimsApi + class DocumentServiceBase < ServiceBase + ## + # Generate form body to upload a document + # + # @return {parameters, file} + # rubocop:disable Metrics/ParameterLists + def generate_upload_body(claim_id:, system_name:, doc_type:, pdf_path:, file_name:, birls_file_number:, + participant_id:, tracked_item_ids:) + + payload = {} + + data = build_body(claim_id:, system_name:, doc_type:, file_name:, participant_id:, + file_number: birls_file_number, tracked_item_ids:) + + fn = Tempfile.new('params') + File.write(fn, data.to_json) + payload[:parameters] = Faraday::UploadIO.new(fn, 'application/json') + payload[:file] = Faraday::UploadIO.new(pdf_path.to_s, 'application/pdf') + payload + end + # rubocop:enable Metrics/ParameterLists + + def compact_veteran_name(first_name, last_name) + [first_name, last_name].compact_blank.join('_') + end + + def build_file_name(veteran_name:, identifier:, suffix:) + "#{[veteran_name, identifier, suffix].compact_blank.join('_')}.pdf" + end + + private + + def build_body(options = {}) + data = { + systemName: options[:system_name], + docType: options[:doc_type], + fileName: options[:file_name], + trackedItemIds: options[:tracked_item_ids].presence || [] + } + data[:claimId] = options[:claim_id] unless options[:claim_id].nil? + data[:participantId] = options[:participant_id] unless options[:participant_id].nil? + data[:fileNumber] = options[:file_number] unless options[:file_number].nil? + { data: } + end + end +end diff --git a/modules/claims_api/app/services/claims_api/slack/failed_submissions_messenger.rb b/modules/claims_api/app/services/claims_api/slack/failed_submissions_messenger.rb index 949c9894718..4b9c182930d 100644 --- a/modules/claims_api/app/services/claims_api/slack/failed_submissions_messenger.rb +++ b/modules/claims_api/app/services/claims_api/slack/failed_submissions_messenger.rb @@ -60,6 +60,12 @@ def build_submission_information(errored_submissions, submission_type) errored_submission_message = ''.dup if submission_type == 'Intent to File' errored_submission_message << "*#{submission_type} Errors* \nTotal: #{errored_submissions.count} \n\n" + elsif submission_type == 'Va Gov Disability Compensation' + errored_submission_message << "*#{submission_type} Errors* \nTotal: #{errored_submissions.count} \n\n```" + errored_submissions.each do |submission_id| + errored_submission_message << "#{link_value(submission_id)}#{submission_id}> \n" + end + errored_submission_message << "``` \n\n" else errored_submission_message << "*#{submission_type} Errors* \nTotal: #{errored_submissions.count} \n\n```" errored_submissions.each do |submission_id| @@ -69,6 +75,23 @@ def build_submission_information(errored_submissions, submission_type) end errored_submission_message end + + def link_value(id) + time_stamps = datadog_timestamps + + " e message = get_error_message(e) diff --git a/modules/claims_api/app/sidekiq/claims_api/report_unsuccessful_submissions.rb b/modules/claims_api/app/sidekiq/claims_api/report_unsuccessful_submissions.rb index 7ae0321dd38..7397fcb6688 100644 --- a/modules/claims_api/app/sidekiq/claims_api/report_unsuccessful_submissions.rb +++ b/modules/claims_api/app/sidekiq/claims_api/report_unsuccessful_submissions.rb @@ -6,10 +6,6 @@ def perform if Settings.claims_api.report_enabled @to = Time.zone.now @from = 1.day.ago - @claims_consumers = ClaimsApi::AutoEstablishedClaim.where(created_at: @from..@to).pluck(:cid).uniq - @poa_consumers = ClaimsApi::PowerOfAttorney.where(created_at: @from..@to).pluck(:cid).uniq - @itf_consumers = ClaimsApi::IntentToFile.where(created_at: @from..@to).pluck(:cid).uniq - @ews_consumers = ClaimsApi::EvidenceWaiverSubmission.where(created_at: @from..@to).pluck(:cid).uniq ClaimsApi::UnsuccessfulReportMailer.build( @from, diff --git a/modules/claims_api/app/sidekiq/claims_api/reporting_base.rb b/modules/claims_api/app/sidekiq/claims_api/reporting_base.rb index eb232133ebf..3e94476d554 100644 --- a/modules/claims_api/app/sidekiq/claims_api/reporting_base.rb +++ b/modules/claims_api/app/sidekiq/claims_api/reporting_base.rb @@ -11,10 +11,11 @@ def unsuccessful_claims_submissions end def errored_claims - ClaimsApi::AutoEstablishedClaim.where( - 'status = ? AND created_at BETWEEN ? AND ? AND cid <> ?', - 'errored', @from, @to, '0oagdm49ygCSJTp8X297' - ).order(:cid, :status) + ClaimsApi::AutoEstablishedClaim.where(created_at: @from..@to, status: 'errored').where( + "cid <> '0oagdm49ygCSJTp8X297'" + ).order( + :cid, :status + ) end def unsuccessful_va_gov_claims_submissions @@ -46,7 +47,8 @@ def with_flashes(cid: nil) end def claims_totals - @claims_consumers.map do |cid| + @claims_consumers = ClaimsApi::AutoEstablishedClaim.where(created_at: @from..@to).pluck(:cid).uniq + @claims_consumers&.map do |cid| counts = ClaimsApi::AutoEstablishedClaim.where(created_at: @from..@to, cid:).group(:status).count totals = counts.sum { |_k, v| v }.to_f @@ -66,7 +68,8 @@ def claims_totals end def poa_totals - @poa_consumers.map do |cid| + @poa_consumers = ClaimsApi::PowerOfAttorney.where(created_at: @from..@to).pluck(:cid).uniq + @poa_consumers&.map do |cid| counts = ClaimsApi::PowerOfAttorney.where(created_at: @from..@to, cid:).group(:status).count totals = counts.sum { |_k, v| v } @@ -94,7 +97,8 @@ def errored_poas end def itf_totals - @itf_consumers.map do |cid| + @itf_consumers = ClaimsApi::IntentToFile.where(created_at: @from..@to).pluck(:cid).uniq + @itf_consumers&.map do |cid| counts = ClaimsApi::IntentToFile.where(created_at: @from..@to, cid:).group(:status).count totals = counts.sum { |_k, v| v } @@ -109,7 +113,8 @@ def itf_totals end def ews_totals - @ews_consumers.map do |cid| + @ews_consumers = ClaimsApi::EvidenceWaiverSubmission.where(created_at: @from..@to).pluck(:cid).uniq + @ews_consumers&.map do |cid| counts = ClaimsApi::EvidenceWaiverSubmission.where(created_at: @from..@to, cid:).group(:status).count totals = counts.sum { |_k, v| v } diff --git a/modules/claims_api/app/sidekiq/claims_api/v2/disability_compensation_benefits_documents_uploader.rb b/modules/claims_api/app/sidekiq/claims_api/v2/disability_compensation_benefits_documents_uploader.rb index 1adf7ce2d22..6e71953375b 100644 --- a/modules/claims_api/app/sidekiq/claims_api/v2/disability_compensation_benefits_documents_uploader.rb +++ b/modules/claims_api/app/sidekiq/claims_api/v2/disability_compensation_benefits_documents_uploader.rb @@ -62,7 +62,11 @@ def bd_upload_body(auto_claim:, file_body:) end def claim_bd_upload_document(claim, pdf_path) - ClaimsApi::BD.new.upload(claim:, pdf_path:) + if Flipper.enabled? :claims_api_bd_refactor + DisabilityCompensation::DisabilityDocumentService.new.create_upload(claim:, pdf_path:) + else + ClaimsApi::BD.new.upload(claim:, pdf_path:) + end end end end diff --git a/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb b/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb index 91da3fbb97e..f4c7a5a1702 100644 --- a/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb +++ b/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb @@ -22,6 +22,7 @@ def perform(power_of_attorney_id, form_number, rep_id) output_path = pdf_constructor(form_number).construct(data(power_of_attorney, form_number, rep), id: power_of_attorney.id) + if Flipper.enabled?(:lighthouse_claims_api_poa_use_bd) doc_type = form_number == '2122' ? 'L190' : 'L075' benefits_doc_api.upload(claim: power_of_attorney, pdf_path: output_path, doc_type:) @@ -60,6 +61,7 @@ def pdf_constructor(form_number) def data(power_of_attorney, form_number, rep) res = power_of_attorney.form_data res.deep_merge!(veteran_attributes(power_of_attorney)) + res.deep_merge!(appointment_date(power_of_attorney)) signatures = if form_number == '2122A' individual_signatures(power_of_attorney, rep) @@ -78,6 +80,12 @@ def data(power_of_attorney, form_number, rep) res end + def appointment_date(power_of_attorney) + { + 'appointmentDate' => power_of_attorney.created_at + } + end + def veteran_attributes(power_of_attorney) { 'veteran' => { diff --git a/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json b/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json index 396e88d354b..a6b12d5c3a0 100644 --- a/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json +++ b/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json @@ -5072,7 +5072,7 @@ "202 without a transactionId": { "value": { "data": { - "id": "03739502-0cb3-4c75-a13a-b62b9141df35", + "id": "04fb02bc-0b7a-4594-a6d3-e426ac64f5d7", "type": "forms/526", "attributes": { "claimId": "600442191", @@ -5257,7 +5257,7 @@ }, "federalActivation": { "activationDate": "2023-10-01", - "anticipatedSeparationDate": "2024-10-10" + "anticipatedSeparationDate": "2024-10-11" }, "confinements": [ { @@ -5303,7 +5303,7 @@ "202 with a transactionId": { "value": { "data": { - "id": "9ac9026d-40c2-418a-95a4-a3a82e9f7021", + "id": "7451466b-22d8-4c01-a449-7eed8dcef91b", "type": "forms/526", "attributes": { "claimId": "600442191", @@ -10516,7 +10516,7 @@ "application/json": { "example": { "data": { - "id": "9199a0dd-94c0-4920-9395-687df0a1427f", + "id": "d884c174-2a35-4f18-8c5f-f3725226230e", "type": "forms/526", "attributes": { "claimProcessType": "STANDARD_CLAIM_PROCESS", @@ -14264,8 +14264,8 @@ "id": "1", "type": "intent_to_file", "attributes": { - "creationDate": "2024-10-08", - "expirationDate": "2025-10-08", + "creationDate": "2024-10-09", + "expirationDate": "2025-10-09", "type": "compensation", "status": "active" } @@ -15161,7 +15161,7 @@ "application/json": { "example": { "data": { - "id": "9a5f9832-701f-48ff-8748-5b9ffc576c63", + "id": "381df74a-b05c-456d-8fe6-aab246fda7f7", "type": "individual", "attributes": { "code": "067", @@ -15854,7 +15854,7 @@ "application/json": { "example": { "data": { - "id": "9c53735e-8d4a-4e05-aaf6-5faad0fb35d9", + "id": "17df2ef1-3760-4bf3-82a9-4d804f7530bc", "type": "organization", "attributes": { "code": "083", @@ -16380,11 +16380,6 @@ "pattern": ".@.", "maxLength": 61, "example": "veteran_representative@example.com" - }, - "appointmentDate": { - "description": "Date of appointment with Veteran.", - "type": "string", - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$" } } }, @@ -17688,11 +17683,6 @@ "pattern": ".@.", "maxLength": 61, "example": "veteran_representative@example.com" - }, - "appointmentDate": { - "description": "Date of appointment with Veteran.", - "type": "string", - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$" } } }, @@ -17805,10 +17795,10 @@ "application/json": { "example": { "data": { - "id": "06228ddb-efef-4d60-808a-c2a8192bb952", + "id": "79a76ea1-feb7-4499-9fd9-b607ec137024", "type": "claimsApiPowerOfAttorneys", "attributes": { - "dateRequestAccepted": "2024-10-08", + "dateRequestAccepted": "2024-10-09", "previousPoa": null, "representative": { "serviceOrganization": { diff --git a/modules/claims_api/app/swagger/claims_api/v2/production/swagger.json b/modules/claims_api/app/swagger/claims_api/v2/production/swagger.json index 8270970b43c..23b6d23eabe 100644 --- a/modules/claims_api/app/swagger/claims_api/v2/production/swagger.json +++ b/modules/claims_api/app/swagger/claims_api/v2/production/swagger.json @@ -3685,7 +3685,7 @@ "202 without a transactionId": { "value": { "data": { - "id": "3715233b-cf79-4b21-9300-c8332428b8a8", + "id": "9b23d156-6ce0-4ad8-8ba2-78d2f65c422c", "type": "forms/526", "attributes": { "claimId": "600442191", @@ -3870,7 +3870,7 @@ }, "federalActivation": { "activationDate": "2023-10-01", - "anticipatedSeparationDate": "2024-10-10" + "anticipatedSeparationDate": "2024-10-11" }, "confinements": [ { @@ -3916,7 +3916,7 @@ "202 with a transactionId": { "value": { "data": { - "id": "86887bd3-07f9-4e56-ace0-6ce6f537792f", + "id": "efa4c6af-6058-42ca-851d-48adcdf256b4", "type": "forms/526", "attributes": { "claimId": "600442191", @@ -9129,7 +9129,7 @@ "application/json": { "example": { "data": { - "id": "369558d0-b970-493c-9a75-4b63a3294011", + "id": "655cf458-1833-409d-8ecc-d9327d8ccfde", "type": "forms/526", "attributes": { "claimProcessType": "STANDARD_CLAIM_PROCESS", @@ -12877,8 +12877,8 @@ "id": "1", "type": "intent_to_file", "attributes": { - "creationDate": "2024-10-08", - "expirationDate": "2025-10-08", + "creationDate": "2024-10-09", + "expirationDate": "2025-10-09", "type": "compensation", "status": "active" } @@ -13774,7 +13774,7 @@ "application/json": { "example": { "data": { - "id": "4ee7b7ea-452b-4f21-8f0f-61cf8c078cd4", + "id": "a886dcd1-79ac-4677-9bfe-07a6a55f1d93", "type": "individual", "attributes": { "code": "067", @@ -14467,7 +14467,7 @@ "application/json": { "example": { "data": { - "id": "cf0c0b97-34f7-4adc-a86e-59c123db82ad", + "id": "ef66475e-4358-4f79-8280-d013e4767951", "type": "organization", "attributes": { "code": "083", @@ -14993,11 +14993,6 @@ "pattern": ".@.", "maxLength": 61, "example": "veteran_representative@example.com" - }, - "appointmentDate": { - "description": "Date of appointment with Veteran.", - "type": "string", - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$" } } }, @@ -16301,11 +16296,6 @@ "pattern": ".@.", "maxLength": 61, "example": "veteran_representative@example.com" - }, - "appointmentDate": { - "description": "Date of appointment with Veteran.", - "type": "string", - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$" } } }, @@ -16418,10 +16408,10 @@ "application/json": { "example": { "data": { - "id": "73e28581-64b0-4748-b9f2-5c56d654b4eb", + "id": "b791fbfe-9f11-4e61-850f-700c352c2663", "type": "claimsApiPowerOfAttorneys", "attributes": { - "dateRequestAccepted": "2024-10-08", + "dateRequestAccepted": "2024-10-09", "previousPoa": null, "representative": { "serviceOrganization": { diff --git a/modules/claims_api/config/routes.rb b/modules/claims_api/config/routes.rb index fbccee8ae6d..658cc55c9f7 100644 --- a/modules/claims_api/config/routes.rb +++ b/modules/claims_api/config/routes.rb @@ -51,6 +51,7 @@ post '/:veteranId/2122a', to: 'individual#submit' get '/:veteranId/power-of-attorney/:id', to: 'base#status' post '/:veteranId/power-of-attorney-request', to: 'request#request_representative' + post '/power-of-attorney-requests', to: 'request#index' end ## 0966 Forms get '/:veteranId/intent-to-file/:type', to: 'intent_to_file#type' @@ -64,6 +65,7 @@ post '/:veteranId/526/synchronous', to: 'disability_compensation#synchronous' end + # Deprecated resources :power_of_attorney_requests, path: 'power-of-attorney-requests', only: [:index] do scope module: :power_of_attorney_requests do resource :decision, only: [:create] diff --git a/modules/claims_api/config/schemas/v2/2122.json b/modules/claims_api/config/schemas/v2/2122.json index 9ecceb725a2..9944873e974 100644 --- a/modules/claims_api/config/schemas/v2/2122.json +++ b/modules/claims_api/config/schemas/v2/2122.json @@ -235,11 +235,6 @@ "pattern": ".@.", "maxLength": 61, "example": "veteran_representative@example.com" - }, - "appointmentDate": { - "description": "Date of appointment with Veteran.", - "type": "string", - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$" } } }, diff --git a/modules/claims_api/lib/bd/bd.rb b/modules/claims_api/lib/bd/bd.rb index 9bc03bfbab6..e4e39117538 100644 --- a/modules/claims_api/lib/bd/bd.rb +++ b/modules/claims_api/lib/bd/bd.rb @@ -67,6 +67,27 @@ def upload(claim:, pdf_path:, doc_type: 'L122', action: 'post', original_filenam raise e end + def upload_document(claim_id:, doc_type_name:, body:) + @multipart = true + res = client.post('documents', body)&.body + + raise ::Common::Exceptions::GatewayTimeout.new(detail: 'Upstream service error.') unless res.is_a?(Hash) + + res = res.deep_symbolize_keys + request_id = res.dig(:data, :requestId) + ClaimsApi::Logger.log('benefits_documents', + detail: "Successfully uploaded #{doc_type_name} doc to BD, + #{doc_type_name}_id: #{claim_id}", + request_id:) + res + rescue => e + ClaimsApi::Logger.log('benefits_documents', + detail: "/upload failure for + #{doc_type_name}_id: #{claim_id}, + #{e.message}") + raise e + end + private def doc_type_to_plain_language(doc_type) @@ -104,7 +125,8 @@ def generate_upload_body(claim:, doc_type:, pdf_path:, action:, original_filenam pctpnt_vet_id: nil) payload = {} auth_headers = claim.auth_headers - veteran_name = compact_veteran_name(auth_headers['va_eauth_firstName'], auth_headers['va_eauth_lastName']) + veteran_name = compact_veteran_name(auth_headers['va_eauth_firstName'], + auth_headers['va_eauth_lastName']) birls_file_num = determine_birls_file_number(doc_type, auth_headers) claim_id = get_claim_id(doc_type, claim) file_name = generate_file_name(doc_type:, veteran_name:, claim_id:, original_filename:, action:) diff --git a/modules/claims_api/lib/bgs_service/manage_representative_service.rb b/modules/claims_api/lib/bgs_service/manage_representative_service.rb index 3c3b0050fd1..201de99c40f 100644 --- a/modules/claims_api/lib/bgs_service/manage_representative_service.rb +++ b/modules/claims_api/lib/bgs_service/manage_representative_service.rb @@ -1,18 +1,53 @@ # frozen_string_literal: true -require_relative 'manage_representative_service/update_poa_request' - module ClaimsApi class ManageRepresentativeService < ClaimsApi::LocalBGS - private - - def make_request(**args) - super( - endpoint: 'VDC/ManageRepresentativeService', - namespaces: { 'data' => '/data' }, - transform_response: false, - **args - ) + def bean_name + 'VDC/ManageRepresentativeService' + end + + def read_poa_request(poa_codes: []) + # Workaround to allow multiple roots in the Nokogiri XML builder + # https://stackoverflow.com/a/4907450 + doc = Nokogiri::XML::DocumentFragment.parse '' + + Nokogiri::XML::Builder.with(doc) do |xml| + xml.send('data:POACodeList') do + poa_codes.each do |poa_code| + xml.POACode poa_code + end + end + xml.send('data:SecondaryStatusList') do + %w[New Pending Accepted Declined].each do |status| + xml.SecondaryStatus status + end + end + end + + body = builder_to_xml(doc) + + make_request(endpoint: bean_name, action: 'readPOARequest', body:, key: 'POARequestRespondReturnVO', + namespaces: { 'data' => '/data' }) + end + + def update_poa_request(representative:, proc_id:) + first_name = representative.try(:first_name) || representative[:first_name] + last_name = representative.try(:last_name) || representative[:last_name] + + builder = Nokogiri::XML::Builder.new do |xml| + xml.send('data:POARequestUpdate') do + xml.VSOUserFirstName first_name + xml.VSOUserLastName last_name + xml.dateRequestActioned Time.current.iso8601 + xml.procId proc_id + xml.secondaryStatus 'obsolete' + end + end + + body = builder_to_xml(builder) + + make_request(endpoint: bean_name, action: 'updatePOARequest', body:, key: 'POARequestUpdate', + namespaces: { 'data' => '/data' }, transform_response: false) end end end diff --git a/modules/claims_api/lib/bgs_service/manage_representative_service/update_poa_request.rb b/modules/claims_api/lib/bgs_service/manage_representative_service/update_poa_request.rb deleted file mode 100644 index 386fa76908e..00000000000 --- a/modules/claims_api/lib/bgs_service/manage_representative_service/update_poa_request.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -module ClaimsApi - class ManageRepresentativeService < ClaimsApi::LocalBGS - def update_poa_request(representative:, proc_id:) - first_name = representative.try(:first_name) || representative[:first_name] - last_name = representative.try(:last_name) || representative[:last_name] - - body = - Nokogiri::XML::DocumentFragment.parse <<~EOXML - - #{first_name} - #{last_name} - #{Time.current.iso8601} - #{proc_id} - - obsolete - - EOXML - - make_request( - action: 'updatePOARequest', - body: body.to_s, - key: 'POARequestUpdate' - ) - end - end -end diff --git a/modules/claims_api/lib/claims_api/error/soap_error_handler.rb b/modules/claims_api/lib/claims_api/error/soap_error_handler.rb index 88aa92e1da7..41d3f6ca72c 100644 --- a/modules/claims_api/lib/claims_api/error/soap_error_handler.rb +++ b/modules/claims_api/lib/claims_api/error/soap_error_handler.rb @@ -39,6 +39,8 @@ def get_exception raise ::Common::Exceptions::ServiceError.new( detail: 'PtcpntIdA has open claims.' ) + elsif record_not_found? + raise ::Common::Exceptions::ResourceNotFound.new(detail: 'Record not found.') else soap_logging('500') raise ::Common::Exceptions::ServiceError.new(detail: 'An external server is experiencing difficulty.') @@ -75,6 +77,13 @@ def participant_has_open_claims? has_error end + def record_not_found? + has_error = @fault_string.include?('No Record Found') + soap_logging('404') if has_error + + has_error + end + def soap_logging(status_code) ClaimsApi::Logger.log('soap_error_handler', detail: "Returning #{status_code} via local_bgs & soap_error_handler, " \ diff --git a/modules/claims_api/lib/claims_api/v2/poa_pdf_constructor/individual.rb b/modules/claims_api/lib/claims_api/v2/poa_pdf_constructor/individual.rb index 1077d349c06..7469caa0f6b 100644 --- a/modules/claims_api/lib/claims_api/v2/poa_pdf_constructor/individual.rb +++ b/modules/claims_api/lib/claims_api/v2/poa_pdf_constructor/individual.rb @@ -51,11 +51,11 @@ def page2_options(data) "#{base_form}.AuthorizationForRepActClaimantsBehalf[0]": data['consentAddressChange'] == true ? 1 : 0, # Conditions of Appointment # Item 22B - "#{base_form}.Date_Signed[0]": I18n.l(Time.zone.now.to_date, format: :va_form), + "#{base_form}.Date_Signed[0]": I18n.l(data['appointmentDate'].to_date, format: :va_form), # Item 23 "#{base_form}.LIMITATIONS[0]": data['conditionsOfAppointment']&.join(', '), # Item 24B - "#{base_form}.Date_Signed[1]": I18n.l(Time.zone.now.to_date, format: :va_form) + "#{base_form}.Date_Signed[1]": I18n.l(data['appointmentDate'].to_date, format: :va_form) } end diff --git a/modules/claims_api/lib/claims_api/v2/poa_pdf_constructor/organization.rb b/modules/claims_api/lib/claims_api/v2/poa_pdf_constructor/organization.rb index 961312c8823..df416dc952e 100644 --- a/modules/claims_api/lib/claims_api/v2/poa_pdf_constructor/organization.rb +++ b/modules/claims_api/lib/claims_api/v2/poa_pdf_constructor/organization.rb @@ -54,9 +54,9 @@ def page2_options(data) # Item 21 "#{base_form}.I_Authorize[0]": data['consentAddressChange'] == true ? 1 : 0, # Item 22B - "#{base_form}.Date_Signed[0]": I18n.l(Time.zone.now.to_date, format: :va_form), + "#{base_form}.Date_Signed[0]": I18n.l(data['appointmentDate'].to_date, format: :va_form), # Item 23B - "#{base_form}.Date_Signed[1]": I18n.l(Time.zone.now.to_date, format: :va_form) + "#{base_form}.Date_Signed[1]": I18n.l(data['appointmentDate'].to_date, format: :va_form) } end @@ -121,7 +121,7 @@ def page1_options(data) # Item 17 "#{base_form}.Email_Address[0]": data.dig('serviceOrganization', 'email'), # Item 18 - "#{base_form}.Date_Of_This_Appointment[0]": I18n.l(Time.zone.now.to_date, format: :va_form) + "#{base_form}.Date_Of_This_Appointment[0]": I18n.l(data['appointmentDate'].to_date, format: :va_form) } end # rubocop:enable Metrics/MethodLength diff --git a/modules/claims_api/spec/controllers/v2/evidence_waiver_controller_spec.rb b/modules/claims_api/spec/controllers/v2/veterans/evidence_waiver_controller_spec.rb similarity index 100% rename from modules/claims_api/spec/controllers/v2/evidence_waiver_controller_spec.rb rename to modules/claims_api/spec/controllers/v2/veterans/evidence_waiver_controller_spec.rb diff --git a/modules/claims_api/spec/controllers/v2/veterans/power_of_attorney/request_controller_spec.rb b/modules/claims_api/spec/controllers/v2/veterans/power_of_attorney/request_controller_spec.rb new file mode 100644 index 00000000000..1cc7c574fe1 --- /dev/null +++ b/modules/claims_api/spec/controllers/v2/veterans/power_of_attorney/request_controller_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'rails_helper' +require_relative '../../../../rails_helper' + +Rspec.describe ClaimsApi::V2::Veterans::PowerOfAttorney::RequestController, type: :request do + include ClaimsApi::Engine.routes.url_helpers + + describe '#index' do + let(:scopes) { %w[claim.read] } + + it 'raises a ParameterMissing error if poaCodes is not present' do + expect do + subject.index + end.to raise_error(Common::Exceptions::ParameterMissing) + end + + context 'when poaCodes is present but empty' do + before do + allow(subject).to receive(:form_attributes).and_return({ 'poaCodes' => [] }) + end + + it 'raises a ParameterMissing error' do + expect do + subject.index + end.to raise_error(Common::Exceptions::ParameterMissing) + end + end + + context 'when poaCodes is present and valid' do + let(:poa_codes) { %w[002 003 083] } + + it 'returns a list of claimants' do + mock_ccg(scopes) do |auth_header| + VCR.use_cassette('claims_api/bgs/manage_representative_service/read_poa_request_valid') do + post_request_with(poa_codes:, auth_header:) + + expect(response).to have_http_status(:ok) + expect(JSON.parse(response.body).size).to eq(16) + end + end + end + end + + context 'when poaCodes is present but no records are found' do + let(:poa_codes) { %w[XYZ] } + + it 'raises a ResourceNotFound error' do + mock_ccg(scopes) do |auth_header| + VCR.use_cassette('claims_api/bgs/manage_representative_service/read_poa_request_not_found') do + post_request_with(poa_codes:, auth_header:) + + expect(response).to have_http_status(:not_found) + end + end + end + end + end + + def post_request_with(poa_codes:, auth_header:) + post v2_veterans_power_of_attorney_requests_path, + params: { data: { attributes: { poaCodes: poa_codes } } }.to_json, + headers: auth_header + end +end diff --git a/modules/claims_api/spec/factories/auto_established_claims.rb b/modules/claims_api/spec/factories/auto_established_claims.rb index 7884b3698c5..60d275ca460 100644 --- a/modules/claims_api/spec/factories/auto_established_claims.rb +++ b/modules/claims_api/spec/factories/auto_established_claims.rb @@ -3,107 +3,56 @@ require 'claims_api/special_issue_mappers/bgs' FactoryBot.define do - factory :auto_established_claim, class: 'ClaimsApi::AutoEstablishedClaim' do + # factories + factory :auto_established_claim, class: 'ClaimsApi::AutoEstablishedClaim', + parent: :claims_api_base_factory do id { SecureRandom.uuid } - status { 'pending' } source { 'oddball' } - evss_id { nil } - auth_headers { { test: ('a'..'z').to_a.shuffle.join } } form_data do json = JSON.parse(File .read(::Rails.root.join(*'/modules/claims_api/spec/fixtures/form_526_json_api.json'.split('/')).to_s)) - json['data']['attributes'] - end - flashes { form_data.dig('veteran', 'flashes') } - special_issues do - if form_data['disabilities'].present? && form_data['disabilities'].first['specialIssues'].present? - mapper = ClaimsApi::SpecialIssueMappers::Bgs.new - [{ code: form_data['disabilities'].first['diagnosticCode'], - name: form_data['disabilities'].first['name'], - special_issues: form_data['disabilities'].first['specialIssues'].map { |si| mapper.code_from_name!(si) } }] - else - [] - end + attributes = json['data']['attributes'] + attributes['disabilities'][0]['specialIssues'] = [] + attributes end - - trait :status_established do - status { 'established' } - evss_id { 600_118_851 } - end - - trait :status_errored do - status { 'errored' } - evss_response { 'something' } - end - - trait :autoCestPDFGeneration_disabled do - form_data do - json = JSON.parse(File - .read(::Rails.root.join(*'/modules/claims_api/spec/fixtures/form_526_json_api.json'.split('/')) - .to_s)) - json['data']['attributes']['autoCestPDFGenerationDisabled'] = false - json['data']['attributes'] - end - end - - factory :auto_established_claim_with_supporting_documents do - after(:create) do |auto_established_claim| - create_list(:supporting_document, 1, auto_established_claim:) - end + end + factory :auto_established_claim_with_supporting_documents, parent: :auto_established_claim do + after(:create) do |auto_established_claim| + create_list(:supporting_document, 1, auto_established_claim:) end end - factory :auto_established_claim_va_gov, class: 'ClaimsApi::AutoEstablishedClaim' do + factory :auto_established_claim_v2, class: 'ClaimsApi::AutoEstablishedClaim', parent: :auto_established_claim do id { SecureRandom.uuid } - evss_id { nil } - auth_headers { { test: ('a'..'z').to_a.shuffle.join } } + status { 'pending' } form_data do - # rubocop:disable Layout/LineLength json = JSON.parse(File - .read(::Rails.root.join(*'/modules/claims_api/spec/fixtures/form_526_no_flashes_no_special_issues.json'.split('/')).to_s)) + .read( + ::Rails.root.join( + *'/modules/claims_api/spec/fixtures/v2/veterans/disability_compensation/form_526_json_api.json' + .split('/') + ).to_s + )) json['data']['attributes'] end + end + factory :auto_established_claim_va_gov, class: 'ClaimsApi::AutoEstablishedClaim', parent: :auto_established_claim do + id { SecureRandom.uuid } cid { '0oagdm49ygCSJTp8X297' } transaction_id { Faker::Number.number(digits: 20) } created_at { Faker::Date.between(from: 1.day.ago, to: Time.zone.now) } - status { ClaimsApi::AutoEstablishedClaim::ERRORED } end - trait :set_transaction_id do - transaction_id { '25' } + # traits + trait :flashes do + flashes { %w[Hardship Homeless] } end - - factory :auto_established_claim_without_flashes_or_special_issues, class: 'ClaimsApi::AutoEstablishedClaim' do - id { SecureRandom.uuid } - status { 'pending' } - source { 'oddball' } - evss_id { nil } - auth_headers { { test: ('a'..'z').to_a.shuffle.join } } - form_data do - json = JSON.parse(File - .read(::Rails.root.join(*'/modules/claims_api/spec/fixtures/form_526_no_flashes_no_special_issues.json'.split('/')).to_s)) - json['data']['attributes'] - end - # rubocop:enable Layout/LineLength - - trait :status_errored do - status { 'errored' } - evss_response { 'something' } - end - end - - factory :auto_established_claim_with_auth_headers, class: 'ClaimsApi::AutoEstablishedClaim' do - id { SecureRandom.uuid } - status { 'pending' } - source { 'oddball' } - evss_id { nil } - auth_headers { { va_eauth_pnid: '123456789', va_eauth_pid: '123456789' } } + trait :special_issues do form_data do json = JSON.parse(File .read(::Rails.root.join(*'/modules/claims_api/spec/fixtures/form_526_json_api.json'.split('/')).to_s)) json['data']['attributes'] end - flashes { form_data.dig('veteran', 'flashes') } special_issues do if form_data['disabilities'].present? && form_data['disabilities'].first['specialIssues'].present? mapper = ClaimsApi::SpecialIssueMappers::Bgs.new @@ -115,163 +64,7 @@ end end end - - factory :bgs_response, class: OpenStruct do - bnft_claim_dto { (association :benefit_claim_details_dto).to_h } - end - - factory :benefit_claim_details_dto, class: OpenStruct do - bnft_claim_id { Faker::Number.number(digits: 9) } - bnft_claim_type_cd { Faker::Alphanumeric.alpha(number: 9) } - bnft_claim_type_label { 'Compensation' } - bnft_claim_type_nm { 'Claim for Increase' } - bnft_claim_user_display { 'YES' } - claim_jrsdtn_lctn_id { Faker::Number.number(digits: 6) } - claim_rcvd_dt { Faker::Date.backward(days: 90) } - cp_claim_end_prdct_type_cd { Faker::Number.number(digits: 3) } - jrn_dt { Faker::Time.backward(days: 5, period: :morning) } - jrn_lctn_id { Faker::Number.number(digits: 3) } - jrn_obj_id { 'cd_clm_lc_status_pkg.do_create' } - jrn_status_type_cd { 'U' } - jrn_user_id { 'VBMSSYSACCT' } - payee_type_cd { Faker::Number.number(digits: 2) } - payee_type_nm { 'Veteran' } - pgm_type_cd { 'CPL' } - pgm_type_nm { 'Compensation-Pension Live' } - ptcpnt_clmant_id { Faker::Number.number(digits: 9) } - ptcpnt_clmant_nm { Faker::Name.name } - ptcpnt_mail_addrs_id { Faker::Number.number(digits: 8) } - ptcpnt_pymt_addrs_id { Faker::Number.number(digits: 8) } - ptcpnt_vet_id { Faker::Number.number(digits: 9) } - ptcpnt_vsr_id { Faker::Number.number(digits: 9) } - station_of_jurisdiction { Faker::Number.number(digits: 3) } - status_type_cd { 'RFD' } - status_type_nm { 'Ready for Decision' } - submtr_applcn_type_cd { 'VBMS' } - submtr_role_type_cd { 'VBA' } - svc_type_cd { 'CP' } - termnl_digit_nbr { Faker::Number.number(digits: 2) } - filed5103_waiver_ind { 'Y' } - end - factory :bgs_response_with_one_lc_status, class: OpenStruct do - benefit_claim_details_dto { (association :bgs_claim_details_dto_with_one_lc_status).to_h } - end - factory :bgs_response_with_lc_status, class: OpenStruct do - benefit_claim_details_dto { (association :bgs_claim_details_dto_with_lc_status).to_h } - end - factory :bgs_response_with_under_review_lc_status, class: OpenStruct do - benefit_claim_details_dto { (association :bgs_claim_details_dto_with_under_review_lc_status).to_h } - end - factory :bgs_response_with_phaseback_lc_status, class: OpenStruct do - benefit_claim_details_dto { (association :bgs_claim_details_dto_with_phaseback_lc_status).to_h } - end - factory :bgs_response_claim_with_unmatched_ptcpnt_vet_id, class: OpenStruct do - benefit_claim_details_dto { - (association :bgs_claim_details_with_unmatched_vet_id).to_h - } - end - factory :bgs_claim_details_dto_with_under_review_lc_status, class: OpenStruct do - benefit_claim_id { '111111111' } - phase_chngd_dt { Faker::Time.backward(days: 5, period: :morning) } - phase_type { 'Under Review' } - ptcpnt_clmant_id { Faker::Number.number(digits: 17) } - ptcpnt_vet_id { Faker::Number.number(digits: 17) } - phase_type_change_ind { '76' } - claim_status_type { 'Compensation' } - bnft_claim_lc_status { [(association :bnft_claim_lc_status_two).to_h] } - end - factory :bgs_claim_details_dto_with_one_lc_status, class: OpenStruct do - benefit_claim_id { '111111111' } - phase_chngd_dt { Faker::Time.backward(days: 5, period: :morning) } - phase_type { 'Pending Decision Approval' } - ptcpnt_clmant_id { Faker::Number.number(digits: 17) } - ptcpnt_vet_id { Faker::Number.number(digits: 17) } - phase_type_change_ind { '76' } - claim_status_type { 'Compensation' } - bnft_claim_lc_status { [(association :bnft_claim_lc_status_one).to_h] } - end - factory :bgs_claim_details_dto_with_lc_status, class: OpenStruct do - benefit_claim_id { '111111111' } - phase_chngd_dt { Faker::Time.backward(days: 5, period: :morning) } - phase_type { 'Pending Decision Approval' } - ptcpnt_clmant_id { Faker::Number.number(digits: 17) } - ptcpnt_vet_id { Faker::Number.number(digits: 17) } - phase_type_change_ind { '76' } - claim_complete_dt { Faker::Time.backward(days: 3, period: :morning) } - claim_status_type { 'Compensation' } - bnft_claim_lc_status { - [(association :bnft_claim_lc_status_five).to_h, (association :bnft_claim_lc_status_four).to_h, - (association :bnft_claim_lc_status_three).to_h, (association :bnft_claim_lc_status_two).to_h, - (association :bnft_claim_lc_status_one).to_h] - } - end - factory :bgs_claim_details_dto_with_phaseback_lc_status, class: OpenStruct do - benefit_claim_id { '111111111' } - phase_chngd_dt { Faker::Time.backward(days: 5, period: :morning) } - ptcpnt_clmant_id { Faker::Number.number(digits: 17) } - ptcpnt_vet_id { Faker::Number.number(digits: 17) } - claim_status_type { 'Compensation' } - bnft_claim_lc_status { [(association :bnft_claim_lc_status_phaseback).to_h] } - end - factory :bnft_claim_lc_status_one, class: OpenStruct do - max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } - min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } - phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } - phase_type { 'Claim Received' } - phase_type_change_ind { 'N' } - end - factory :bnft_claim_lc_status_two, class: OpenStruct do - max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } - min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } - phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } - phase_type { 'Under Review' } - phase_type_change_ind { '12' } - end - factory :bnft_claim_lc_status_three, class: OpenStruct do - max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } - min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } - phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } - phase_type { 'Gathering of Evidence' } - phase_type_change_ind { '23' } - end - factory :bnft_claim_lc_status_four, class: OpenStruct do - max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } - min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } - phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } - phase_type { 'Review of Evidence' } - phase_type_change_ind { '34' } - end - factory :bnft_claim_lc_status_five, class: OpenStruct do - max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } - min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } - phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } - phase_type { 'Preparation for Decision' } - phase_type_change_ind { '45' } - end - factory :bnft_claim_lc_status_phaseback, class: OpenStruct do - max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } - min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } - phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } - phase_type { 'Under Review' } - phase_type_change_ind { '32' } - end - factory :bgs_claim_details_with_unmatched_vet_id, class: OpenStruct do - benefit_claim_id { '111111111' } - phase_chngd_dt { Faker::Time.backward(days: 5, period: :morning) } - phase_type { 'Pending Decision Approval' } - phase_type_change_ind { '76' } - ptcpnt_vet_id { Faker::Number.number(digits: 9) } - ptcpnt_clmant_id { '8675309' } - claim_status_type { 'Compensation' } - bnft_claim_lc_status { [(association :bnft_claim_lc_status_one).to_h] } - end - - factory :auto_established_claim_v2, class: 'ClaimsApi::AutoEstablishedClaim' do - id { SecureRandom.uuid } - status { 'pending' } - source { 'oddball' } - evss_id { nil } - auth_headers { { test: ('a'..'z').to_a.shuffle.join } } + trait :special_issues_v2 do form_data do json = JSON.parse(File .read( @@ -282,5 +75,28 @@ )) json['data']['attributes'] end + special_issues do + if form_data['disabilities'].present? && form_data['disabilities'].first['specialIssues'].present? + mapper = ClaimsApi::SpecialIssueMappers::Bgs.new + [{ code: form_data['disabilities'].first['diagnosticCode'], + name: form_data['disabilities'].first['name'], + special_issues: form_data['disabilities'].first['specialIssues'].map { |si| mapper.code_from_name!(si) } }] + else + [] + end + end + end + trait :autoCestPDFGeneration_disabled do + form_data do + json = JSON.parse(File + .read(::Rails.root.join(*'/modules/claims_api/spec/fixtures/form_526_json_api.json'.split('/')) + .to_s)) + json['data']['attributes']['autoCestPDFGenerationDisabled'] = false + json['data']['attributes'] + end + end + + trait :set_transaction_id do + transaction_id { '25' } end end diff --git a/modules/claims_api/spec/factories/bgs_response.rb b/modules/claims_api/spec/factories/bgs_response.rb new file mode 100644 index 00000000000..9e8b243ea36 --- /dev/null +++ b/modules/claims_api/spec/factories/bgs_response.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :bgs_response, class: OpenStruct do + bnft_claim_dto { (association :benefit_claim_details_dto).to_h } + end + + factory :benefit_claim_details_dto, class: OpenStruct do + bnft_claim_id { Faker::Number.number(digits: 9) } + bnft_claim_type_cd { Faker::Alphanumeric.alpha(number: 9) } + bnft_claim_type_label { 'Compensation' } + bnft_claim_type_nm { 'Claim for Increase' } + bnft_claim_user_display { 'YES' } + claim_jrsdtn_lctn_id { Faker::Number.number(digits: 6) } + claim_rcvd_dt { Faker::Date.backward(days: 90) } + cp_claim_end_prdct_type_cd { Faker::Number.number(digits: 3) } + jrn_dt { Faker::Time.backward(days: 5, period: :morning) } + jrn_lctn_id { Faker::Number.number(digits: 3) } + jrn_obj_id { 'cd_clm_lc_status_pkg.do_create' } + jrn_status_type_cd { 'U' } + jrn_user_id { 'VBMSSYSACCT' } + payee_type_cd { Faker::Number.number(digits: 2) } + payee_type_nm { 'Veteran' } + pgm_type_cd { 'CPL' } + pgm_type_nm { 'Compensation-Pension Live' } + ptcpnt_clmant_id { Faker::Number.number(digits: 9) } + ptcpnt_clmant_nm { Faker::Name.name } + ptcpnt_mail_addrs_id { Faker::Number.number(digits: 8) } + ptcpnt_pymt_addrs_id { Faker::Number.number(digits: 8) } + ptcpnt_vet_id { Faker::Number.number(digits: 9) } + ptcpnt_vsr_id { Faker::Number.number(digits: 9) } + station_of_jurisdiction { Faker::Number.number(digits: 3) } + status_type_cd { 'RFD' } + status_type_nm { 'Ready for Decision' } + submtr_applcn_type_cd { 'VBMS' } + submtr_role_type_cd { 'VBA' } + svc_type_cd { 'CP' } + termnl_digit_nbr { Faker::Number.number(digits: 2) } + filed5103_waiver_ind { 'Y' } + end + factory :bgs_response_with_one_lc_status, class: OpenStruct do + benefit_claim_details_dto { (association :bgs_claim_details_dto_with_one_lc_status).to_h } + end + factory :bgs_response_with_lc_status, class: OpenStruct do + benefit_claim_details_dto { (association :bgs_claim_details_dto_with_lc_status).to_h } + end + factory :bgs_response_with_under_review_lc_status, class: OpenStruct do + benefit_claim_details_dto { (association :bgs_claim_details_dto_with_under_review_lc_status).to_h } + end + factory :bgs_response_with_phaseback_lc_status, class: OpenStruct do + benefit_claim_details_dto { (association :bgs_claim_details_dto_with_phaseback_lc_status).to_h } + end + factory :bgs_response_claim_with_unmatched_ptcpnt_vet_id, class: OpenStruct do + benefit_claim_details_dto { + (association :bgs_claim_details_with_unmatched_vet_id).to_h + } + end + factory :bgs_claim_details_dto_with_under_review_lc_status, class: OpenStruct do + benefit_claim_id { '111111111' } + phase_chngd_dt { Faker::Time.backward(days: 5, period: :morning) } + phase_type { 'Under Review' } + ptcpnt_clmant_id { Faker::Number.number(digits: 17) } + ptcpnt_vet_id { Faker::Number.number(digits: 17) } + phase_type_change_ind { '76' } + claim_status_type { 'Compensation' } + bnft_claim_lc_status { [(association :bnft_claim_lc_status_two).to_h] } + end + factory :bgs_claim_details_dto_with_one_lc_status, class: OpenStruct do + benefit_claim_id { '111111111' } + phase_chngd_dt { Faker::Time.backward(days: 5, period: :morning) } + phase_type { 'Pending Decision Approval' } + ptcpnt_clmant_id { Faker::Number.number(digits: 17) } + ptcpnt_vet_id { Faker::Number.number(digits: 17) } + phase_type_change_ind { '76' } + claim_status_type { 'Compensation' } + bnft_claim_lc_status { [(association :bnft_claim_lc_status_one).to_h] } + end + factory :bgs_claim_details_dto_with_lc_status, class: OpenStruct do + benefit_claim_id { '111111111' } + phase_chngd_dt { Faker::Time.backward(days: 5, period: :morning) } + phase_type { 'Pending Decision Approval' } + ptcpnt_clmant_id { Faker::Number.number(digits: 17) } + ptcpnt_vet_id { Faker::Number.number(digits: 17) } + phase_type_change_ind { '76' } + claim_complete_dt { Faker::Time.backward(days: 3, period: :morning) } + claim_status_type { 'Compensation' } + bnft_claim_lc_status { + [(association :bnft_claim_lc_status_five).to_h, (association :bnft_claim_lc_status_four).to_h, + (association :bnft_claim_lc_status_three).to_h, (association :bnft_claim_lc_status_two).to_h, + (association :bnft_claim_lc_status_one).to_h] + } + end + factory :bgs_claim_details_dto_with_phaseback_lc_status, class: OpenStruct do + benefit_claim_id { '111111111' } + phase_chngd_dt { Faker::Time.backward(days: 5, period: :morning) } + ptcpnt_clmant_id { Faker::Number.number(digits: 17) } + ptcpnt_vet_id { Faker::Number.number(digits: 17) } + claim_status_type { 'Compensation' } + bnft_claim_lc_status { [(association :bnft_claim_lc_status_phaseback).to_h] } + end + factory :bnft_claim_lc_status_one, class: OpenStruct do + max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } + min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } + phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } + phase_type { 'Claim Received' } + phase_type_change_ind { 'N' } + end + factory :bnft_claim_lc_status_two, class: OpenStruct do + max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } + min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } + phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } + phase_type { 'Under Review' } + phase_type_change_ind { '12' } + end + factory :bnft_claim_lc_status_three, class: OpenStruct do + max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } + min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } + phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } + phase_type { 'Gathering of Evidence' } + phase_type_change_ind { '23' } + end + factory :bnft_claim_lc_status_four, class: OpenStruct do + max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } + min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } + phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } + phase_type { 'Review of Evidence' } + phase_type_change_ind { '34' } + end + factory :bnft_claim_lc_status_five, class: OpenStruct do + max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } + min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } + phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } + phase_type { 'Preparation for Decision' } + phase_type_change_ind { '45' } + end + factory :bnft_claim_lc_status_phaseback, class: OpenStruct do + max_est_claim_complete_dt { Faker::Time.backward(days: 5, period: :morning) } + min_est_claim_complete_dt { Faker::Time.backward(days: 7, period: :morning) } + phase_chngd_dt { Faker::Time.backward(days: 6, period: :morning) } + phase_type { 'Under Review' } + phase_type_change_ind { '32' } + end + factory :bgs_claim_details_with_unmatched_vet_id, class: OpenStruct do + benefit_claim_id { '111111111' } + phase_chngd_dt { Faker::Time.backward(days: 5, period: :morning) } + phase_type { 'Pending Decision Approval' } + phase_type_change_ind { '76' } + ptcpnt_vet_id { Faker::Number.number(digits: 9) } + ptcpnt_clmant_id { '8675309' } + claim_status_type { 'Compensation' } + bnft_claim_lc_status { [(association :bnft_claim_lc_status_one).to_h] } + end +end diff --git a/modules/claims_api/spec/factories/claims_api_base_factory.rb b/modules/claims_api/spec/factories/claims_api_base_factory.rb index 8025b61650a..34a65cb1fe8 100644 --- a/modules/claims_api/spec/factories/claims_api_base_factory.rb +++ b/modules/claims_api/spec/factories/claims_api_base_factory.rb @@ -52,6 +52,11 @@ status { 'submitted' } end + trait :established do + status { 'established' } + evss_id { 600_118_851 } + end + trait :vbms_error_message do vbms_error_message { 'A VBMS error has occurred' } end diff --git a/modules/claims_api/spec/factories/intent_to_file.rb b/modules/claims_api/spec/factories/intent_to_file.rb new file mode 100644 index 00000000000..5ded0e00d2e --- /dev/null +++ b/modules/claims_api/spec/factories/intent_to_file.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :intent_to_file, class: 'ClaimsApi::IntentToFile' do + id { FactoryBot.generate(:uuid) } + created_at { Time.zone.now } + status { %w[pending errored submitted].sample } + cid { + %w[0oa9uf05lgXYk6ZXn297 0oa66qzxiq37neilh297 0oadnb0o063rsPupH297 0oadnb1x4blVaQ5iY297 + 0oadnavva9u5F6vRz297 0oagdm49ygCSJTp8X297 0oaqzbqj9wGOCJBG8297 0oao7p92peuKEvQ73297].sample + } + end + + trait :itf_errored do + status { 'errored' } + end +end diff --git a/modules/claims_api/spec/lib/claims_api/bd_spec.rb b/modules/claims_api/spec/lib/claims_api/bd_spec.rb index 93ed321ba81..989131c66c5 100644 --- a/modules/claims_api/spec/lib/claims_api/bd_spec.rb +++ b/modules/claims_api/spec/lib/claims_api/bd_spec.rb @@ -12,6 +12,7 @@ tracked_items: [234, 235]) end.freeze let(:claim) { create(:auto_established_claim, evss_id: 600_400_688, id: '581128c6-ad08-4b1e-8b82-c3640e829fb3') } + let(:body) { 'test body' } before do allow_any_instance_of(ClaimsApi::V2::BenefitsDocuments::Service) @@ -30,6 +31,14 @@ end end + it 'uploads a document to BD using refactored #upload_document' do + VCR.use_cassette('claims_api/bd/upload') do + result = subject.upload_document(claim_id: claim.evss_id, doc_type_name: 'claim', body:) + expect(result).to be_a Hash + expect(result[:data][:success]).to be true + end + end + it 'uploads an attachment to BD for L023' do result = subject.send(:generate_upload_body, claim:, doc_type: 'L023', pdf_path:, action: 'post', original_filename: 'stuff.pdf') diff --git a/modules/claims_api/spec/lib/claims_api/disability_document_service_spec.rb b/modules/claims_api/spec/lib/claims_api/disability_document_service_spec.rb new file mode 100644 index 00000000000..4ab9414fe71 --- /dev/null +++ b/modules/claims_api/spec/lib/claims_api/disability_document_service_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'rails_helper' +require_relative '../../rails_helper' + +describe ClaimsApi::DisabilityCompensation::DisabilityDocumentService do + subject { described_class.new } + + let(:claim) { create(:auto_established_claim, evss_id: 600_400_688, id: '581128c6-ad08-4b1e-8b82-c3640e829fb3') } + let(:body) { 'test body' } + + before do + allow_any_instance_of(ClaimsApi::V2::BenefitsDocuments::Service) + .to receive(:get_auth_token).and_return('some-value-here') + end + + describe 'disability comp (doc_type: L122)' do + let(:veteran_name) { 'John_Smith' } + let(:claim_id) { '600_400_688' } + let(:form_name) { '526EZ' } + let(:original_filename) { '' } + let(:doc_type) { 'L122' } + + it 'generates the correct filename for L122' do + result = subject.send(:generate_file_name, veteran_name:, claim_id:, form_name:, original_filename:) + expect(result).to be_a String + expect(result).to eq 'John_Smith_600_400_688_526EZ.pdf' + end + end + + describe 'other attachments (doc_type: L023)' do + let(:veteran_name) { 'John_Smith' } + let(:claim_id) { '600_400_688' } + let(:form_name) { 'supporting' } + let(:original_filename) { 'original_filename_IRT56SX99qs.pdf' } + let(:doc_type) { 'L023' } + + it 'generates the correct filename for L023' do + result = subject.send(:generate_file_name, veteran_name:, claim_id:, form_name:, original_filename:) + expect(result).to be_a String + expect(result).to eq 'John_Smith_600_400_688_original_filename.pdf' + end + end +end diff --git a/modules/claims_api/spec/lib/claims_api/document_service_base_spec.rb b/modules/claims_api/spec/lib/claims_api/document_service_base_spec.rb new file mode 100644 index 00000000000..f7398810539 --- /dev/null +++ b/modules/claims_api/spec/lib/claims_api/document_service_base_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'rails_helper' +require_relative '../../rails_helper' + +describe ClaimsApi::DocumentServiceBase do + subject { described_class.new } + + let(:claim_id) { '581128c6-ad08-4b1e-8b82-c3640e829fb3' } + + describe '#build_body' do + it 'builds an L122 (526) body correctly' do + result = subject.send(:build_body, system_name: 'VA.gov', doc_type: 'L122', file_name: '21-526EZ.pdf', claim_id:) + + expected = { data: { systemName: 'VA.gov', docType: 'L122', claimId: '581128c6-ad08-4b1e-8b82-c3640e829fb3', + fileName: '21-526EZ.pdf', trackedItemIds: [] } } + expect(result).to eq(expected) + end + + it 'builds an L023 (correspondence) body correctly' do + result = subject.send(:build_body, system_name: 'VA.gov', doc_type: 'L023', file_name: 'rx.pdf', claim_id:) + + expected = { data: { systemName: 'VA.gov', docType: 'L023', claimId: '581128c6-ad08-4b1e-8b82-c3640e829fb3', + fileName: 'rx.pdf', trackedItemIds: [] } } + expect(result).to eq(expected) + end + end +end diff --git a/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/individual_spec.rb b/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/individual_spec.rb index aafa7a5aae3..dd7449d463c 100644 --- a/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/individual_spec.rb +++ b/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/individual_spec.rb @@ -134,6 +134,7 @@ 'ssn' => power_of_attorney.auth_headers['va_eauth_pnid'], 'birthdate' => power_of_attorney.auth_headers['va_eauth_birthdate'] }, + 'appointmentDate' => power_of_attorney.created_at, 'text_signatures' => { 'page2' => [ { @@ -172,6 +173,7 @@ 'ssn' => power_of_attorney.auth_headers['va_eauth_pnid'], 'birthdate' => power_of_attorney.auth_headers['va_eauth_birthdate'] }, + 'appointmentDate' => power_of_attorney.created_at, 'text_signatures' => { 'page2' => [ { diff --git a/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/organization_spec.rb b/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/organization_spec.rb index 1a4b7f60b7d..1734cf2c9e9 100644 --- a/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/organization_spec.rb +++ b/modules/claims_api/spec/lib/claims_api/v2/poa_pdf_constructor/organization_spec.rb @@ -78,6 +78,7 @@ 'ssn' => power_of_attorney.auth_headers['va_eauth_pnid'], 'birthdate' => power_of_attorney.auth_headers['va_eauth_birthdate'] }, + 'appointmentDate' => power_of_attorney.created_at, 'text_signatures' => { 'page2' => [ { diff --git a/modules/claims_api/spec/mailers/report_monthly_submissions_spec.rb b/modules/claims_api/spec/mailers/report_monthly_submissions_spec.rb index b130f6b49c4..c30162b4eae 100644 --- a/modules/claims_api/spec/mailers/report_monthly_submissions_spec.rb +++ b/modules/claims_api/spec/mailers/report_monthly_submissions_spec.rb @@ -8,7 +8,7 @@ from = 1.month.ago to = Time.zone.now - claim = create(:auto_established_claim, :status_established) + claim = create(:auto_established_claim, :established) ClaimsApi::ClaimSubmission.create claim:, claim_type: 'PACT', consumer_label: 'Consumer name here' described_class.build( diff --git a/modules/claims_api/spec/models/auto_establish_claim_spec.rb b/modules/claims_api/spec/models/auto_establish_claim_spec.rb index d0e39d22514..35de560af2d 100644 --- a/modules/claims_api/spec/models/auto_establish_claim_spec.rb +++ b/modules/claims_api/spec/models/auto_establish_claim_spec.rb @@ -3,8 +3,8 @@ require 'rails_helper' RSpec.describe ClaimsApi::AutoEstablishedClaim, type: :model do - let(:auto_form) { build(:auto_established_claim, auth_headers: { some: 'data' }) } - let(:pending_record) { create(:auto_established_claim) } + let(:auto_form) { create(:auto_established_claim_va_gov, auth_headers: { some: 'data' }) }.freeze + let(:pending_record) { create(:auto_established_claim, :special_issues, :flashes) }.freeze describe 'encrypted attributes' do it 'does the thing' do @@ -23,22 +23,17 @@ end it 'writes flashes and special issues to the DB on create' do - pending_record.status = 'submitted' - expected_claims = ClaimsApi::AutoEstablishedClaim.all - expect(expected_claims.first.id).to eq(pending_record.id) - expect(expected_claims.first.special_issues).to eq(pending_record.special_issues) - expect(expected_claims.first.flashes).to eq(%w[Hardship Homeless]) - expect(expected_claims.first.special_issues.first['special_issues']).to eq(['FDC', 'PTSD/2']) + pending_claim = ClaimsApi::AutoEstablishedClaim.find(pending_record.id) + va_gov_claim = ClaimsApi::AutoEstablishedClaim.find(auto_form.id) + + expect(pending_claim.form_data['disabilities'][0]['specialIssues']).to eq(['Fully Developed Claim', 'PTSD/2']) + expect(pending_claim.flashes).to eq(%w[Hardship Homeless]) + expect(va_gov_claim.form_data['disabilities'][0]['specialIssues']).to eq([]) end describe "persisting 'cid' (OKTA client_id)" do it "stores 'cid' in the DB upon creation" do - auto_form.cid = 'ABC123' - auto_form.save! - - claim = ClaimsApi::AutoEstablishedClaim.first - - expect(claim.cid).to eq('ABC123') + expect(auto_form.cid).to eq('0oagdm49ygCSJTp8X297') end end @@ -508,6 +503,33 @@ expect(payload['form526']['treatments'][0]['center']['name']).to eq(' ') end + + context 'handles empty spaces and dashes in the unitPhone numbers values' do + let(:temp_form_data) do + pending_record.form_data.tap do |data| + data['serviceInformation']['reservesNationalGuardService']['unitPhone'] = { + 'areaCode' => ' 555 ', + 'phoneNumber' => '555-5555 ' + } + end + end + let(:payload) { JSON.parse(pending_record.to_internal) } + let(:reserves) { payload['form526']['serviceInformation']['reservesNationalGuardService'] } + + before do + pending_record.form_data = temp_form_data + end + + it 'removes any extra spaces and dashes from the phoneNumber' do + phone_number = reserves['unitPhone']['phoneNumber'] + expect(phone_number).to eq('5555555') + end + + it 'removes any extra spaces from the areaCode' do + phone_number = reserves['unitPhone']['areaCode'] + expect(phone_number).to eq('555') + end + end end describe 'evss_id_by_token' do @@ -741,7 +763,7 @@ describe "'remove_encrypted_fields' callback" do context "when 'status' is 'established'" do - let(:auto_form) { create(:auto_established_claim, :status_established, auth_headers: { some: 'data' }) } + let(:auto_form) { create(:auto_established_claim, :established, auth_headers: { some: 'data' }) } context 'and the record is updated' do it "erases the 'form_data' attribute" do @@ -765,7 +787,7 @@ end it "does not erase the 'file_data' attribute" do - auto_form = build(:auto_established_claim, :status_established, auth_headers: { some: 'data' }) + auto_form = build(:auto_established_claim, :established, auth_headers: { some: 'data' }) file = Rack::Test::UploadedFile.new( ::Rails.root.join(*'/modules/claims_api/spec/fixtures/extras.pdf'.split('/')).to_s ) diff --git a/modules/claims_api/spec/requests/v1/claims_spec.rb b/modules/claims_api/spec/requests/v1/claims_spec.rb index df1a0f4952a..664151ccec8 100644 --- a/modules/claims_api/spec/requests/v1/claims_spec.rb +++ b/modules/claims_api/spec/requests/v1/claims_spec.rb @@ -106,6 +106,7 @@ it 'shows a single Claim through auto established claims', run_at: 'Wed, 13 Dec 2017 03:28:23 GMT' do mock_acg(scopes) do |auth_header| create(:auto_established_claim, + status: 'pending', source: 'abraham lincoln', auth_headers: { some: 'data' }, evss_id: 600_118_851, @@ -125,6 +126,7 @@ run_at: 'Wed, 13 Dec 2017 03:28:23 GMT' do mock_acg(scopes) do |auth_header| create(:auto_established_claim, + status: 'pending', source: 'abraham lincoln', auth_headers: { some: 'data' }, evss_id: 600_118_851, @@ -145,6 +147,7 @@ it 'shows a single Claim through auto established claims', run_at: 'Wed, 13 Dec 2017 03:28:23 GMT' do mock_acg(scopes) do |auth_header| create(:auto_established_claim, + status: 'pending', source: 'abraham lincoln', auth_headers: { some: 'data' }, evss_id: 600_118_851, @@ -166,6 +169,7 @@ it 'shows a single Claim through auto established claims', run_at: 'Wed, 13 Dec 2017 03:28:23 GMT' do mock_acg(scopes) do |auth_header| create(:auto_established_claim, + status: 'pending', source: 'oddball', auth_headers: { some: 'data' }, evss_id: 600_118_851, diff --git a/modules/claims_api/spec/requests/v1/forms/526_spec.rb b/modules/claims_api/spec/requests/v1/forms/526_spec.rb index f270002b005..991c1066e39 100644 --- a/modules/claims_api/spec/requests/v1/forms/526_spec.rb +++ b/modules/claims_api/spec/requests/v1/forms/526_spec.rb @@ -2947,7 +2947,7 @@ def obj.class end context 'when a claim is already established' do - let(:auto_claim) { create(:auto_established_claim, :status_established) } + let(:auto_claim) { create(:auto_established_claim, :established) } it 'returns a 404 error because only pending claims are allowed' do mock_acg(scopes) do |auth_header| diff --git a/modules/claims_api/spec/requests/v1/forms/rswag_526_spec.rb b/modules/claims_api/spec/requests/v1/forms/rswag_526_spec.rb index ed0a17e601f..eb632291303 100644 --- a/modules/claims_api/spec/requests/v1/forms/rswag_526_spec.rb +++ b/modules/claims_api/spec/requests/v1/forms/rswag_526_spec.rb @@ -297,7 +297,7 @@ def append_example_metadata(example, response) 'disability', 'upload.json').read) let(:scopes) { %w[claim.write] } - let(:auto_claim) { create(:auto_established_claim) } + let(:auto_claim) { create(:auto_established_claim, status: ClaimsApi::AutoEstablishedClaim::PENDING) } let(:attachment) do Rack::Test::UploadedFile.new(Rails.root.join(*'/modules/claims_api/spec/fixtures/extras.pdf'.split('/')) .to_s) @@ -330,13 +330,12 @@ def append_example_metadata(example, response) describe 'Getting a 400 response' do response '400', 'Bad Request' do let(:scopes) { %w[claim.write] } - let(:auto_claim) { create(:auto_established_claim) } + let(:auto_claim) { create(:auto_established_claim, status: ClaimsApi::PowerOfAttorney::ERRORED) } let(:attachment) { nil } let(:id) { auto_claim.id } before do |example| stub_poa_verification - mock_acg(scopes) do submit_request(example.metadata) end @@ -686,7 +685,7 @@ def append_example_metadata(example, response) 'disability', 'attachments.json').read) let(:scopes) { %w[claim.write] } - let(:auto_claim) { create(:auto_established_claim) } + let(:auto_claim) { create(:auto_established_claim, status: ClaimsApi::AutoEstablishedClaim::PENDING) } let(:attachment1) do Rack::Test::UploadedFile.new(Rails.root.join(*'/modules/claims_api/spec/fixtures/extras.pdf'.split('/')) .to_s) diff --git a/modules/claims_api/spec/requests/v1/rswag_claims_spec.rb b/modules/claims_api/spec/requests/v1/rswag_claims_spec.rb index abb7b36ebfd..e9bea229c92 100644 --- a/modules/claims_api/spec/requests/v1/rswag_claims_spec.rb +++ b/modules/claims_api/spec/requests/v1/rswag_claims_spec.rb @@ -193,7 +193,7 @@ let(:scopes) { %w[claim.read] } let(:claim) do - create(:auto_established_claim_with_supporting_documents, :status_established, source: 'abraham lincoln') + create(:auto_established_claim_with_supporting_documents, :established, source: 'abraham lincoln') end let(:id) { claim.id } @@ -294,13 +294,14 @@ let(:scopes) { %w[claim.read] } let(:claim) do - create(:auto_established_claim_with_supporting_documents, :status_errored) + create(:auto_established_claim_with_supporting_documents) end let(:id) { claim.id } before do |example| stub_poa_verification + claim.status = ClaimsApi::AutoEstablishedClaim::ERRORED claim.evss_response = [] # induce a 422 response allow(ClaimsApi::AutoEstablishedClaim).to receive(:find_by).and_return(claim) diff --git a/modules/claims_api/spec/requests/v2/veterans/claims_spec.rb b/modules/claims_api/spec/requests/v2/veterans/claims_spec.rb index 05193c6e0bc..29849771a04 100644 --- a/modules/claims_api/spec/requests/v2/veterans/claims_spec.rb +++ b/modules/claims_api/spec/requests/v2/veterans/claims_spec.rb @@ -1311,7 +1311,7 @@ let(:claim) do create( :auto_established_claim_with_supporting_documents, - :status_errored, + :errored, source: 'abraham lincoln', veteran_icn: veteran_id, evss_response: [ diff --git a/modules/claims_api/spec/serializers/claim_detail_serializer_spec.rb b/modules/claims_api/spec/serializers/claim_detail_serializer_spec.rb index 22073f4aa63..e656149a294 100644 --- a/modules/claims_api/spec/serializers/claim_detail_serializer_spec.rb +++ b/modules/claims_api/spec/serializers/claim_detail_serializer_spec.rb @@ -5,7 +5,7 @@ describe ClaimsApi::ClaimDetailSerializer, type: :serializer do subject { serialize(claim, serializer_class: described_class) } - let(:claim) { create(:auto_established_claim_with_supporting_documents, :status_established) } + let(:claim) { create(:auto_established_claim_with_supporting_documents, :established) } let(:uuid) { '90770019-ae82-4e5a-b961-4272256ff080' } let(:rendered_documents) do [ diff --git a/modules/claims_api/spec/services/disability_compensation/pdf_generation_service_spec.rb b/modules/claims_api/spec/services/disability_compensation/pdf_generation_service_spec.rb index ec030715681..02f634a1709 100644 --- a/modules/claims_api/spec/services/disability_compensation/pdf_generation_service_spec.rb +++ b/modules/claims_api/spec/services/disability_compensation/pdf_generation_service_spec.rb @@ -23,7 +23,7 @@ temp['data']['attributes'] end let(:claim) do - claim = create(:auto_established_claim, form_data:) + claim = create(:auto_established_claim, :pending, form_data:) claim.auth_headers = auth_headers claim.transaction_id = '00000000-0000-0000-000000000000' claim.save diff --git a/modules/claims_api/spec/services/failed_submissions_messenger_spec.rb b/modules/claims_api/spec/services/failed_submissions_messenger_spec.rb index 8b40bf9f536..1cb238d0277 100644 --- a/modules/claims_api/spec/services/failed_submissions_messenger_spec.rb +++ b/modules/claims_api/spec/services/failed_submissions_messenger_spec.rb @@ -11,17 +11,33 @@ let(:itf) { ['24252627'] } let(:ews) { %w[32333435 36373839] } let(:from) { '2022-01-01' } - let(:to) { '2022-01-31' } + let(:to) { '2022-01-01' } let(:environment) { 'production' } + let(:link_text) do + " \n \n" + end + describe '#build_notification_message' do - it 'builds the notification message correctly' do + it 'builds the notification message correctly', run_at: '2022-01-01T18:48:27Z' do message = subject.send(:build_notification_message) - expected_message = "*ERRORED SUBMISSIONS* \n\n2022-01-01 - 2022-01-31 " \ + expected_message = "*ERRORED SUBMISSIONS* \n\n2022-01-01 - 2022-01-01 " \ "\nThe following submissions have encountered errors in *#{environment}*. \n\n*Disability " \ "Compensation Errors* \nTotal: 2 \n\n```123456 \n789101112 \n``` \n\n*Va Gov Disability " \ - "Compensation Errors* \nTotal: 2 \n\n```64738 \n378249 \n``` \n\n*Power of " \ + "Compensation Errors* \nTotal: 2 \n\n``` \n \n``` \n\n*Power of " \ "Attorney Errors* \nTotal: 2 \n\n```1314151617 \n181920212223 \n``` \n\n*Intent to " \ "File Errors* \nTotal: 1 \n\n*Evidence Waiver Errors* \nTotal: 2 " \ "\n\n```32333435 \n36373839 \n``` \n\n" @@ -29,7 +45,7 @@ expect(message).to include("#{claims.count} \n") expect(message).to include("123456 \n789101112 \n") expect(message).to include("#{va_gov_claims.count} \n") - expect(message).to include("64738 \n378249 \n") + expect(message).to include(link_text) expect(message).to include("#{poa.count} \n") expect(message).to include("1314151617 \n181920212223 \n") expect(message).to include("#{itf.count} \n") diff --git a/modules/claims_api/spec/shared_reporting_helper.rb b/modules/claims_api/spec/shared_reporting_helper.rb index bea8f821d04..a33d190ffc6 100644 --- a/modules/claims_api/spec/shared_reporting_helper.rb +++ b/modules/claims_api/spec/shared_reporting_helper.rb @@ -4,28 +4,28 @@ let(:upload_claims) do upload_claims = [] upload_claims.push(FactoryBot.create(:auto_established_claim, - :status_errored, + :errored, cid: '0oa9uf05lgXYk6ZXn297', evss_response: nil)) upload_claims.push(FactoryBot.create(:auto_established_claim, - :status_errored, + :errored, cid: '0oa9uf05lgXYk6ZXn297', evss_response: 'random string')) evss_response_array = [{ 'key' => 'key-here', 'severity' => 'FATAL', 'text' => 'message-here' }] upload_claims.push(FactoryBot.create(:auto_established_claim, - :status_errored, + :errored, cid: '0oa9uf05lgXYk6ZXn297', evss_response: evss_response_array)) upload_claims.push(FactoryBot.create(:auto_established_claim, - :status_errored, + :errored, cid: '0oa9uf05lgXYk6ZXn297', evss_response: evss_response_array.to_json)) - upload_claims.push(FactoryBot.create(:auto_established_claim_without_flashes_or_special_issues, - :status_errored, + upload_claims.push(FactoryBot.create(:auto_established_claim, + :errored, cid: '0oa9uf05lgXYk6ZXn297', evss_response: evss_response_array.to_json)) - upload_claims.push(FactoryBot.create(:auto_established_claim_without_flashes_or_special_issues, - :status_errored, + upload_claims.push(FactoryBot.create(:auto_established_claim, + :errored, cid: '0oa9uf05lgXYk6ZXn297', evss_response: evss_response_array.to_json)) end diff --git a/modules/claims_api/spec/sidekiq/claim_uploader_spec.rb b/modules/claims_api/spec/sidekiq/claim_uploader_spec.rb index 0c2b94d2ef9..fd53f0fc656 100644 --- a/modules/claims_api/spec/sidekiq/claim_uploader_spec.rb +++ b/modules/claims_api/spec/sidekiq/claim_uploader_spec.rb @@ -7,6 +7,7 @@ before do Sidekiq::Job.clear_all + allow(Flipper).to receive(:enabled?).with(:claims_api_bd_refactor).and_return false allow(Flipper).to receive(:enabled?).with(:claims_claim_uploader_use_bd).and_return false allow(Flipper).to receive(:enabled?).with(:claims_load_testing).and_return false end @@ -17,7 +18,7 @@ end let(:supporting_document) do - claim = create(:auto_established_claim_with_supporting_documents, :status_established) + claim = create(:auto_established_claim_with_supporting_documents, :established) supporting_document = claim.supporting_documents[0] supporting_document.set_file_data!( Rack::Test::UploadedFile.new( diff --git a/modules/claims_api/spec/sidekiq/flash_updater_spec.rb b/modules/claims_api/spec/sidekiq/flash_updater_spec.rb index 22d9a55aa48..c7c05fbde83 100644 --- a/modules/claims_api/spec/sidekiq/flash_updater_spec.rb +++ b/modules/claims_api/spec/sidekiq/flash_updater_spec.rb @@ -16,7 +16,7 @@ } end let(:flashes) { %w[Hardship Homeless] } - let(:claim) { create(:auto_established_claim_with_auth_headers) } + let(:claim) { create(:auto_established_claim, :with_full_headers) } let(:assigned_flashes) do { flashes: flashes.map do |flash| { assigned_indicator: claim.auth_headers['va_eauth_pnid'], flash_name: "#{flash} ", diff --git a/modules/claims_api/spec/sidekiq/report_monthly_submissions_spec.rb b/modules/claims_api/spec/sidekiq/report_monthly_submissions_spec.rb index d6853693419..d157aaa83e4 100644 --- a/modules/claims_api/spec/sidekiq/report_monthly_submissions_spec.rb +++ b/modules/claims_api/spec/sidekiq/report_monthly_submissions_spec.rb @@ -49,7 +49,7 @@ end def setup_one_claim_one_pact_claim - claim = create(:auto_established_claim, :status_established, cid: '0oa9uf05lgXYk6ZXn297') + claim = create(:auto_established_claim, :established, cid: '0oa9uf05lgXYk6ZXn297') ClaimsApi::ClaimSubmission.create claim:, claim_type: 'PACT', consumer_label: 'Consumer name here' end @@ -64,7 +64,7 @@ def setup_one_claim_one_pact_claim end def setup_one_claim_no_pact_claims - create(:auto_established_claim, :status_established, cid: '0oa9uf05lgXYk6ZXn297') + create(:auto_established_claim, :established, cid: '0oa9uf05lgXYk6ZXn297') end it_behaves_like 'sends mail with expected totals' @@ -79,8 +79,8 @@ def setup_one_claim_no_pact_claims end def setup_two_claims_one_pact_claim - claim = create(:auto_established_claim, :status_established, cid: '0oa9uf05lgXYk6ZXn297') - create(:auto_established_claim, :status_errored, cid: '0oagdm49ygCSJTp8X297') + claim = create(:auto_established_claim, :established, cid: '0oa9uf05lgXYk6ZXn297') + create(:auto_established_claim, :errored, cid: '0oagdm49ygCSJTp8X297') ClaimsApi::ClaimSubmission.create claim:, claim_type: 'PACT', consumer_label: 'Consumer name here' end @@ -96,9 +96,9 @@ def setup_two_claims_one_pact_claim def setup_one_consumer_multiple_claims cid = '0oa9uf05lgXYk6ZXn297' - create(:auto_established_claim, :status_established, cid:) - create(:auto_established_claim, :status_established, cid:) - create(:auto_established_claim, :status_errored, cid:) + create(:auto_established_claim, :established, cid:) + create(:auto_established_claim, :established, cid:) + create(:auto_established_claim, :errored, cid:) end it_behaves_like 'sends mail with expected totals' diff --git a/modules/claims_api/spec/sidekiq/report_unsuccessful_submissions_spec.rb b/modules/claims_api/spec/sidekiq/report_unsuccessful_submissions_spec.rb index ab0b5c6e643..3827425abbc 100644 --- a/modules/claims_api/spec/sidekiq/report_unsuccessful_submissions_spec.rb +++ b/modules/claims_api/spec/sidekiq/report_unsuccessful_submissions_spec.rb @@ -28,10 +28,7 @@ from, to, consumer_claims_totals: [], - unsuccessful_claims_submissions: ClaimsApi::AutoEstablishedClaim.where( - 'status = ? AND created_at BETWEEN ? AND ? AND cid <> ?', - 'errored', @from, @to, '0oagdm49ygCSJTp8X297' - ).order(:cid, :status).pluck(:cid, :status, :id), + unsuccessful_claims_submissions: [], unsuccessful_va_gov_claims_submissions: nil, poa_totals: [], unsuccessful_poa_submissions: [], diff --git a/modules/claims_api/spec/sidekiq/shared_reporting_examples_spec.rb b/modules/claims_api/spec/sidekiq/shared_reporting_examples_spec.rb index 0503ea10c1a..61712fdad73 100644 --- a/modules/claims_api/spec/sidekiq/shared_reporting_examples_spec.rb +++ b/modules/claims_api/spec/sidekiq/shared_reporting_examples_spec.rb @@ -13,8 +13,7 @@ unsuccessful_poa_submissions = job.unsuccessful_poa_submissions expect(poa_totals[0]['VA TurboClaim'][:totals]).to eq(6) - # TODO: address in API-40862-dynamic-email-report-preview - # expect(unsuccessful_poa_submissions.count).to eq(2) + expect(unsuccessful_poa_submissions[1][:created_at]).to be > 1.day.ago expect(unsuccessful_poa_submissions[0][:cid]).to eq('0oa9uf05lgXYk6ZXn297') end end @@ -31,8 +30,7 @@ unsuccessful_evidence_waiver_submissions = job.unsuccessful_evidence_waiver_submissions expect(ews_totals[0]['VA TurboClaim'][:totals]).to eq(6) - # TODO: address in API-40862-dynamic-email-report-preview - # expect(unsuccessful_evidence_waiver_submissions.count).to eq(2) + expect(unsuccessful_evidence_waiver_submissions[1][:created_at]).to be > 1.day.ago expect(unsuccessful_evidence_waiver_submissions[0][:cid]).to eq('0oa9uf05lgXYk6ZXn297') end end @@ -40,11 +38,11 @@ it 'includes ITF metrics' do with_settings(Settings.claims_api, report_enabled: true) do - ClaimsApi::IntentToFile.create!(status: ClaimsApi::IntentToFile::SUBMITTED, cid: '0oa9uf05lgXYk6ZXn297') - ClaimsApi::IntentToFile.create!(status: ClaimsApi::IntentToFile::ERRORED, cid: '0oa9uf05lgXYk6ZXn297') + FactoryBot.create(:intent_to_file, status: 'submitted', cid: '0oa9uf05lgXYk6ZXn297') + FactoryBot.create(:intent_to_file, :itf_errored, cid: '0oa9uf05lgXYk6ZXn297') - ClaimsApi::IntentToFile.create!(status: ClaimsApi::IntentToFile::SUBMITTED, cid: '0oadnb0o063rsPupH297') - ClaimsApi::IntentToFile.create!(status: ClaimsApi::IntentToFile::ERRORED, cid: '0oadnb0o063rsPupH297') + FactoryBot.create(:intent_to_file, status: 'submitted', cid: '0oadnb0o063rsPupH297') + FactoryBot.create(:intent_to_file, :itf_errored, cid: '0oadnb0o063rsPupH297') job = described_class.new job.perform @@ -60,12 +58,12 @@ end end - it 'includes 526EZ claims from VaGov' do + it 'includes 526EZ claims from VaGov', skip: 'pending changes in API-41029' do with_settings(Settings.claims_api, report_enabled: true) do - create(:auto_established_claim_va_gov, created_at: Time.zone.now).freeze - create(:auto_established_claim_va_gov, created_at: Time.zone.now).freeze - create(:auto_established_claim_va_gov, :set_transaction_id, created_at: Time.zone.now).freeze - create(:auto_established_claim_va_gov, :set_transaction_id, created_at: Time.zone.now).freeze + FactoryBot.create(:auto_established_claim_va_gov, :errored) + FactoryBot.create(:auto_established_claim_va_gov, :errored) + FactoryBot.create(:auto_established_claim_va_gov, :errored) + FactoryBot.create(:auto_established_claim_va_gov, :errored) job = described_class.new job.perform @@ -73,7 +71,6 @@ expect(va_gov_groups).to include('A') expect(va_gov_groups).to include('B') - expect(va_gov_groups).to include('C') expect(va_gov_groups['A'][0][:transaction_id]).to be_a(String) expect(va_gov_groups['A'][0][:id]).to be_a(String) end diff --git a/modules/claims_api/spec/sidekiq/special_issue_updater_spec.rb b/modules/claims_api/spec/sidekiq/special_issue_updater_spec.rb index ad9046e45f6..c804abf190b 100644 --- a/modules/claims_api/spec/sidekiq/special_issue_updater_spec.rb +++ b/modules/claims_api/spec/sidekiq/special_issue_updater_spec.rb @@ -16,7 +16,7 @@ } end let(:contention_id) { { claim_id: '123', code: '200', name: 'contention-name-here' } } - let(:claim_record) { create(:auto_established_claim) } + let(:claim_record) { create(:auto_established_claim, :special_issues) } let(:special_issues) { claim_record.special_issues } it 'submits successfully' do diff --git a/modules/claims_api/spec/sidekiq/v2/disability_compensation_benefits_documents_uploader_spec.rb b/modules/claims_api/spec/sidekiq/v2/disability_compensation_benefits_documents_uploader_spec.rb index 75a2cce285f..e07c5a73cb5 100644 --- a/modules/claims_api/spec/sidekiq/v2/disability_compensation_benefits_documents_uploader_spec.rb +++ b/modules/claims_api/spec/sidekiq/v2/disability_compensation_benefits_documents_uploader_spec.rb @@ -11,6 +11,7 @@ Sidekiq::Job.clear_all stub_claims_api_auth_token allow(Flipper).to receive(:enabled?).with(:claims_load_testing).and_return false + allow(Flipper).to receive(:enabled?).with(:claims_api_bd_refactor).and_return true end let(:user) { FactoryBot.create(:user, :loa3) } @@ -68,7 +69,7 @@ end it 'submits successfully with BD' do - expect_any_instance_of(ClaimsApi::BD).to receive(:upload).and_return true + expect_any_instance_of(ClaimsApi::BD).to receive(:upload_document).and_return true service.perform(claim.id) diff --git a/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb b/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb index 221f1251aa8..4d2cb21b0cd 100644 --- a/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb +++ b/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb @@ -68,6 +68,11 @@ } } ) + .deep_merge( + { + 'appointmentDate' => power_of_attorney.created_at + } + ) final_data = data.deep_merge( { 'text_signatures' => { @@ -190,6 +195,11 @@ } } ) + .deep_merge( + { + 'appointmentDate' => power_of_attorney.created_at + } + ) final_data = data.deep_merge( { 'text_signatures' => { @@ -273,6 +283,11 @@ } } ) + .deep_merge( + { + 'appointmentDate' => power_of_attorney.created_at + } + ) final_data = data.deep_merge( { 'text_signatures' => { @@ -393,6 +408,11 @@ } } ) + .deep_merge( + { + 'appointmentDate' => power_of_attorney.created_at + } + ) final_data = data.deep_merge( { 'text_signatures' => { diff --git a/modules/debts_api/app/workers/debts_api/v0/form5655/vha/sharepoint_submission_job.rb b/modules/debts_api/app/sidekiq/debts_api/v0/form5655/vha/sharepoint_submission_job.rb similarity index 100% rename from modules/debts_api/app/workers/debts_api/v0/form5655/vha/sharepoint_submission_job.rb rename to modules/debts_api/app/sidekiq/debts_api/v0/form5655/vha/sharepoint_submission_job.rb diff --git a/modules/debts_api/app/workers/debts_api/v0/form5655/vha/vbs_submission_job.rb b/modules/debts_api/app/sidekiq/debts_api/v0/form5655/vha/vbs_submission_job.rb similarity index 100% rename from modules/debts_api/app/workers/debts_api/v0/form5655/vha/vbs_submission_job.rb rename to modules/debts_api/app/sidekiq/debts_api/v0/form5655/vha/vbs_submission_job.rb diff --git a/modules/debts_api/spec/workers/debt_api/v0/vha/sharepoint_submission_job_spec.rb b/modules/debts_api/spec/sidekiq/debt_api/v0/vha/sharepoint_submission_job_spec.rb similarity index 100% rename from modules/debts_api/spec/workers/debt_api/v0/vha/sharepoint_submission_job_spec.rb rename to modules/debts_api/spec/sidekiq/debt_api/v0/vha/sharepoint_submission_job_spec.rb diff --git a/modules/debts_api/spec/workers/debt_api/v0/vha/vbs_submission_job_spec.rb b/modules/debts_api/spec/sidekiq/debt_api/v0/vha/vbs_submission_job_spec.rb similarity index 100% rename from modules/debts_api/spec/workers/debt_api/v0/vha/vbs_submission_job_spec.rb rename to modules/debts_api/spec/sidekiq/debt_api/v0/vha/vbs_submission_job_spec.rb diff --git a/modules/meb_api/app/controllers/meb_api/v0/forms_controller.rb b/modules/meb_api/app/controllers/meb_api/v0/forms_controller.rb index 043fd97b774..94e605a0063 100644 --- a/modules/meb_api/app/controllers/meb_api/v0/forms_controller.rb +++ b/modules/meb_api/app/controllers/meb_api/v0/forms_controller.rb @@ -65,7 +65,7 @@ def submit_claim end end - response = submission_service.submit_claim(params, response_data, 'toe') + response = submission_service.submit_claim(params, response_data) clear_saved_form(params[:form_id]) if params[:form_id] diff --git a/modules/meb_api/lib/dgi/forms/service/submission_service.rb b/modules/meb_api/lib/dgi/forms/service/submission_service.rb index 23818368823..f44c1dc2ff4 100644 --- a/modules/meb_api/lib/dgi/forms/service/submission_service.rb +++ b/modules/meb_api/lib/dgi/forms/service/submission_service.rb @@ -14,7 +14,8 @@ class Service < MebApi::DGI::Service configuration MebApi::DGI::Submission::Configuration STATSD_KEY_PREFIX = 'api.dgi.submission' - def submit_claim(params, response_data, form_type = 'toe') + def submit_claim(params, response_data) + form_type = params.key?('@type') ? params['@type'] : 'ToeSubmission' unmasked_params = update_dd_params(params, response_data) with_monitoring do headers = request_headers @@ -28,7 +29,11 @@ def submit_claim(params, response_data, form_type = 'toe') private def end_point(form_type) - "claimType/#{form_type}/claimsubmission".dup + if form_type == 'ToeSubmission' + 'claimType/toe/claimsubmission'.dup + else + "claimType/#{form_type.capitalize}/claimsubmission".dup + end end def request_headers @@ -48,7 +53,7 @@ def format_params(params) end def update_dd_params(params, dd_params) - check_masking = params.dig(:form, :direct_deposit, :direct_deposit_account_number).include?('*') + check_masking = params.dig(:form, :direct_deposit, :direct_deposit_account_number)&.include?('*') if check_masking && !Flipper.enabled?(:toe_light_house_dgi_direct_deposit, @current_user) params[:form][:direct_deposit][:direct_deposit_account_number] = dd_params[:dposit_acnt_nbr]&.dup params[:form][:direct_deposit][:direct_deposit_routing_number] = dd_params[:routng_trnsit_nbr]&.dup diff --git a/modules/meb_api/lib/dgi/submission/service.rb b/modules/meb_api/lib/dgi/submission/service.rb index a171e3fa610..e2a227f90b8 100644 --- a/modules/meb_api/lib/dgi/submission/service.rb +++ b/modules/meb_api/lib/dgi/submission/service.rb @@ -28,7 +28,7 @@ def submit_claim(params, response_data = nil) def end_point(form_type) if form_type - "claimType/#{form_type}/claimsubmission" + "claimType/#{form_type.capitalize}/claimsubmission" else 'claimType/Chapter33/claimsubmission' end diff --git a/modules/meb_api/spec/dgi/forms/service/toe_submission_service_spec.rb b/modules/meb_api/spec/dgi/forms/service/toe_submission_service_spec.rb index bd07082f310..e819846665c 100644 --- a/modules/meb_api/spec/dgi/forms/service/toe_submission_service_spec.rb +++ b/modules/meb_api/spec/dgi/forms/service/toe_submission_service_spec.rb @@ -108,8 +108,23 @@ it 'Lighthouse returns a status of 200' do VCR.use_cassette('dgi/forms/submit_toe_claim') do response = service.submit_claim(ActionController::Parameters.new(claimant_params), - ActionController::Parameters.new(dd_params_lighthouse), - 'toe') + ActionController::Parameters.new(dd_params_lighthouse)) + + expect(response.status).to eq(200) + end + end + end + + context 'Feature CH35 toe_light_house_dgi_direct_deposit=true' do + before do + Flipper.enable(:toe_light_house_dgi_direct_deposit) + claimant_params[:form]['@type'] = 'Chapter35' + end + + it 'Lighthouse returns a status of 200' do + VCR.use_cassette('dgi/forms/submit_toe_claim') do + response = service.submit_claim(ActionController::Parameters.new(claimant_params), + ActionController::Parameters.new(dd_params_lighthouse)) expect(response.status).to eq(200) end @@ -124,8 +139,7 @@ it 'EVSS returns a status of 200' do VCR.use_cassette('dgi/forms/submit_toe_claim') do response = service.submit_claim(ActionController::Parameters.new(claimant_params), - ActionController::Parameters.new(dd_params), - 'toe') + ActionController::Parameters.new(dd_params)) expect(response.status).to eq(200) end diff --git a/modules/mobile/app/controllers/mobile/v0/efolder_controller.rb b/modules/mobile/app/controllers/mobile/v0/efolder_controller.rb new file mode 100644 index 00000000000..f8c4f9ee3ff --- /dev/null +++ b/modules/mobile/app/controllers/mobile/v0/efolder_controller.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Mobile + module V0 + class EfolderController < ApplicationController + def index + response = service.list_documents + documents = efolder_adapter.parse(response) + render json: Mobile::V0::EfolderSerializer.new(documents) + end + + private + + def service + ::Efolder::Service.new(@current_user) + end + + def efolder_adapter + Mobile::V0::Adapters::Efolder + end + end + end +end diff --git a/modules/mobile/app/controllers/mobile/v0/translations_controller.rb b/modules/mobile/app/controllers/mobile/v0/translations_controller.rb new file mode 100644 index 00000000000..c9852048ba7 --- /dev/null +++ b/modules/mobile/app/controllers/mobile/v0/translations_controller.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Mobile + module V0 + class TranslationsController < ApplicationController + skip_before_action :authenticate + + def download + if needs_translations? + response.headers['Content-Version'] = file_md5 + send_file( + file, + type: 'application/json', + filename: 'common.json', + disposition: 'attachment' + ) + else + head :no_content + end + end + + private + + def file + Rails.root.join('modules', 'mobile', 'app', 'assets', 'translations', 'en', 'common.json') + end + + def file_md5 + @file_md5 ||= Digest::MD5.file(file).hexdigest + end + + def needs_translations? + params[:current_version] != file_md5 + end + end + end +end diff --git a/modules/mobile/app/models/mobile/v0/adapters/efolder.rb b/modules/mobile/app/models/mobile/v0/adapters/efolder.rb new file mode 100644 index 00000000000..9ab43e943df --- /dev/null +++ b/modules/mobile/app/models/mobile/v0/adapters/efolder.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Mobile + module V0 + module Adapters + class Efolder + def self.parse(documents) + documents.map do |document| + Mobile::V0::Efolder.new( + id: document['document_id'], + doc_type: document['doc_type'], + type_description: document['type_description'], + received_at: document['received_at'] + ) + end + end + end + end + end +end diff --git a/modules/mobile/app/models/mobile/v0/efolder.rb b/modules/mobile/app/models/mobile/v0/efolder.rb new file mode 100644 index 00000000000..099c705be4f --- /dev/null +++ b/modules/mobile/app/models/mobile/v0/efolder.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'common/models/resource' + +module Mobile + module V0 + class Efolder < Common::Resource + attribute :id, Types::String + attribute :doc_type, Types::String + attribute :type_description, Types::String + attribute :received_at, Types::Date + end + end +end diff --git a/modules/mobile/app/serializers/mobile/v0/efolder_serializer.rb b/modules/mobile/app/serializers/mobile/v0/efolder_serializer.rb new file mode 100644 index 00000000000..bd447ca9463 --- /dev/null +++ b/modules/mobile/app/serializers/mobile/v0/efolder_serializer.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Mobile + module V0 + class EfolderSerializer + include JSONAPI::Serializer + + set_type :efolder_document + attributes :doc_type, + :type_description, + :received_at + end + end +end diff --git a/modules/mobile/config/routes.rb b/modules/mobile/config/routes.rb index 902c8ac7b6d..508b58bf15b 100644 --- a/modules/mobile/config/routes.rb +++ b/modules/mobile/config/routes.rb @@ -38,6 +38,7 @@ get '/dependents/request-decisions', to: 'dependents_request_decisions#index' get '/disability-rating', to: 'disability_rating#index' get '/enrollment-status', to: 'enrollment_status#show' + get '/efolder/documents', to: 'efolder#index' get '/facilities-info', to: 'facilities_info#index' get '/facilities-info/:sort', to: 'facilities_info#schedulable' post '/financial-status-reports/download', to: 'financial_status_reports#download' @@ -81,6 +82,7 @@ get '/push/prefs/:endpoint_sid', to: 'push_notifications#get_prefs' put '/push/prefs/:endpoint_sid', to: 'push_notifications#set_pref' post '/push/send', to: 'push_notifications#send_notification' + get '/translations/download', to: 'translations#download' get '/user', to: 'users#show' get '/user/authorized-services', to: 'authorized_services#index' get '/user/contact-info', to: 'contact_info#show' diff --git a/modules/mobile/docs/index.html b/modules/mobile/docs/index.html index c296fb2ac52..94d78cfc9b1 100755 --- a/modules/mobile/docs/index.html +++ b/modules/mobile/docs/index.html @@ -2222,7 +2222,7 @@ -
502

An upstream service the API depends on returned an error.

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/enrollment-status

Returns the user's VA enrollment status.

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/efolder/documents

Returns the user's list of documents in efolder

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/facilities-info

Retrieves facilities info for a user's va treatment facilities

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/enrollment-status

Returns the user's VA enrollment status.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/facilities-info/{sort_method}

Retrieves facilities info for all facilities a given user has the ability to schedule appointments at

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/facilities-info

Retrieves facilities info for a user's va treatment facilities

+
Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

+

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/facilities-info/{sort_method}

Retrieves facilities info for all facilities a given user has the ability to schedule appointments at

Authorizations:
Bearer
path Parameters
sort_method
required
string
Enum: "current" "home" "alphabetical" "appointments"

Sort method (Closest to home or current location, alphabetical, or by most recent appointment location) Note - When most recent appointment is selected any facility that doesn't appear in the user's appointments will be sorted alphabetically after those that do appear in the appointments list

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

Lat Long for user's current location. Only required if sort method is current, but can be supplied anyway

@@ -2748,7 +2760,7 @@

Request samples

Content type
application/json
{
  • "lat": 34.5968,
  • "long": 10.5796
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/financial-status-reports/download

Returns financial status report PDF

+

Request samples

Content type
application/json
{
  • "lat": 34.5968,
  • "long": 10.5796
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/financial-status-reports/download

Returns financial status report PDF

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/health/immunizations

Returns the list of immunization records for given user

+

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/health/immunizations

Returns the list of immunization records for given user

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": [
    ]
}

/v0/health/allergy-intolerances

Retrieves a list of the user's known allergies related to medication, food, or other substances

+

Response samples

Content type
application/json
{
  • "data": [
    ]
}

/v0/health/allergy-intolerances

Retrieves a list of the user's known allergies related to medication, food, or other substances

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{}

/v0/health/labs-and-tests

List patient labs and tests. Each report contains a list of which tests were a part of the report, along with links to get the results for those tests.

+

Response samples

Content type
application/json
{}

/v0/health/labs-and-tests

List patient labs and tests. Each report contains a list of which tests were a part of the report, along with links to get the results for those tests.

query Parameters
category
string

The category classifies the clinical discipline, department, or diagnostic service that created the report

code
string

A code that indicates the type of information contained within the diagnostic report. Supported values are from the LOINC diagnostic report codes.

date
datetime

A date or range of dates (maximum of 2) that describe the date that the diagnostic report was recorded. Supported formats are: YYYY, YYYY-MM, YYYY-MM-DD, YYYY-MM-DD'T'HH:MM:SSZ

@@ -2806,7 +2818,7 @@

Response samples

Content type
application/json
{}

/v0/health/observations/{id}

Gets an observation from a user's diagnostic report

+

Response samples

Content type
application/json
{}

/v0/health/observations/{id}

Gets an observation from a user's diagnostic report

path Parameters
id
required
string

id of observation

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{}

/v0/health/locations/{id}

Returns location info based on location id from vaccine record

+

Response samples

Content type
application/json
{}

/v0/health/locations/{id}

Returns location info based on location id from vaccine record

Authorizations:
Bearer
path Parameters
id
required
string

location id from immunization info

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/health/rx/prescriptions

Returns the users prescriptions.

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/health/rx/prescriptions

Returns the users prescriptions.

Authorizations:
Bearer
query Parameters
sort
string

what field to sort array of prescriptions by. fields that can be sorted: prescription_id, refill_status, refill_submit_date, refill_date, facility_name, ordered_date, prescription_name, dispensed_date. date fields sort by DESC by default while all others default to ASC. To get the opposite sort direction negate the field with a '-'. EX: -prescription_id

filter
string

filter by field values. Syntax: ?filter[refill_status][eq]=refillinprocess. fields that can be filtered: prescription_id, refill_status, refill_submit_date, facility_name. eq can be switched out with not_eq. to filter by multiple values of the same field, deliminate the parameter value with commas. Syntax: ?filter[refill_status][eq]=refillinprocess,active

page[number]
integer
Example: page[number]=1

The page number requested. Defaults to 1.

@@ -2849,7 +2861,7 @@

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v0/health/rx/prescriptions/refill

Requests refill for prescriptions.

+

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v0/health/rx/prescriptions/refill

Requests refill for prescriptions.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

array of prescription ids to request refill

ids
required
Array of arrays

Responses

Request samples

Content type
application/json
{
  • "ids": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "6260ab13-177f-583d-b2dc-1b350404abb7",
  • "type": "PrescriptionRefills",
  • "attributes": {
    }
}

/v0/health/rx/prescriptions/{id}/tracking

Requests list of tracking data for a prescription id

+

Request samples

Content type
application/json
{
  • "ids": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "6260ab13-177f-583d-b2dc-1b350404abb7",
  • "type": "PrescriptionRefills",
  • "attributes": {
    }
}

/v0/health/rx/prescriptions/{id}/tracking

Requests list of tracking data for a prescription id

Authorizations:
Bearer
path Parameters
id
required
object
Example: 13650545

id of the prescription tracking data is being requested for

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": [
    ]
}

/v0/letters

Returns the list of letter names and types for the given user

+

Response samples

Content type
application/json
{
  • "data": [
    ]
}

/v0/letters

Returns the list of letter names and types for the given user

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/letters/beneficiary

Returns benefit info and options for the given user with or without a dependent

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/letters/beneficiary

Returns benefit info and options for the given user with or without a dependent

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/letters/{type}/download

Returns requested letter for download. Downloads as either PDF or JSON, dependent upon format param. Defaults to PDF when format is not specified.

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/letters/{type}/download

Returns requested letter for download. Downloads as either PDF or JSON, dependent upon format param. Defaults to PDF when format is not specified.

Authorizations:
Bearer
path Parameters
type
required
string
Enum: "benefit_summary" "benefit_summary_dependent" "benefit_verification" "certificate_of_eligibility" "civil_service" "commissary" "medicare_partd" "minimum_essential_coverage" "proof_of_service" "service_verification"

letter type

query Parameters
format
string
Enum: "pdf" "json"

format

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

@@ -2924,7 +2936,7 @@

Request samples

Content type
application/json
{
  • "militaryService": true,
  • "serviceConnectedDisabilities": true,
  • "serviceConnectedEvaluation": true,
  • "nonServiceConnectedPension": true,
  • "monthlyAward": true,
  • "unemployable": true,
  • "specialMonthlyCompensation": true,
  • "adaptedHousing": true,
  • "chapter35Eligibility": true,
  • "deathResultOfDisability": true,
  • "survivorsAward": true
}

Response samples

Content type
No sample

/v0/maintenance_windows

List maintenance windows

+

Request samples

Content type
application/json
{
  • "militaryService": true,
  • "serviceConnectedDisabilities": true,
  • "serviceConnectedEvaluation": true,
  • "nonServiceConnectedPension": true,
  • "monthlyAward": true,
  • "unemployable": true,
  • "specialMonthlyCompensation": true,
  • "adaptedHousing": true,
  • "chapter35Eligibility": true,
  • "deathResultOfDisability": true,
  • "survivorsAward": true
}

Response samples

Content type
No sample

/v0/maintenance_windows

List maintenance windows

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": [
    ]
}

/v0/messaging/health/folders

List available secure messaging folders

+

Response samples

Content type
application/json
{
  • "data": [
    ]
}

/v0/messaging/health/folders

List available secure messaging folders

Authorizations:
Bearer
query Parameters
page
integer
Example: page=1

The page number requested

perPage
integer
Example: perPage=10

The number of records to return per page. Defaults to 100

useCache
boolean
Example: useCache=true

Whether or not to use this API's cache or fetch records from the upstream service. Defaults to true.

@@ -2949,7 +2961,7 @@

Response samples

Content type
application/json
{
  • "data": [],
  • "meta": {
    }
}

/v0/messaging/health/folder

Create a new secure messaging folder

+

Response samples

Content type
application/json
{
  • "data": [],
  • "meta": {
    }
}

/v0/messaging/health/folder

Create a new secure messaging folder

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json
required
object

Responses

Request samples

Content type
application/json
{
  • "folder": {
    }
}

Response samples

Content type
application/json
{}

/v0/messaging/health/folders/{id}

Get a secure messaging folder

+

Request samples

Content type
application/json
{
  • "folder": {
    }
}

Response samples

Content type
application/json
{}

/v0/messaging/health/folders/{id}

Get a secure messaging folder

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{}

/v0/messaging/health/folders/{id}/messages

List messages in a secure messaging folder.

+

Response samples

Content type
application/json
{}

/v0/messaging/health/folders/{id}/messages

List messages in a secure messaging folder.

When listing messages, the response for each message will include most but not all of the message attributes. Specifically, the message body and attachment information is not included. Those attributes can be obtained by getting the specific message resource.

@@ -2990,7 +3002,7 @@

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v0/messaging/health/folders/{id}/threads

List of threads in a secure messaging folder

+

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v0/messaging/health/folders/{id}/threads

List of threads in a secure messaging folder

Authorizations:
Bearer
path Parameters
folderId
required
string

The id of the folder that threads are being retrieved from

query Parameters
pageSize,
string

The size of the pagination you want. Defaults to 10

page,
string

The page number to get based on your page size

@@ -3007,7 +3019,7 @@

Response samples

Content type
application/json
{
  • "data": [
    ]
}

/v0/messaging/health/message_drafts

Save a new draft message

+

Response samples

Content type
application/json
{
  • "data": [
    ]
}

/v0/messaging/health/message_drafts

Save a new draft message

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json
recipient_id
required
integer

The message recipient. This must be a valid recipient id that is assigned to the user. The list of valid recipients for a user can be obtained from the

/v0/messaging/health/recipients
endpoint.

@@ -3023,7 +3035,7 @@

Request samples

Content type
application/json
{
  • "recipient_id": 1763526,
  • "category": "OTHER",
  • "body": "What is the proper dosage and how long should I take this medication?",
  • "subject": "Question about my medication",
  • "draft_id": 0
}

Response samples

Content type
application/json
{
  • "recipient_id": 1763526,
  • "category": "OTHER",
  • "body": "What is the proper dosage and how long should I take this medication?",
  • "subject": "Question about my medication",
  • "draft_id": 0
}

/v0/messaging/health/message_drafts/{id}

Update an existing draft message

+

Request samples

Content type
application/json
{
  • "recipient_id": 1763526,
  • "category": "OTHER",
  • "body": "What is the proper dosage and how long should I take this medication?",
  • "subject": "Question about my medication",
  • "draft_id": 0
}

Response samples

Content type
application/json
{
  • "recipient_id": 1763526,
  • "category": "OTHER",
  • "body": "What is the proper dosage and how long should I take this medication?",
  • "subject": "Question about my medication",
  • "draft_id": 0
}

/v0/messaging/health/message_drafts/{id}

Update an existing draft message

Authorizations:
Bearer
path Parameters
id
required
string

The id of the draft that is to be updated

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json
object

Responses

Request samples

Content type
application/json
{
  • "body": "the updated message"
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/messaging/health/message_drafts/{reply_id}/replydraft

Save a new draft message as a reply to an existing message

+

Request samples

Content type
application/json
{
  • "body": "the updated message"
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/messaging/health/message_drafts/{reply_id}/replydraft

Save a new draft message as a reply to an existing message

Authorizations:
Bearer
path Parameters
reply_id
required
string

The id of the message that will be replied to

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json
recipient_id
required
integer

The message recipient. This must be a valid recipient id that is assigned to the user. The list of valid @@ -3052,7 +3064,7 @@

Request samples

Content type
application/json
{
  • "recipient_id": 1763526,
  • "category": "OTHER",
  • "body": "What is the proper dosage and how long should I take this medication?",
  • "subject": "Question about my medication",
  • "draft_id": 0
}

Response samples

Content type
application/json
{
  • "recipient_id": 1763526,
  • "category": "OTHER",
  • "body": "What is the proper dosage and how long should I take this medication?",
  • "subject": "Question about my medication",
  • "draft_id": 0
}

/v0/messaging/health/message_drafts/{reply_id}/replydraft/{draft_id}

Edit a draft message that was a reply to an existing message

+

Request samples

Content type
application/json
{
  • "recipient_id": 1763526,
  • "category": "OTHER",
  • "body": "What is the proper dosage and how long should I take this medication?",
  • "subject": "Question about my medication",
  • "draft_id": 0
}

Response samples

Content type
application/json
{
  • "recipient_id": 1763526,
  • "category": "OTHER",
  • "body": "What is the proper dosage and how long should I take this medication?",
  • "subject": "Question about my medication",
  • "draft_id": 0
}

/v0/messaging/health/message_drafts/{reply_id}/replydraft/{draft_id}

Edit a draft message that was a reply to an existing message

Authorizations:
Bearer
path Parameters
reply_id
required
string

The id of the message that will be replied to

draft_id
required
string

The id of the draft that is to be updated

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

@@ -3065,7 +3077,7 @@

Request samples

Content type
application/json
{
  • "body": "the updated message"
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/messaging/health/messages

Send a new secure message

+

Request samples

Content type
application/json
{
  • "body": "the updated message"
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/messaging/health/messages

Send a new secure message

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema:

New message body.

NOTES:

@@ -3098,7 +3110,7 @@

Request samples

Content type
{
  • "recipient_id": 1763526,
  • "category": "OTHER",
  • "body": "What is the proper dosage and how long should I take this medication?",
  • "subject": "Question about my medication",
  • "draft_id": 0
}

Response samples

Content type
application/json
{
  • "type": "messages",
  • "id": "123789",
  • "attributes": {
    },
  • "relationships": {
    },
  • "included": []
}

/v0/messaging/health/messages/categories

List available message categories

+

Request samples

Content type
{
  • "recipient_id": 1763526,
  • "category": "OTHER",
  • "body": "What is the proper dosage and how long should I take this medication?",
  • "subject": "Question about my medication",
  • "draft_id": 0
}

Response samples

Content type
application/json
{
  • "type": "messages",
  • "id": "123789",
  • "attributes": {
    },
  • "relationships": {
    },
  • "included": []
}

/v0/messaging/health/messages/categories

List available message categories

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/messaging/health/messages/signature

Gets user message signature preferences

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/messaging/health/messages/signature

Gets user message signature preferences

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/messaging/health/messages/{id}

Moves a secure message to the "Deleted" folder

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/messaging/health/messages/{id}

Moves a secure message to the "Deleted" folder

Authorizations:
Bearer
path Parameters
id
required
string

The id of the message that is to be deleted

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/messaging/health/messages/{id}

Get a secure message and mark the message as read.

+

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/messaging/health/messages/{id}

Get a secure message and mark the message as read.

NOTES:

  • Unlike listing messages in a folder, the message resource returned from this operation will include @@ -3152,7 +3164,7 @@

Response samples

Content type
application/json
{
  • "type": "messages",
  • "id": "123789",
  • "attributes": {
    },
  • "relationships": {
    },
  • "included": [],
  • "meta": {
    }
}

/v0/messaging/health/messages/{id}/move

Moves a secure message to a specified folder

+

Response samples

Content type
application/json
{
  • "type": "messages",
  • "id": "123789",
  • "attributes": {
    },
  • "relationships": {
    },
  • "included": [],
  • "meta": {
    }
}

/v0/messaging/health/messages/{id}/move

Moves a secure message to a specified folder

Authorizations:
Bearer
path Parameters
id
required
string

The id of the message that is to be moved

query Parameters
folder_id,
required
string

The id of the folder that the message is to be moved to

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

@@ -3165,7 +3177,7 @@

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/messaging/health/messages/{id}/attachments/{attachment_id}

Get a secure message attachment content as a direct binary download. Secure messaging supports the following file types/extensions: doc, docx, gif, jpg, pdf, png, rtf, txt, xls, xlsx.

+

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/messaging/health/messages/{id}/attachments/{attachment_id}

Get a secure message attachment content as a direct binary download. Secure messaging supports the following file types/extensions: doc, docx, gif, jpg, pdf, png, rtf, txt, xls, xlsx.

Authorizations:
Bearer
path Parameters
id
required
integer

ID of the message that we are retrieving attachments of

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/messaging/health/messages/{id}/reply

Send reply to a secure message

+

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/messaging/health/messages/{id}/reply

Send reply to a secure message

NOTE: If including file attachments, this request must be sent as multipart/form-data

File attachment restrictions (as imposed by MHV):

    @@ -3199,7 +3211,7 @@

Request samples

Content type
{
  • "recipient_id": 1112233,
  • "category": "TEST",
  • "subject": "My Test Results",
  • "body": "Dear provider, please clarify my test results. Thank you.",
  • "draft_id": 0
}

Response samples

Content type
application/json
{
  • "type": "messages",
  • "id": "123789",
  • "attributes": {
    },
  • "relationships": {
    },
  • "included": []
}

/v0/messaging/health/messages/{id}/thread

Gets a list of message summaries that are related to the message of the passed id and older than the message of +

Request samples

Content type
{
  • "recipient_id": 1112233,
  • "category": "TEST",
  • "subject": "My Test Results",
  • "body": "Dear provider, please clarify my test results. Thank you.",
  • "draft_id": 0
}

Response samples

Content type
application/json
{
  • "type": "messages",
  • "id": "123789",
  • "attributes": {
    },
  • "relationships": {
    },
  • "included": []
}

/v0/messaging/health/messages/{id}/thread

Gets a list of message summaries that are related to the message of the passed id and older than the message of the id provided. Does not include the message of the passed id itself.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v1/messaging/health/messages/{id}/thread

Gets a list of message summaries that are related to the message of the passed id regardless of their age in +

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v1/messaging/health/messages/{id}/thread

Gets a list of message summaries that are related to the message of the passed id regardless of their age in relation to the message of the id provided. Unless specified in the query parameters, this does include the message of the passed id itself.

Authorizations:
Bearer
query Parameters
excludeProvidedMessage
boolean

Excludes the message with the provided message id

@@ -3225,7 +3237,7 @@

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v0/messaging/health/recipients

List available recipients to which messages may be sent

+

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v0/messaging/health/recipients

List available recipients to which messages may be sent

Authorizations:
Bearer
query Parameters
useCache
boolean
Example: useCache=true

Whether or not to use this API's cache or fetch records from the upstream service. Defaults to true.

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v0/military-service-history

Returns user's service history

+

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v0/military-service-history

Returns user's service history

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/payment-history

Returns user's payment history

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/payment-history

Returns user's payment history

Authorizations:
Bearer
query Parameters
startDate
string <date-time>
Example: startDate=2020-10-29T07:00:00Z

The start date for the range of payments in ISO 8601 UTC format. Defaults to the beginning of the year of the most recent payment.

endDate
string <date-time>
Example: endDate=2021-11-29T08:00:00Z

The end date for the range of appointments in ISO 8601 UTC format. Defaults to the end of the year of the most recent payment.

page[number]
integer
Example: page[number]=1

The page number requested. Defaults to 1.

@@ -3263,7 +3275,7 @@

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v0/payment-information/benefits

Returns direct deposit payment info

+

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

/v0/payment-information/benefits

Returns direct deposit payment info

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "type": "paymentInformation",
  • "id": "abe3f152-90b0-45cb-8776-4958bad0e0ef",
  • "attributes": {
    }
}

/v0/payment-information/benefits

Returns updated direct deposit payment info

+

Response samples

Content type
application/json
{
  • "type": "paymentInformation",
  • "id": "abe3f152-90b0-45cb-8776-4958bad0e0ef",
  • "attributes": {
    }
}

/v0/payment-information/benefits

Returns updated direct deposit payment info

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

New direct deposit info

accountNumber
required
string
accountType
required
string
Enum: "Savings" "Checking"
financialInstitutionName
required
string
financialInstitutionRoutingNumber
required
string

Responses

Request samples

Content type
application/json
{
  • "accountNumber": "12345678901",
  • "accountType": "Savings",
  • "financialInstitutionName": "PACIFIC PREMIER BANK",
  • "financialInstitutionRoutingNumber": "021000021"
}

Response samples

Content type
application/json
{
  • "type": "paymentInformation",
  • "id": "abe3f152-90b0-45cb-8776-4958bad0e0ef",
  • "attributes": {
    }
}

/v0/pensions

Get current pensions overview

+

Request samples

Content type
application/json
{
  • "accountNumber": "12345678901",
  • "accountType": "Savings",
  • "financialInstitutionName": "PACIFIC PREMIER BANK",
  • "financialInstitutionRoutingNumber": "021000021"
}

Response samples

Content type
application/json
{
  • "type": "paymentInformation",
  • "id": "abe3f152-90b0-45cb-8776-4958bad0e0ef",
  • "attributes": {
    }
}

/v0/pensions

Get current pensions overview

Authorizations:
Bearer

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/push/prefs/{endpointSid}

Get the user's push notification preferences

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/push/prefs/{endpointSid}

Get the user's push notification preferences

Authorizations:
Bearer
path Parameters
endpointSid
required
string

device endpointSid provided by the register endpoint

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/push/prefs/{endpointSid}

Set the user's push notification preferences

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/push/prefs/{endpointSid}

Set the user's push notification preferences

Authorizations:
Bearer
path Parameters
endpointSid
required
string

device endpointSid provided by the register endpoint

header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

Push notification preferences

@@ -3326,7 +3338,7 @@

Request samples

Content type
application/json
{
  • "preference": "appointment_reminders",
  • "enabled": true
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/push/register

Allows a new app install to register to receive push notifications

+

Request samples

Content type
application/json
{
  • "preference": "appointment_reminders",
  • "enabled": true
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/push/register

Allows a new app install to register to receive push notifications

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

Device information

deviceToken
required
string
osName
required
string
Enum: "ios" "android"
deviceName
string
appName
required
string
debug
boolean

Flag to switch between sandbox and non-sandbox app sid. Lower envs only

@@ -3340,7 +3352,7 @@

Request samples

Content type
application/json
{
  • "deviceToken": "740f4707bebcf74f9b7c25d48e3358945f6aa01da5ddb387462c7eaf61bb78ad",
  • "osName": "ios",
  • "deviceName": "Galaxy 8",
  • "appName": "va_mobile_app",
  • "debug": true
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/push/send

Allows client to trigger specified push notification to be sent to specified endpoint

+

Request samples

Content type
application/json
{
  • "deviceToken": "740f4707bebcf74f9b7c25d48e3358945f6aa01da5ddb387462c7eaf61bb78ad",
  • "osName": "ios",
  • "deviceName": "Galaxy 8",
  • "appName": "va_mobile_app",
  • "debug": true
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/push/send

Allows client to trigger specified push notification to be sent to specified endpoint

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

Template id, endpoint sid, and personalization for template

appName
required
string
templateId
required
string
required
object
debug
boolean

Flag to switch between sandbox and non-sandbox app sid. Lower envs only

@@ -3354,7 +3366,18 @@

Request samples

Content type
application/json
{
  • "appName": "va_mobile_app",
  • "templateId": "0EF7C8C9390847D7B3B521426EFF5814",
  • "personalization": {
    },
  • "debug": true
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/user

Returns the user profile, including the user's addresses and the services the user has the requisite ids to access. Meta data for this endpoint returns all the services available in the API.

+

Request samples

Content type
application/json
{
  • "appName": "va_mobile_app",
  • "templateId": "0EF7C8C9390847D7B3B521426EFF5814",
  • "personalization": {
    },
  • "debug": true
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/translations/download

Downloads translations file.

+
query Parameters
current_version
string

When this endpoint responds with a 200, it includes a Content-Version header. That value is an epoch time integer that the frontend will store and send as the current_version parameter. When this value is less than the translation file's last modified time, it responds with a 200 status and the newest version of the translations file. If the timestamp is equal to the translation file's last modified time, it responds with 204 and no content.

+
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

+

Responses

Response samples

Content type
application/json
"string"

/v0/user

Returns the user profile, including the user's addresses and the services the user has the requisite ids to access. Meta data for this endpoint returns all the services available in the API.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    },
  • "meta": {
    }
}

/v0/user/authorized-services

Returns a hash of all available services, and a boolean value of whether the user has access to that service.

+

Response samples

Content type
application/json
{
  • "data": {
    },
  • "meta": {
    }
}

/v0/user/authorized-services

Returns a hash of all available services, and a boolean value of whether the user has access to that service.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/contact-info

Returns the user contact info. If the user does not have a vet360 id, the contact info will be null.

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/contact-info

Returns the user contact info. If the user does not have a vet360 id, the contact info will be null.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v1/user

Returns the user profile, including the user's addresses and the services the user has the requisite ids to access. Meta data for this endpoint returns all the services available in the API. v1 includes LOGINGOV as login type.

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v1/user

Returns the user profile, including the user's addresses and the services the user has the requisite ids to access. Meta data for this endpoint returns all the services available in the API. v1 includes LOGINGOV as login type.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    },
  • "meta": {
    }
}

/v2/user

Returns basic user information

+

Response samples

Content type
application/json
{
  • "data": {
    },
  • "meta": {
    }
}

/v2/user

Returns basic user information

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/addresses

Deletes a user's address

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/addresses

Deletes a user's address

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

A domestic, internation, or military address

id
required
integer
addressLine1
required
string
addressLine2
required
string, null
addressLine3
required
string, null
addressPou
required
string
Enum: "RESIDENCE/CHOICE" "CORRESPONDENCE"
addressType
required
string
Enum: "DOMESTIC" "INTERNATIONAL" "MILITARY"
city
required
string
countryCode
required
string
internationalPostalCode
required
string, null
province
required
string, null
stateCode
required
string
zipCode
required
string
zipCodeSuffix
required
string, null

Responses

Request samples

Content type
application/json
{
  • "id": 157032,
  • "addressLine1": "1493 Martin Luther King Rd",
  • "addressLine2": null,
  • "addressLine3": null,
  • "addressPou": "RESIDENCE/CHOICE",
  • "addressType": "DOMESTIC",
  • "city": "Fulton",
  • "countryCode": "US",
  • "internationalPostalCode": null,
  • "province": null,
  • "stateCode": "NY",
  • "zipCode": "97062",
  • "zipCodeSuffix": "1234"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/addresses

Creates a new residential or mailing address for a user. Calling this endpoint is the second step in adding a new address for a user. The first step is to call the address validation endpoint to check if an address is valid. If it is valid you'll receive a 'addressMetaData' object back with the addresses confidence score. This object should then be included along with the new address in the request body. If the user wishes to continue with an 'invalid' address then the 'validationKey' should be passed along with the new address in the request body. This lets the underlying service know that an invalid address be passed through.

+

Request samples

Content type
application/json
{
  • "id": 157032,
  • "addressLine1": "1493 Martin Luther King Rd",
  • "addressLine2": null,
  • "addressLine3": null,
  • "addressPou": "RESIDENCE/CHOICE",
  • "addressType": "DOMESTIC",
  • "city": "Fulton",
  • "countryCode": "US",
  • "internationalPostalCode": null,
  • "province": null,
  • "stateCode": "NY",
  • "zipCode": "97062",
  • "zipCodeSuffix": "1234"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/addresses

Creates a new residential or mailing address for a user. Calling this endpoint is the second step in adding a new address for a user. The first step is to call the address validation endpoint to check if an address is valid. If it is valid you'll receive a 'addressMetaData' object back with the addresses confidence score. This object should then be included along with the new address in the request body. If the user wishes to continue with an 'invalid' address then the 'validationKey' should be passed along with the new address in the request body. This lets the underlying service know that an invalid address be passed through.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

A domestic, internation, or military address

required
object

Responses

Request samples

Content type
application/json
Example
{
  • "addressLine1": "1493 Martin Luther King Rd",
  • "addressPou": "RESIDENCE/CHOICE",
  • "addressType": "DOMESTIC",
  • "city": "Fulton",
  • "countryCodeIso3": "USA",
  • "countryName": "United States",
  • "stateCode": "MS",
  • "validationKey": -1206619807,
  • "zipCode": "38843"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/addresses

Updates a user's residential or mailing address. Calling this endpoint is the second step in adding a new address for a user. The first step is to call the address validation endpoint to check if an address is valid. If it is valid you'll receive a 'addressMetaData' object back with the addresses confidence score. This object should then be included along with the new address in the request body. If the user wishes to continue with an 'invalid' address then the 'validationKey' should be passed along with the new address in the request body. This lets the underlying service know that an invalid address be passed through.

+

Request samples

Content type
application/json
Example
{
  • "addressLine1": "1493 Martin Luther King Rd",
  • "addressPou": "RESIDENCE/CHOICE",
  • "addressType": "DOMESTIC",
  • "city": "Fulton",
  • "countryCodeIso3": "USA",
  • "countryName": "United States",
  • "stateCode": "MS",
  • "validationKey": -1206619807,
  • "zipCode": "38843"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/addresses

Updates a user's residential or mailing address. Calling this endpoint is the second step in adding a new address for a user. The first step is to call the address validation endpoint to check if an address is valid. If it is valid you'll receive a 'addressMetaData' object back with the addresses confidence score. This object should then be included along with the new address in the request body. If the user wishes to continue with an 'invalid' address then the 'validationKey' should be passed along with the new address in the request body. This lets the underlying service know that an invalid address be passed through.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

A domestic, internation, or military address

id
required
string
object
validationKey
integer
addressLine1
required
string
addressLine2
string, null
addressLine3
string, null
addressPou
required
string
Enum: "RESIDENCE/CHOICE" "CORRESPONDENCE"
addressType
required
string
Enum: "DOMESTIC" "INTERNATIONAL" "MILITARY"
city
required
string
countryCode
required
string
internationalPostalCode
string, null
province
string, null
stateCode
string
zipCode
string
zipCodeSuffix
string, null

Responses

Request samples

Content type
application/json
Example
{
  • "addressLine1": "1493 Martin Luther King Rd",
  • "addressPou": "RESIDENCE/CHOICE",
  • "addressType": "DOMESTIC",
  • "city": "Fulton",
  • "countryCodeIso3": "USA",
  • "countryName": "United States",
  • "id": 181513,
  • "stateCode": "MS",
  • "validationKey": -1206619807,
  • "zipCode": "38843"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/addresses/validate

Validates a residential or mailing address for a user. Calling this endpoint is the first step in adding a new address for a user. If the address is valid you'll receive a 'addressMetaData' object back with the addresses confidence score. This object should then be included along with the new address in the request body. If the user wishes to continue with an 'invalid' address then the 'validationKey' should be passed along with the new address in the request body. This lets the underlying service know that an invalid address be passed through.

+

Request samples

Content type
application/json
Example
{
  • "addressLine1": "1493 Martin Luther King Rd",
  • "addressPou": "RESIDENCE/CHOICE",
  • "addressType": "DOMESTIC",
  • "city": "Fulton",
  • "countryCodeIso3": "USA",
  • "countryName": "United States",
  • "id": 181513,
  • "stateCode": "MS",
  • "validationKey": -1206619807,
  • "zipCode": "38843"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/addresses/validate

Validates a residential or mailing address for a user. Calling this endpoint is the first step in adding a new address for a user. If the address is valid you'll receive a 'addressMetaData' object back with the addresses confidence score. This object should then be included along with the new address in the request body. If the user wishes to continue with an 'invalid' address then the 'validationKey' should be passed along with the new address in the request body. This lets the underlying service know that an invalid address be passed through.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

A domestic, internation, or military address

id
required
integer
addressLine1
required
string
addressLine2
required
string, null
addressLine3
required
string, null
addressPou
required
string
Enum: "RESIDENCE/CHOICE" "CORRESPONDENCE"
addressType
required
string
Enum: "DOMESTIC" "INTERNATIONAL" "MILITARY"
city
required
string
countryCode
required
string
internationalPostalCode
required
string, null
province
required
string, null
stateCode
required
string
zipCode
required
string
zipCodeSuffix
required
string, null

Responses

Request samples

Content type
application/json
{
  • "addressLine1": "51 W Weber Rd",
  • "addressPou": "CORRESPONDENCE",
  • "addressType": "DOMESTIC",
  • "city": "Columbus",
  • "countryCodeIso3": "USA",
  • "countryName": "United States",
  • "stateCode": "OH",
  • "type": "DOMESTIC",
  • "zipCode": "43202"
}

Response samples

Content type
application/json
Example
{
  • "data": [
    ]
}

/v0/user/demographics

Returns the users demographics info

+

Request samples

Content type
application/json
{
  • "addressLine1": "51 W Weber Rd",
  • "addressPou": "CORRESPONDENCE",
  • "addressType": "DOMESTIC",
  • "city": "Columbus",
  • "countryCodeIso3": "USA",
  • "countryName": "United States",
  • "stateCode": "OH",
  • "type": "DOMESTIC",
  • "zipCode": "43202"
}

Response samples

Content type
application/json
Example
{
  • "data": [
    ]
}

/v0/user/demographics

Returns the users demographics info

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/emails

Deletes a user's email address

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/emails

Deletes a user's email address

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

The email address to delete

id
required
integer
emailAddress
required
string

Responses

Request samples

Content type
application/json
{
  • "emailAddress": "person42@example.com",
  • "id": "42,"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/emails

Creates a new email address

+

Request samples

Content type
application/json
{
  • "emailAddress": "person42@example.com",
  • "id": "42,"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/emails

Creates a new email address

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

The new email address

emailAddress
required
string

Responses

Request samples

Content type
application/json
{
  • "emailAddress": "person42@example.com"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/emails

Updates a user's email address

+

Request samples

Content type
application/json
{
  • "emailAddress": "person42@example.com"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/emails

Updates a user's email address

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

The new email address

id
required
integer
emailAddress
required
string

Responses

Request samples

Content type
application/json
{
  • "emailAddress": "person42@example.com",
  • "id": "42,"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/gender_identity

Updates a user's gender identity. Only users with id.me or login.gov accounts may use this

+

Request samples

Content type
application/json
{
  • "emailAddress": "person42@example.com",
  • "id": "42,"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/gender_identity

Updates a user's gender identity. Only users with id.me or login.gov accounts may use this

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

The new gender identity key

code
required
string

Responses

Request samples

Content type
application/json
{
  • "code": "B"
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/user/gender_identity/edit

Retrieves a list of valid gender identity keys. Note that this endpoint does not use the camel case key inflection header like most other mobile endpoints to keep the keys upcase.

+

Request samples

Content type
application/json
{
  • "code": "B"
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/user/gender_identity/edit

Retrieves a list of valid gender identity keys. Note that this endpoint does not use the camel case key inflection header like most other mobile endpoints to keep the keys upcase.

Authorizations:
Bearer

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/logout

Logs the user out by revoking their access token from the IAM SSOe OAuth service and destroying the IAM user, user identity, and session objects from Redis.

+

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/logout

Logs the user out by revoking their access token from the IAM SSOe OAuth service and destroying the IAM user, user identity, and session objects from Redis.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/user/logged-in

Called by the mobile app after successful login to perform any actions needed to start a session.

+

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/user/logged-in

Called by the mobile app after successful login to perform any actions needed to start a session.

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Responses

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/user/preferred_name

Updates a user's preferred name. Only users with id.me or login.gov accounts may use this

+

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/user/preferred_name

Updates a user's preferred name. Only users with id.me or login.gov accounts may use this

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

The new preferred name

text
required
string

Responses

Request samples

Content type
application/json
{
  • "text": "New Preferred Name"
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/user/phones

Deletes one of a user's phone numbers

+

Request samples

Content type
application/json
{
  • "text": "New Preferred Name"
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

/v0/user/phones

Deletes one of a user's phone numbers

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

The phone number to delete

id
required
integer
areaCode
required
string
countryCode
required
string
phoneNumber
required
string
phoneType
required
string
Enum: "HOME" "FAX" "MOBILE" "WORK"
extension
required
string

Responses

Request samples

Content type
application/json
{
  • "id": 157032,
  • "areaCode": "704",
  • "countryCode": "1",
  • "phoneNumber": "7749069",
  • "phoneType": "HOME",
  • "extension": "4567"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/phones

Creates a phone number for a user

+

Request samples

Content type
application/json
{
  • "id": 157032,
  • "areaCode": "704",
  • "countryCode": "1",
  • "phoneNumber": "7749069",
  • "phoneType": "HOME",
  • "extension": "4567"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/phones

Creates a phone number for a user

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

The new phone number

id
integer
areaCode
required
string
countryCode
required
string
phoneNumber
required
string
phoneType
required
string
Enum: "HOME" "FAX" "MOBILE" "WORK"
extension
required
string

Responses

Request samples

Content type
application/json
{
  • "id": 157032,
  • "areaCode": "704",
  • "countryCode": "1",
  • "phoneNumber": "7749069",
  • "phoneType": "HOME",
  • "extension": "4567"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/phones

Updates a user's phone number

+

Request samples

Content type
application/json
{
  • "id": 157032,
  • "areaCode": "704",
  • "countryCode": "1",
  • "phoneNumber": "7749069",
  • "phoneType": "HOME",
  • "extension": "4567"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v0/user/phones

Updates a user's phone number

Authorizations:
Bearer
header Parameters
X-Key-Inflection
string
Default: snake
Enum: "camel" "snake"

Allows the API to return camelCase keys rather than snake_case

Request Body schema: application/json

The new phone number

id
required
integer
areaCode
required
string
countryCode
required
string
phoneNumber
required
string
phoneType
required
string
Enum: "HOME" "FAX" "MOBILE" "WORK"
extension
required
string

Responses

Request samples

Content type
application/json
{
  • "id": 157032,
  • "areaCode": "704",
  • "countryCode": "1",
  • "phoneNumber": "7749069",
  • "phoneType": "HOME",
  • "extension": "4567"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v1/health/immunizations

Returns a paginated list of immunization records for given user

+

Request samples

Content type
application/json
{
  • "id": 157032,
  • "areaCode": "704",
  • "countryCode": "1",
  • "phoneNumber": "7749069",
  • "phoneType": "HOME",
  • "extension": "4567"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

/v1/health/immunizations

Returns a paginated list of immunization records for given user

Authorizations:
Bearer
query Parameters
page[number]
integer
Example: page[number]=1

The page number requested. Defaults to 1.

page[size]
integer
Example: page[size]=10

The number of records to return per page. Defaults to 10.

useCache
boolean
Example: useCache=true

Whether or not to use this API's cache or fetch records from the upstream service. Defaults to true.

@@ -3623,9 +3646,9 @@

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}
+

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}