From aaceb9279c03cd5e1f6903cf57e0b6846a8f8ccc Mon Sep 17 00:00:00 2001 From: Adam King Date: Tue, 3 Sep 2024 11:13:39 -0500 Subject: [PATCH 01/31] add feature toggle (#18266) --- config/features.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/features.yml b/config/features.yml index 44c1940bb5d..3b7df234fa1 100644 --- a/config/features.yml +++ b/config/features.yml @@ -1385,6 +1385,10 @@ features: veteran_onboarding_show_to_newly_onboarded: actor_type: user description: Conditionally display the new veteran onboarding flow to user, based upon number of days since verified + veteran_onboarding_show_welcome_message_to_new_users: + actor_type: user + description: Conditionally display the "Welcome to VA" message to new (LOA1 or LOA3) users + enable_in_development: true show_edu_benefits_1990EZ_Wizard: actor_type: user description: Navigates user to 1990EZ or 1990 depending on form questions. From ed0b56328722920c562b3f8db0bfaee24e85c403 Mon Sep 17 00:00:00 2001 From: Rockwell Windsor Rice <129893414+rockwellwindsor-va@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:45:22 -0500 Subject: [PATCH 02/31] Api 39213 move build supporting docs to concern (#18152) * API-39213-move-build-supporting-docs-to-concern * Moves some related methods out into a concern modified: modules/claims_api/app/controllers/claims_api/v2/veterans/claims_controller.rb new file: modules/claims_api/app/controllers/concerns/claims_api/v2/claims_requests/supporting_documents.rb * WIP * Revert Gemfile.lock change from conflict * Revert Gemfile.lock change from conflict * Repositions spec file in line with other refactor * tryng to knock down some of the line count: removed unneeded test values * Adds tests for evss_docs * Reverts Gemfile.lock update due to merge conflict --- .../v2/veterans/claims_controller.rb | 83 +-------- .../claims_requests/supporting_documents.rb | 93 ++++++++++ .../supporting_documents_spec.rb | 172 ++++++++++++++++++ 3 files changed, 266 insertions(+), 82 deletions(-) create mode 100644 modules/claims_api/app/controllers/concerns/claims_api/v2/claims_requests/supporting_documents.rb create mode 100644 modules/claims_api/spec/concerns/claims_api/v2/claims_requests/supporting_documents_spec.rb diff --git a/modules/claims_api/app/controllers/claims_api/v2/veterans/claims_controller.rb b/modules/claims_api/app/controllers/claims_api/v2/veterans/claims_controller.rb index 4f81b718b8d..9420e881faf 100644 --- a/modules/claims_api/app/controllers/claims_api/v2/veterans/claims_controller.rb +++ b/modules/claims_api/app/controllers/claims_api/v2/veterans/claims_controller.rb @@ -7,6 +7,7 @@ module V2 module Veterans class ClaimsController < ClaimsApi::V2::ApplicationController include ClaimsApi::V2::ClaimsRequests::TrackedItems + include ClaimsApi::V2::ClaimsRequests::SupportingDocuments include ClaimsApi::V2::ClaimsRequests::TrackedItemsAssistance include ClaimsApi::V2::ClaimsRequests::ClaimValidation @@ -41,10 +42,6 @@ def show private - def evss_docs_service - EVSS::DocumentsService.new(auth_headers) - end - def bgs_phase_status_mapper ClaimsApi::BGSClaimStatusMapper.new end @@ -378,76 +375,6 @@ def find_tracked_item(id) [@tracked_items].flatten.compact.find { |item| item[:dvlpmt_item_id] == id } end - def get_evss_documents(claim_id) - evss_docs_service.get_claim_documents(claim_id).body - rescue => e - claims_v2_logging('evss_doc_service', level: 'error', - message: "getting docs failed in claims controller with e.message: ' \ - '#{e.message}, rid: #{request.request_id}") - {} - end - - # rubocop:disable Metrics/MethodLength - def build_supporting_docs(bgs_claim) - return [] if bgs_claim.nil? - - @supporting_documents = [] - - docs = if benefits_documents_enabled? - file_number = if use_birls_id_file_number? - target_veteran.birls_id - else - local_bgs_service.find_by_ssn(target_veteran.ssn)&.dig(:file_nbr) # rubocop:disable Rails/DynamicFindBy - end - - if file_number.nil? - claims_v2_logging('benefits_documents', - message: "calling benefits documents api for claim_id: #{params[:id]} " \ - 'returned a nil file number in claims controller v2') - - return [] - end - - claims_v2_logging('benefits_documents', - message: "calling benefits documents api for claim_id #{params[:id]} " \ - 'in claims controller v2') - supporting_docs_list = benefits_doc_api.search(params[:id], - file_number)&.dig(:data) - # add with_indifferent_access so ['documents'] works below - # we can remove when EVSS is gone and access it via it's symbol - supporting_docs_list.with_indifferent_access if supporting_docs_list.present? - else - get_evss_documents(bgs_claim[:benefit_claim_details_dto][:benefit_claim_id]) - end - return [] if docs.nil? || docs&.dig('documents').blank? - - @supporting_documents = docs['documents'].map do |doc| - doc = doc.transform_keys(&:underscore) if benefits_documents_enabled? - upload_date = upload_date(doc['upload_date']) || bd_upload_date(doc['uploaded_date_time']) - { - document_id: doc['document_id'], - document_type_label: doc['document_type_label'], - original_file_name: doc['original_file_name'], - tracked_item_id: doc['tracked_item_id'], - upload_date: - } - end - end - # rubocop:enable Metrics/MethodLength - - # duplicating temporarily to bd_upload_date. remove when EVSS call is gone - def upload_date(upload_date) - return if upload_date.nil? - - Time.zone.at(upload_date / 1000).strftime('%Y-%m-%d') - end - - def bd_upload_date(upload_date) - return if upload_date.nil? - - Date.parse(upload_date).strftime('%Y-%m-%d') - end - def build_claim_phase_attributes(bgs_claim, view) return {} if bgs_claim.nil? @@ -466,14 +393,6 @@ def build_claim_phase_attributes(bgs_claim, view) } end end - - def benefits_documents_enabled? - Flipper.enabled? :claims_status_v2_lh_benefits_docs_service_enabled - end - - def use_birls_id_file_number? - Flipper.enabled? :lighthouse_claims_api_use_birls_id - end end end end diff --git a/modules/claims_api/app/controllers/concerns/claims_api/v2/claims_requests/supporting_documents.rb b/modules/claims_api/app/controllers/concerns/claims_api/v2/claims_requests/supporting_documents.rb new file mode 100644 index 00000000000..1029154c174 --- /dev/null +++ b/modules/claims_api/app/controllers/concerns/claims_api/v2/claims_requests/supporting_documents.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +module ClaimsApi + module V2 + module ClaimsRequests + module SupportingDocuments + extend ActiveSupport::Concern + + # rubocop:disable Metrics/MethodLength + def build_supporting_docs(bgs_claim) + return [] if bgs_claim.nil? + + @supporting_documents = [] + + docs = if benefits_documents_enabled? + file_number = if use_birls_id_file_number? + target_veteran.birls_id + else + local_bgs_service.find_by_ssn(target_veteran.ssn)&.dig(:file_nbr) # rubocop:disable Rails/DynamicFindBy + end + + if file_number.nil? + claims_v2_logging('benefits_documents', + message: "calling benefits documents api for claim_id: #{params[:id]} " \ + 'returned a nil file number in claims controller v2') + + return [] + end + + claims_v2_logging('benefits_documents', + message: "calling benefits documents api for claim_id #{params[:id]} " \ + 'in claims controller v2') + supporting_docs_list = benefits_doc_api.search(params[:id], + file_number)&.dig(:data) + # add with_indifferent_access so ['documents'] works below + # we can remove when EVSS is gone and access it via it's symbol + supporting_docs_list.with_indifferent_access if supporting_docs_list.present? + else + get_evss_documents(bgs_claim[:benefit_claim_details_dto][:benefit_claim_id]) + end + return [] if docs.nil? || docs&.dig('documents').blank? + + @supporting_documents = docs['documents'].map do |doc| + doc = doc.transform_keys(&:underscore) if benefits_documents_enabled? + upload_date = upload_date(doc['upload_date']) || bd_upload_date(doc['uploaded_date_time']) + { + document_id: doc['document_id'], + document_type_label: doc['document_type_label'], + original_file_name: doc['original_file_name'], + tracked_item_id: doc['tracked_item_id'], + upload_date: + } + end + end + # rubocop:enable Metrics/MethodLength + + def get_evss_documents(claim_id) + evss_docs_service.get_claim_documents(claim_id).body + rescue => e + claims_v2_logging('evss_doc_service', level: 'error', + message: "getting docs failed in claims controller with e.message: ' \ + '#{e.message}, rid: #{request.request_id}") + {} + end + + # duplicating temporarily to bd_upload_date. remove when EVSS call is gone + def upload_date(upload_date) + return if upload_date.nil? + + Time.zone.at(upload_date / 1000).strftime('%Y-%m-%d') + end + + def bd_upload_date(upload_date) + return if upload_date.nil? + + Date.parse(upload_date).strftime('%Y-%m-%d') + end + + def evss_docs_service + EVSS::DocumentsService.new(auth_headers) + end + + def benefits_documents_enabled? + Flipper.enabled? :claims_status_v2_lh_benefits_docs_service_enabled + end + + def use_birls_id_file_number? + Flipper.enabled? :lighthouse_claims_api_use_birls_id + end + end + end + end +end diff --git a/modules/claims_api/spec/concerns/claims_api/v2/claims_requests/supporting_documents_spec.rb b/modules/claims_api/spec/concerns/claims_api/v2/claims_requests/supporting_documents_spec.rb new file mode 100644 index 00000000000..f0f98b1b1cc --- /dev/null +++ b/modules/claims_api/spec/concerns/claims_api/v2/claims_requests/supporting_documents_spec.rb @@ -0,0 +1,172 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'bd/bd' + +class FakeController + include ClaimsApi::V2::ClaimsRequests::SupportingDocuments + + def local_bgs_service + @local_bgs_service ||= ClaimsApi::LocalBGS.new( + external_uid: target_veteran.participant_id, + external_key: target_veteran.participant_id + ) + end + + def target_veteran + OpenStruct.new( + icn: '1013062086V794840', + first_name: 'abraham', + last_name: 'lincoln', + loa: { current: 3, highest: 3 }, + ssn: '796111863', + edipi: '8040545646', + participant_id: '600061742', + mpi: OpenStruct.new( + icn: '1013062086V794840', + profile: OpenStruct.new(ssn: '796111863') + ) + ) + end + + def request + { request_id: '222222222' } + end + + def benefits_doc_api + @benefits_doc_api ||= ClaimsApi::BD.new + end + + def claims_v2_logging(*) + true + end + + def params + { id: '8675309' } + end +end + +describe ClaimsApi::V2::ClaimsRequests::SupportingDocuments do + let(:bgs_claim) do + { + benefit_claim_details_dto: { + benefit_claim_id: '111111111' + } + } + end + + let(:supporting_doc_list) do + { data: { + documents: [ + { + documentId: '{2161bfaa-cb21-43a6-90fc-c800c88f1234}', + originalFileName: 'Jesse_Gray_600527334_526EZ.pdf', + documentTypeLabel: 'VA 21-526 Veterans Application for Compensation or Pension', + uploadedDateTime: '2024-07-16T18:59:08Z' + }, { + documentId: '{c4dbbe82-4502-4a0a-bfec-a65b7ddd2f8f}', + originalFileName: 'Jesse_Gray_600527334_526EZ.pdf', + documentTypeLabel: 'VA 21-526 Veterans Application for Compensation or Pension', + uploadedDateTime: '2024-07-16T18:59:43Z' + } + ] + } } + end + + let(:evss_doc_list) do + { + 'messages' => nil, + 'documents' => [ + { + 'content' => nil, + 'corporate_document_id' => 107_597, + 'tracked_item_id' => nil, + 'document_id' => '{54EF0C16-A9E7-4C3F-B876-B2C7BEC1F834}', + 'document_size' => 0, + 'document_type_code' => 'L478', + 'document_type_id' => '478', + 'document_type_label' => 'Medical' + } + ] + } + end + + let(:dummy_class) { Class.new { include ClaimsApi::V2::ClaimsRequests::SupportingDocuments } } + + let(:controller) { FakeController.new } + + before do + allow(Flipper).to receive(:enabled?).with(:claims_status_v2_lh_benefits_docs_service_enabled).and_return(true) + allow(Flipper).to receive(:enabled?).with(:lighthouse_claims_api_use_birls_id).and_return(false) + + allow(controller.local_bgs_service).to receive(:find_by_ssn).with('796111863') + .and_return({ file_nbr: '796111863' }) + allow(controller.benefits_doc_api).to receive(:search).with('8675309', '796111863') + .and_return(supporting_doc_list) + end + + describe '#build_supporting_docs from Benefits Documents' do + it 'builds and returns the correctly number of docs' do + result = controller.build_supporting_docs(bgs_claim) + expect(result.length).to eq(supporting_doc_list[:data][:documents].length) + end + + it 'builds the correct doc output' do + result = controller.build_supporting_docs(bgs_claim) + + expect(result[0][:document_id]).to eq(supporting_doc_list[:data][:documents][0][:documentId]) + expect(result[0][:document_type_label]).to eq(supporting_doc_list[:data][:documents][0][:documentTypeLabel]) + expect(result[0][:original_file_name]).to eq(supporting_doc_list[:data][:documents][0][:originalFileName]) + expect(result[0][:tracked_item_id]).to eq(nil) + expect(result[0][:upload_date]).to eq('2024-07-16') + end + end + + describe '#build_supporting_docs from EVSS Docs Service' do + before do + allow(Flipper).to receive(:enabled?).with(:claims_status_v2_lh_benefits_docs_service_enabled).and_return(false) + allow(controller).to receive(:get_evss_documents).and_call_original + allow(controller).to receive(:get_evss_documents).and_return(evss_doc_list) + end + + it 'builds and returns the correctly number of docs' do + result = controller.build_supporting_docs(bgs_claim) + expect(result.length).to eq(evss_doc_list['documents'].length) + end + + it 'builds the correct doc output' do + result = controller.build_supporting_docs(bgs_claim) + + expect(result[0][:document_id]).to eq(evss_doc_list['documents'][0]['document_id']) + expect(result[0][:document_type_label]).to eq(evss_doc_list['documents'][0]['document_type_label']) + expect(result[0][:original_file_name]).to eq(nil) + expect(result[0][:tracked_item_id]).to eq(nil) + expect(result[0][:upload_date]).to eq(nil) + end + end + + describe '#bd_upload_date' do + it 'properly formats the date when a date is sent' do + result = controller.bd_upload_date(supporting_doc_list[:data][:documents][0][:uploadedDateTime]) + expect(result).to eq('2024-07-16') + end + + it 'returns nil if the date is empty' do + result = controller.bd_upload_date(nil) + expect(result).to eq(nil) + end + end + + describe '#upload_date' do + it 'properly formats the date when a date is sent' do + result = controller.upload_date(1_414_781_700_000) + + expect(result).to eq('2014-10-31') + end + + it 'returns nil if the date is empty' do + result = controller.upload_date(nil) + expect(result).to eq(nil) + end + end +end From 95b31e79ad1fb8a7b6df6325c17c3e047e34e0cb Mon Sep 17 00:00:00 2001 From: Michael Clement Date: Tue, 3 Sep 2024 13:45:57 -0500 Subject: [PATCH 03/31] updated mapping to use new street combined property (#18190) --- modules/ivc_champva/app/form_mappings/vha_10_7959f_1.json.erb | 4 ++-- .../ivc_champva/spec/fixtures/form_json/vha_10_7959f_1.json | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/ivc_champva/app/form_mappings/vha_10_7959f_1.json.erb b/modules/ivc_champva/app/form_mappings/vha_10_7959f_1.json.erb index ed90786035f..7e1e9f7d670 100644 --- a/modules/ivc_champva/app/form_mappings/vha_10_7959f_1.json.erb +++ b/modules/ivc_champva/app/form_mappings/vha_10_7959f_1.json.erb @@ -5,9 +5,9 @@ "form1[0].#subform[0].SocialSecurityNumber[0]": "<%= form.data.dig('veteran', 'ssn') %>", "form1[0].#subform[0].VAClaimFileNumber[0]": "<%= form.data.dig('veteran', 'va_claim_number') %>", "form1[0].#subform[0].DateofBirth[0]": "<%= form.data.dig('veteran', 'date_of_birth') %>", - "form1[0].#subform[0].PhysicalAddress[0]": "<%= form.data.dig('veteran', 'physical_address', 'street') + '\n' + form.data.dig('veteran', 'physical_address', 'city') + ', ' + form.data.dig('veteran', 'physical_address', 'state') + '\n' + form.data.dig('veteran', 'physical_address', 'postal_code') %>", + "form1[0].#subform[0].PhysicalAddress[0]": "<%= form.data.dig('veteran', 'physical_address', 'street_combined') + '\n' + form.data.dig('veteran', 'physical_address', 'city') + ', ' + form.data.dig('veteran', 'physical_address', 'state') + '\n' + form.data.dig('veteran', 'physical_address', 'postal_code') %>", "form1[0].#subform[0].Country[0]": "<%= form.data.dig('veteran', 'physical_address', 'country') %>", - "form1[0].#subform[0].MailingAddress[0]": "<%= form.data.dig('veteran', 'mailing_address', 'street') + '\n' + form.data.dig('veteran', 'mailing_address', 'city') + ', ' + form.data.dig('veteran', 'mailing_address', 'state') + '\n' + form.data.dig('veteran', 'mailing_address', 'postal_code') %>", + "form1[0].#subform[0].MailingAddress[0]": "<%= form.data.dig('veteran', 'mailing_address', 'street_combined') + '\n' + form.data.dig('veteran', 'mailing_address', 'city') + ', ' + form.data.dig('veteran', 'mailing_address', 'state') + '\n' + form.data.dig('veteran', 'mailing_address', 'postal_code') %>", "form1[0].#subform[0].Country[1]": "<%= form.data.dig('veteran', 'mailing_address', 'country') %>", "form1[0].#subform[0].TelephoneNumber[0]": "<%= form.data.dig('veteran', 'phone_number') %>", "form1[0].#subform[0].EmailAddress[0]": "<%= form.data.dig('veteran', 'email_address') %>", diff --git a/modules/ivc_champva/spec/fixtures/form_json/vha_10_7959f_1.json b/modules/ivc_champva/spec/fixtures/form_json/vha_10_7959f_1.json index dce2d4db410..c2a969bbee9 100644 --- a/modules/ivc_champva/spec/fixtures/form_json/vha_10_7959f_1.json +++ b/modules/ivc_champva/spec/fixtures/form_json/vha_10_7959f_1.json @@ -17,6 +17,7 @@ "physical_address": { "country": "USA", "street": "1 Physical Ln", + "street_combined": "1 Physical Ln", "city": "Place", "state": "AL", "postal_code": "12345" @@ -24,6 +25,7 @@ "mailing_address": { "country": "USA", "street": "1 Mail Ln", + "street_combined": "1 Mail Ln", "city": "Place", "state": "PA", "postal_code": "12345" @@ -35,4 +37,4 @@ }, "statement_of_truth_signature": "Veteran B Surname", "current_date": "01/01/2024" -} \ No newline at end of file +} From cb95e081483b133d08907fa957a1cc1d7c9e100e Mon Sep 17 00:00:00 2001 From: Don Shin <99479640+cloudmagic80@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:50:32 -0500 Subject: [PATCH 04/31] multistamp fix (#18280) --- modules/ivc_champva/app/models/ivc_champva/vha_10_10d.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ivc_champva/app/models/ivc_champva/vha_10_10d.rb b/modules/ivc_champva/app/models/ivc_champva/vha_10_10d.rb index 07d4fc8888b..c1a3bac1e99 100644 --- a/modules/ivc_champva/app/models/ivc_champva/vha_10_10d.rb +++ b/modules/ivc_champva/app/models/ivc_champva/vha_10_10d.rb @@ -100,7 +100,7 @@ def initial_stamps stamps << { coords: [520, 470], text: first_applicant_country, page: 0 } stamps << { coords: [520, 590], text: veteran_country, page: 0 } unless sponsor_is_deceased - + stamps << { coords: [420, 45], text: veteran_country, page: 0 } if @data['certifier_role'] == 'sponsor' stamps end From 312ae43fafe69e99d395058ef2ae9ab88c9dd625 Mon Sep 17 00:00:00 2001 From: Austin Covrig Date: Tue, 3 Sep 2024 15:07:04 -0400 Subject: [PATCH 05/31] Api 39255 person web service (#18124) * Fix alphabetization * Add IntentToFileWebService --- modules/claims_api/lib/bgs_service/local_bgs.rb | 3 ++- modules/claims_api/spec/lib/claims_api/find_definition_spec.rb | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/claims_api/lib/bgs_service/local_bgs.rb b/modules/claims_api/lib/bgs_service/local_bgs.rb index e97b22ad5a3..cbc014aceb9 100644 --- a/modules/claims_api/lib/bgs_service/local_bgs.rb +++ b/modules/claims_api/lib/bgs_service/local_bgs.rb @@ -16,8 +16,9 @@ module ClaimsApi class LocalBGS CACHED_SERVICES = %w[ ClaimantServiceBean/ClaimantWebService - OrgWebServiceBean/OrgWebService IntentToFileWebServiceBean/IntentToFileWebService + OrgWebServiceBean/OrgWebService + PersonWebServiceBean/PersonWebService VDC/VeteranRepresentativeService VdcBean/ManageRepresentativeService VnpAtchmsWebServiceBean/VnpAtchmsService diff --git a/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb b/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb index 64c34faa249..624da476ca6 100644 --- a/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb +++ b/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb @@ -71,6 +71,7 @@ it 'response with the correct attributes' do result = subject.for_action(endpoint, action) parsed_result = JSON.parse(result.to_json) + expect(parsed_result['service']['bean']['path']).to eq 'PersonWebServiceBean' expect(parsed_result['service']['path']).to eq 'PersonWebService' expect(parsed_result['service']['bean']['namespaces']['target']).to eq 'http://person.services.vetsnet.vba.va.gov/' @@ -236,7 +237,7 @@ end end - context 'PersonWebServiceBean' do + context 'PersonWebService' do let(:endpoint) { 'PersonWebServiceBean/PersonWebService' } it 'response with the correct namespace' do From 8d0c2f8e4b655c995be63a8499b940c07b4270f8 Mon Sep 17 00:00:00 2001 From: Riley Anderson Date: Tue, 3 Sep 2024 14:19:22 -0600 Subject: [PATCH 06/31] [VI-371] MHV account creation service (#18250) --- .github/CODEOWNERS | 6 +- Gemfile | 1 + Gemfile.lock | 4 + config/initializers/sign_in_service.rb | 5 + config/settings.yml | 7 ++ db/seeds/development.rb | 11 ++ lib/mhv/account_creation/configuration.rb | 83 +++++++++++++ lib/mhv/account_creation/service.rb | 45 ++++++++ spec/lib/mhv/account_creation/service_spec.rb | 99 ++++++++++++++++ .../account_creation_service_200_response.yml | 109 ++++++++++++++++++ .../account_creation_service_400_response.yml | 109 ++++++++++++++++++ .../account_creation_service_500_response.yml | 109 ++++++++++++++++++ .../sts/sts_token_400_response.yml | 53 +++++++++ 13 files changed, 640 insertions(+), 1 deletion(-) create mode 100644 config/initializers/sign_in_service.rb create mode 100644 lib/mhv/account_creation/configuration.rb create mode 100644 lib/mhv/account_creation/service.rb create mode 100644 spec/lib/mhv/account_creation/service_spec.rb create mode 100644 spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_200_response.yml create mode 100644 spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_400_response.yml create mode 100644 spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_500_response.yml create mode 100644 spec/support/vcr_cassettes/sign_in_service/sts/sts_token_400_response.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 45265daf2f8..07dc0668afa 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -777,6 +777,7 @@ config/initializers/rubyzip.rb @department-of-veterans-affairs/va-api-engineers config/initializers/saml.rb @department-of-veterans-affairs/octo-identity config/initializers/session_store.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group config/initializers/sidekiq.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +config/initializers/sign_in_service.rb @department-of-veterans-affairs/octo-identity config/initializers/staccato.rb @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group config/initializers/statsd_instrument_monkeypatch.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group config/initializers/statsd.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -940,6 +941,7 @@ lib/mail_automation @department-of-veterans-affairs/va-api-engineers @department lib/map @department-of-veterans-affairs/octo-identity lib/mdot @department-of-veterans-affairs/va-cto-health-products @department-of-veterans-affairs/backend-review-group lib/medical_records @department-of-veterans-affairs/vfs-mhv-medical-records @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +lib/mhv/account_creation @department-of-veterans-affairs/octo-identity lib/mhv_ac @department-of-veterans-affairs/vfs-health-modernization-initiative @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/mhv_logging @department-of-veterans-affairs/vfs-health-modernization-initiative @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group lib/mpi @department-of-veterans-affairs/octo-identity @@ -1459,6 +1461,7 @@ spec/lib/mail_automation @department-of-veterans-affairs/va-api-engineers @depar spec/lib/map @department-of-veterans-affairs/octo-identity spec/lib/mdot @department-of-veterans-affairs/va-cto-health-products @department-of-veterans-affairs/backend-review-group spec/lib/medical_records @department-of-veterans-affairs/vfs-mhv-medical-records @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +spec/lib/mhv/account_creation @department-of-veterans-affairs/octo-identity spec/lib/mhv_ac @department-of-veterans-affairs/vfs-health-modernization-initiative @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/mhv_ac/client_spec.rb @department-of-veterans-affairs/vfs-health-modernization-initiative @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/lib/mhv_logging @department-of-veterans-affairs/vfs-health-modernization-initiative @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -2062,6 +2065,7 @@ spec/support/vcr_cassettes/lighthouse/veteran_verification @department-of-vetera spec/support/vcr_cassettes/mail_automation @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/support/vcr_cassettes/map @department-of-veterans-affairs/octo-identity spec/support/vcr_cassettes/mdot @department-of-veterans-affairs/va-cto-health-products @department-of-veterans-affairs/backend-review-group +spec/support/vcr_cassettes/mhv/account_creation @department-of-veterans-affairs/octo-identity spec/support/vcr_cassettes/mhv_account_creation @department-of-veterans-affairs/octo-identity spec/support/vcr_cassettes/mhv_account_type_service @department-of-veterans-affairs/octo-identity spec/support/vcr_cassettes/mhv_logging_client @department-of-veterans-affairs/vfs-health-modernization-initiative @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -2081,6 +2085,7 @@ spec/support/vcr_cassettes/search @department-of-veterans-affairs/backend-review spec/support/vcr_cassettes/search_click_tracking @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers spec/support/vcr_cassettes/search_typeahead @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers spec/support/vcr_cassettes/shared @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +spec/support/vcr_cassettes/sign_in_service @department-of-veterans-affairs/octo-identity spec/support/vcr_cassettes/slack/slack_bot_notify.yml @department-of-veterans-affairs/octo-identity spec/support/vcr_cassettes/sm_client @department-of-veterans-affairs/vfs-mhv-secure-messaging @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/support/vcr_cassettes/spec/support @department-of-veterans-affairs/octo-identity @@ -2143,4 +2148,3 @@ README.md @department-of-veterans-affairs/backend-review-group modules/accredited_representative_portal/spec/services/accredited_representative_portal/representative_user_loader_spec.rb @department-of-veterans-affairs/octo-identity modules/accredited_representative_portal/app/services/accredited_representative_portal/representative_user_loader.rb @department-of-veterans-affairs/octo-identity config/form_profile_mappings/FORM-MOCK-AE-DESIGN-PATTERNS.yml @department-of-veterans-affairs/tmf-auth-exp-design-patterns @department-of-veterans-affairs/backend-review-group - diff --git a/Gemfile b/Gemfile index 2c75d3dcca4..5e2db9f169d 100644 --- a/Gemfile +++ b/Gemfile @@ -147,6 +147,7 @@ gem 'rubyzip' gem 'savon' gem 'sentry-ruby' gem 'shrine' +gem 'sign_in_service' gem 'slack-notify' gem 'socksify' gem 'staccato' diff --git a/Gemfile.lock b/Gemfile.lock index 2df8a830140..dba8d2547d7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -989,6 +989,9 @@ GEM connection_pool (>= 2.3.0) rack (>= 2.2.4) redis-client (>= 0.19.0) + sign_in_service (0.4.0) + faraday (~> 2.7) + jwt (~> 2.8) signet (0.19.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) @@ -1272,6 +1275,7 @@ DEPENDENCIES sidekiq (~> 7.2.0) sidekiq-ent! sidekiq-pro! + sign_in_service simple_forms_api! simplecov slack-notify diff --git a/config/initializers/sign_in_service.rb b/config/initializers/sign_in_service.rb new file mode 100644 index 00000000000..c4f0607dde1 --- /dev/null +++ b/config/initializers/sign_in_service.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +SignInService::Sts.configure do |config| + config.base_url = Settings.sign_in.sts_client.base_url +end diff --git a/config/settings.yml b/config/settings.yml index 5781a872e7b..75c3745daba 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -79,6 +79,7 @@ sign_in: vamobile_client_id: vamobile arp_client_id: arp sts_client: + base_url: http://localhost:3000 key_path: spec/fixtures/sign_in/sts_client.pem terms_of_use: @@ -558,6 +559,12 @@ mhv: host: fake-host app_token: fake-app-token x_auth_key: fake-x-auth-key + account_creation: + mock: true + host: https://mhv-intb-api.myhealth.va.gov + sts: + service_account_id: c34b86f2130ff3cd4b1d309bc09d8740 + issuer: http://localhost:3000 # Settings for alternate MHV integration for mobile app mhv_mobile: diff --git a/db/seeds/development.rb b/db/seeds/development.rb index 10c358fe548..f4f5c0c9a2e 100644 --- a/db/seeds/development.rb +++ b/db/seeds/development.rb @@ -158,6 +158,17 @@ certificates: [File.read('spec/fixtures/sign_in/sts_client.crt')] ) +# Create Service Account Config for MHV Account Creation +mhv_ac = SignIn::ServiceAccountConfig.find_or_initialize_by(service_account_id: 'c34b86f2130ff3cd4b1d309bc09d8740') +mhv_ac.update!( + description: 'MHV Account Creation - localhost', + scopes: ['https://mhv-intb-api.myhealth.va.gov/mhvapi/v1/usermgmt/account-service/account'], + access_token_audience: 'http://localhost:3000', + access_token_user_attributes: ['icn'], + access_token_duration: SignIn::Constants::ServiceAccountAccessToken::VALIDITY_LENGTH_SHORT_MINUTES, + certificates: [File.read('spec/fixtures/sign_in/sts_client.crt')] +) + # Update any exisitng ServiceAccountConfigs and ClientConfigs with default empty arrays SignIn::ServiceAccountConfig.where(certificates: nil).update(certificates: []) SignIn::ServiceAccountConfig.where(scopes: nil).update(scopes: []) diff --git a/lib/mhv/account_creation/configuration.rb b/lib/mhv/account_creation/configuration.rb new file mode 100644 index 00000000000..603d5269c34 --- /dev/null +++ b/lib/mhv/account_creation/configuration.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +require 'common/client/configuration/rest' +require 'common/client/middleware/logging' + +module MHV + module AccountCreation + class Configuration < Common::Client::Configuration::REST + def base_path + Settings.mhv.account_creation.host + end + + def service_name + 'mhv_account_creation' + end + + def account_creation_path + 'mhvapi/v1/usermgmt/account-service/account' + end + + def logging_prefix + '[MHV][AccountCreation][Service]' + end + + def tou_status + 'accepted' + end + + def tou_revision + '3' + end + + def tou_legal_version + '1.0' + end + + def tou_doc_title + 'VA Enterprise Terms of Use' + end + + def connection + Faraday.new(base_path, headers: base_request_headers, request: request_options) do |conn| + conn.use :breakers + conn.use Faraday::Response::RaiseError + conn.adapter Faraday.default_adapter + conn.response :json + conn.response :betamocks if Settings.mhv.account_creation.mock + end + end + + def sts_token(user_identifier:) + token = sts_client(user_identifier).token + Rails.logger.info("#{logging_prefix} sts token request success", user_identifier:) + token + rescue SignInService::Error => e + error_message = e.message + Rails.logger.error("#{logging_prefix} sts token request failed", user_identifier:, error_message:) + raise Common::Client::Errors::ClientError, error_message + end + + private + + def sts_client(user_identifier) + SignInService::Sts.new( + service_account_id: mhv_sts_settings.service_account_id, + issuer: mhv_sts_settings.issuer, + private_key_path: Settings.sign_in.sts_client.key_path, + scopes: sts_scopes, + user_identifier:, + user_attributes: { icn: user_identifier } + ) + end + + def sts_scopes + ["#{base_path}/#{account_creation_path}"] + end + + def mhv_sts_settings + Settings.mhv.account_creation.sts + end + end + end +end diff --git a/lib/mhv/account_creation/service.rb b/lib/mhv/account_creation/service.rb new file mode 100644 index 00000000000..6fe95cae152 --- /dev/null +++ b/lib/mhv/account_creation/service.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'mhv/account_creation/configuration' + +module MHV + module AccountCreation + class Service < Common::Client::Base + configuration Configuration + + def create_account(icn:, email:, tou_occurred_at:) + params = build_create_account_params(icn:, email:, tou_occurred_at:) + + response = perform(:post, config.account_creation_path, params, authenticated_header(icn:)) + Rails.logger.info("#{config.logging_prefix} create_account success", icn:) + + normalize_response_body(response.body) + 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: }) + end + + private + + def build_create_account_params(icn:, email:, tou_occurred_at:) + { + icn:, + email:, + vaTermsOfUseDateTime: tou_occurred_at, + vaTermsOfUseStatus: config.tou_status, + vaTermsOfUseRevision: config.tou_revision, + vaTermsOfUseLegalVersion: config.tou_legal_version, + vaTermsOfUseDocTitle: config.tou_doc_title + }.to_json + end + + def authenticated_header(icn:) + { 'Authorization' => "Bearer #{config.sts_token(user_identifier: icn)}" } + end + + def normalize_response_body(response_body) + response_body.deep_transform_keys { |key| key.underscore.to_sym } + end + end + end +end diff --git a/spec/lib/mhv/account_creation/service_spec.rb b/spec/lib/mhv/account_creation/service_spec.rb new file mode 100644 index 00000000000..46cc6d01347 --- /dev/null +++ b/spec/lib/mhv/account_creation/service_spec.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'mhv/account_creation/service' + +describe MHV::AccountCreation::Service do + describe '#create_account' do + subject { described_class.new.create_account(icn:, email:, tou_occurred_at:) } + + let(:icn) { '10101V964144' } + let(:email) { 'some-email@email.com' } + let(:tou_status) { 'accepted' } + let(:tou_version) { 'v1' } + let(:tou_occurred_at) { Time.current } + let(:log_prefix) { '[MHV][AccountCreation][Service]' } + + before do + allow(Rails.logger).to receive(:info) + allow(Rails.logger).to receive(:error) + allow_any_instance_of(SignInService::Sts).to receive(:base_url).and_return('https://staging-api.va.gov') + end + + context 'when the response is successful' do + let(:expected_log_message) { "#{log_prefix} create_account success" } + let(:expected_log_payload) { { icn: } } + let(:expected_response_body) do + { + mhv_userprofileid: '12345678', + is_premium: true, + is_champ_va: true, + is_patient: true, + is_sm_account_created: true, + message: 'Existing MHV Account Found for ICN' + } + end + + it 'logs the create account request' do + VCR.use_cassette('mhv/account_creation/account_creation_service_200_response') do + subject + expect(Rails.logger).to have_received(:info).with(expected_log_message, expected_log_payload) + end + end + + it 'returns the expected response' do + VCR.use_cassette('mhv/account_creation/account_creation_service_200_response') do + expect(subject).to eq(expected_response_body) + end + end + end + + context 'when the response is a client error' do + let(:expected_log_message) { "#{log_prefix} create_account client_error" } + let(:expected_log_payload) do + { + body: { errorCode: 812, message: 'Required ICN field is missing or invalid in the JWT' }.as_json, + error_message: 'the server responded with status 400', + icn: + } + end + + it 'logs the client error' do + VCR.use_cassette('mhv/account_creation/account_creation_service_400_response') do + subject + expect(Rails.logger).to have_received(:error).with(expected_log_message, expected_log_payload) + end + end + end + + context 'when the response is a parsing error' do + let(:expected_log_message) { "#{log_prefix} create_account parsing_error" } + let(:expected_log_payload) do + { + body: 'Internal Server Error', + error_message: "unexpected token at 'Internal Server Error'", + icn: + } + end + + it 'logs the parsing error' do + VCR.use_cassette('mhv/account_creation/account_creation_service_500_response') do + subject + expect(Rails.logger).to have_received(:error).with(expected_log_message, expected_log_payload) + end + end + end + + context 'when the STS token request fails' do + let(:expected_log_message) { "#{log_prefix} sts token request failed" } + let(:expected_log_payload) { { user_identifier: icn, error_message: 'Service account config not found' } } + + it 'logs the STS token request failure' do + VCR.use_cassette('sign_in_service/sts/sts_token_400_response') do + subject + expect(Rails.logger).to have_received(:error).with(expected_log_message, expected_log_payload) + end + end + end + end +end diff --git a/spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_200_response.yml b/spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_200_response.yml new file mode 100644 index 00000000000..a62d49512bd --- /dev/null +++ b/spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_200_response.yml @@ -0,0 +1,109 @@ + +http_interactions: +- request: + method: post + uri: https://staging-api.va.gov/v0/sign_in/token + body: + encoding: UTF-8 + string: '{"grant_type":"urn:ietf:params:oauth:grant-type:jwt-bearer","assertion":"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJzdWIiOiIxMDEwMVY5NjQxNDQiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvdjAvc2lnbl9pbi90b2tlbiIsImlhdCI6MTcyNDg5ODY2MiwiZXhwIjoxNzI0ODk4OTYyLCJqdGkiOiI3N2NhZmRlNTdkZWI4OTdkY2Y3Yjg2YmM1YjNjMDZmNyIsInNjb3BlcyI6WyJodHRwczovL21odi1pbnRiLWFwaS5teWhlYWx0aC52YS5nb3YvbWh2YXBpL3YxL3VzZXJtZ210L2FjY291bnQtc2VydmljZS9hY2NvdW50Il0sInNlcnZpY2VfYWNjb3VudF9pZCI6ImMzNGI4NmYyMTMwZmYzY2Q0YjFkMzA5YmMwOWQ4NzQwIn0.g0ZaRIXyYLLUgYRn8yJqdT2BHrRDgXLZIVOjsdYbuqzqWEKEMXZJQsQPseM903XXM5vZ6LMoXC48uU19ZZs9Yz-QBbm8S4s9N6EayLP0ZyigUhtYIJI0FIDdkUrZSn3q3f7s0t9lNL-SlxFRUmwU-vpJrlT0MvkQ571d626TDKvaLl44reCsNoY3Kwk1xgbZHqDj0x3oGB-_YRFG5EkvPHrrXMYxlV0N8MQEAeZcW_AcM0CIZKI54slRyUCiLUurf3EzDFp0TPn9h7IN8x3XwylJu6FB89pTVR9vHir06iL_egxtkK0p0C9G5um-Cmi_Sk36eD-tyNr_SoO50eKQ8FZ4Lump-UhzxCuAbbCpjLlmnykSXbwwkl41t5IICRxKz5_-zTfyhfRqpwrM8hjbdxWDOpbpgN5MLB8EX6GmJo1UGSnhu86y-9hWGm3RMLItR_uuXyx6N-CN-Wb8LVWw00elikhj_dyPLARkiYmbyYu-h0cuW38M1FLgzlA4nTPx0831EAkM75Y_gPQd6mKrZpgcRVA3nQgazYeykYW7cmA4oLJ5S0sWwVX6c5WjpMEJ8KiccUf7-IHXi4_8UKHBmK_HXEk0dTWYc3cvmtlu_eF7oiXt-ZL61pFWBjzAeu18JN0QyJj4nKtr-J9kDhbVEjbuqm_CqPd6ionzRJgGIRE"}' + headers: + User-Agent: + - "" + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - '0' + X-Content-Type-Options: + - nosniff + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Git-Sha: + - MISSING_GIT_REVISION + X-Github-Repository: + - https://github.com/department-of-veterans-affairs/vets-api + Content-Type: + - application/json; charset=utf-8 + Etag: + - W/"8f1609ce8a01221b218e183b578a7857" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - 78e70a5a-0576-4343-a6c3-a44aae71c000 + X-Runtime: + - '0.138483' + Vary: + - Accept, Origin + Content-Length: + - '844' + body: + encoding: UTF-8 + string: '{"data":{"access_token":"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJ2YS5nb3Ygc2lnbiBpbiIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMCIsImp0aSI6ImNkYzNmN2JlLTQ5MTMtNGQxZC04ZTI4LTRhNmJkZmJiYjYxOCIsInN1YiI6IjEwMTAxVjk2NDE0NCIsImV4cCI6MTcyNDg5ODk2MiwiaWF0IjoxNzI0ODk4NjYyLCJ2ZXJzaW9uIjoiVjAiLCJzY29wZXMiOlsiaHR0cHM6Ly9taHYtaW50Yi1hcGkubXloZWFsdGgudmEuZ292L21odmFwaS92MS91c2VybWdtdC9hY2NvdW50LXNlcnZpY2UvYWNjb3VudCJdLCJzZXJ2aWNlX2FjY291bnRfaWQiOiJjMzRiODZmMjEzMGZmM2NkNGIxZDMwOWJjMDlkODc0MCIsInVzZXJfYXR0cmlidXRlcyI6e319.Ld_KvqHnm2HDuZE0sO5LAbILSA9ccPahuZXBDbvnDI2Vl9n1TPUovCo7V1iQr50T_kttgZtE4fz5FIs8wpbsTfC2G2CtT2TEaT6wKODBAXb2Fdyskv7lkN29K_PlhW8_HJIFiaSpxIcg2AQxvByTnfAvOZ4qWjBu16OXqnJjC4koLpyL-tcj0yO9tMzd_Cup8irdmLcDruqIjfkG1sIyuFHTAKThBX0_3oDs5eNSEM20Iwd3pxylfP8RmN67WrMo38oH53skJNg2BorfsLwebcr3JjLmJQJcRR7fypovBqXSMjDiXLMOkg6NTr23XfOmxmnEbJLx936U1uOuWpg4hA"}}' + recorded_at: Thu, 29 Aug 2024 02:31:02 GMT +- request: + method: post + uri: "https://mhv-intb-api.myhealth.va.gov/mhvapi/v1/usermgmt/account-service/account" + body: + encoding: UTF-8 + string: '{"icn":"10101V964144","email":"some-email@email.com","vaTermsOfUseStatus":"accepted","vaTermsOfUseDateTime":"2017-07-26T19:56:07Z","vaTermsOfUseRevision":"3","vaTermsOfUseLegalVersion":"1.0","vaTermsOfUseDocTitle":"VA Enterprise Terms of Use"}' + headers: + Authorization: + - Bearer eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJ2YS5nb3Ygc2lnbiBpbiIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMCIsImp0aSI6ImNkYzNmN2JlLTQ5MTMtNGQxZC04ZTI4LTRhNmJkZmJiYjYxOCIsInN1YiI6IjEwMTAxVjk2NDE0NCIsImV4cCI6MTcyNDg5ODk2MiwiaWF0IjoxNzI0ODk4NjYyLCJ2ZXJzaW9uIjoiVjAiLCJzY29wZXMiOlsiaHR0cHM6Ly9taHYtaW50Yi1hcGkubXloZWFsdGgudmEuZ292L21odmFwaS92MS91c2VybWdtdC9hY2NvdW50LXNlcnZpY2UvYWNjb3VudCJdLCJzZXJ2aWNlX2FjY291bnRfaWQiOiJjMzRiODZmMjEzMGZmM2NkNGIxZDMwOWJjMDlkODc0MCIsInVzZXJfYXR0cmlidXRlcyI6e319.Ld_KvqHnm2HDuZE0sO5LAbILSA9ccPahuZXBDbvnDI2Vl9n1TPUovCo7V1iQr50T_kttgZtE4fz5FIs8wpbsTfC2G2CtT2TEaT6wKODBAXb2Fdyskv7lkN29K_PlhW8_HJIFiaSpxIcg2AQxvByTnfAvOZ4qWjBu16OXqnJjC4koLpyL-tcj0yO9tMzd_Cup8irdmLcDruqIjfkG1sIyuFHTAKThBX0_3oDs5eNSEM20Iwd3pxylfP8RmN67WrMo38oH53skJNg2BorfsLwebcr3JjLmJQJcRR7fypovBqXSMjDiXLMOkg6NTr23XfOmxmnEbJLx936U1uOuWpg4hA + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Vets.gov Agent + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json; charset=utf-8 + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Runtime: + - '0.026178' + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + Vary: + - Accept-Encoding + Expires: + - Wed, 28 Aug 2024 19:56:07 GMT + Cache-Control: + - max-age=0, no-cache, no-store + Pragma: + - no-cache + Date: + - Wed, 28 Aug 2024 19:56:07 GMT + Content-Length: + - '14658' + body: + encoding: UTF-8 + string: '{"mhv_userprofileid":"12345678","isPremium":true,"isChampVA":true,"isPatient":true,"isSMAccountCreated":true,"message":"Existing MHV Account Found for ICN"}' + recorded_at: Wed, 28 Aug 2024 19:56:07 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_400_response.yml b/spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_400_response.yml new file mode 100644 index 00000000000..ed2df4f73ef --- /dev/null +++ b/spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_400_response.yml @@ -0,0 +1,109 @@ + +http_interactions: +- request: + method: post + uri: https://staging-api.va.gov/v0/sign_in/token + body: + encoding: UTF-8 + string: '{"grant_type":"urn:ietf:params:oauth:grant-type:jwt-bearer","assertion":"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJzdWIiOiIxMDEwMVY5NjQxNDQiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvdjAvc2lnbl9pbi90b2tlbiIsImlhdCI6MTcyNDg5ODY2MiwiZXhwIjoxNzI0ODk4OTYyLCJqdGkiOiI3N2NhZmRlNTdkZWI4OTdkY2Y3Yjg2YmM1YjNjMDZmNyIsInNjb3BlcyI6WyJodHRwczovL21odi1pbnRiLWFwaS5teWhlYWx0aC52YS5nb3YvbWh2YXBpL3YxL3VzZXJtZ210L2FjY291bnQtc2VydmljZS9hY2NvdW50Il0sInNlcnZpY2VfYWNjb3VudF9pZCI6ImMzNGI4NmYyMTMwZmYzY2Q0YjFkMzA5YmMwOWQ4NzQwIn0.g0ZaRIXyYLLUgYRn8yJqdT2BHrRDgXLZIVOjsdYbuqzqWEKEMXZJQsQPseM903XXM5vZ6LMoXC48uU19ZZs9Yz-QBbm8S4s9N6EayLP0ZyigUhtYIJI0FIDdkUrZSn3q3f7s0t9lNL-SlxFRUmwU-vpJrlT0MvkQ571d626TDKvaLl44reCsNoY3Kwk1xgbZHqDj0x3oGB-_YRFG5EkvPHrrXMYxlV0N8MQEAeZcW_AcM0CIZKI54slRyUCiLUurf3EzDFp0TPn9h7IN8x3XwylJu6FB89pTVR9vHir06iL_egxtkK0p0C9G5um-Cmi_Sk36eD-tyNr_SoO50eKQ8FZ4Lump-UhzxCuAbbCpjLlmnykSXbwwkl41t5IICRxKz5_-zTfyhfRqpwrM8hjbdxWDOpbpgN5MLB8EX6GmJo1UGSnhu86y-9hWGm3RMLItR_uuXyx6N-CN-Wb8LVWw00elikhj_dyPLARkiYmbyYu-h0cuW38M1FLgzlA4nTPx0831EAkM75Y_gPQd6mKrZpgcRVA3nQgazYeykYW7cmA4oLJ5S0sWwVX6c5WjpMEJ8KiccUf7-IHXi4_8UKHBmK_HXEk0dTWYc3cvmtlu_eF7oiXt-ZL61pFWBjzAeu18JN0QyJj4nKtr-J9kDhbVEjbuqm_CqPd6ionzRJgGIRE"}' + headers: + User-Agent: + - "" + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - '0' + X-Content-Type-Options: + - nosniff + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Git-Sha: + - MISSING_GIT_REVISION + X-Github-Repository: + - https://github.com/department-of-veterans-affairs/vets-api + Content-Type: + - application/json; charset=utf-8 + Etag: + - W/"8f1609ce8a01221b218e183b578a7857" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - 78e70a5a-0576-4343-a6c3-a44aae71c000 + X-Runtime: + - '0.138483' + Vary: + - Accept, Origin + Content-Length: + - '844' + body: + encoding: UTF-8 + string: '{"data":{"access_token":"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJ2YS5nb3Ygc2lnbiBpbiIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMCIsImp0aSI6ImNkYzNmN2JlLTQ5MTMtNGQxZC04ZTI4LTRhNmJkZmJiYjYxOCIsInN1YiI6IjEwMTAxVjk2NDE0NCIsImV4cCI6MTcyNDg5ODk2MiwiaWF0IjoxNzI0ODk4NjYyLCJ2ZXJzaW9uIjoiVjAiLCJzY29wZXMiOlsiaHR0cHM6Ly9taHYtaW50Yi1hcGkubXloZWFsdGgudmEuZ292L21odmFwaS92MS91c2VybWdtdC9hY2NvdW50LXNlcnZpY2UvYWNjb3VudCJdLCJzZXJ2aWNlX2FjY291bnRfaWQiOiJjMzRiODZmMjEzMGZmM2NkNGIxZDMwOWJjMDlkODc0MCIsInVzZXJfYXR0cmlidXRlcyI6e319.Ld_KvqHnm2HDuZE0sO5LAbILSA9ccPahuZXBDbvnDI2Vl9n1TPUovCo7V1iQr50T_kttgZtE4fz5FIs8wpbsTfC2G2CtT2TEaT6wKODBAXb2Fdyskv7lkN29K_PlhW8_HJIFiaSpxIcg2AQxvByTnfAvOZ4qWjBu16OXqnJjC4koLpyL-tcj0yO9tMzd_Cup8irdmLcDruqIjfkG1sIyuFHTAKThBX0_3oDs5eNSEM20Iwd3pxylfP8RmN67WrMo38oH53skJNg2BorfsLwebcr3JjLmJQJcRR7fypovBqXSMjDiXLMOkg6NTr23XfOmxmnEbJLx936U1uOuWpg4hA"}}' + recorded_at: Thu, 29 Aug 2024 02:31:02 GMT +- request: + method: post + uri: "https://mhv-intb-api.myhealth.va.gov/mhvapi/v1/usermgmt/account-service/account" + body: + encoding: UTF-8 + string: '{"icn":"10101V964144","email":"some-email@email.com","vaTermsOfUseStatus":"accepted","vaTermsOfUseDateTime":"2017-07-26T19:56:07Z","vaTermsOfUseRevision":"3","vaTermsOfUseLegalVersion":"1.0","vaTermsOfUseDocTitle":"VA Enterprise Terms of Use"}' + headers: + Authorization: + - Bearer eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJ2YS5nb3Ygc2lnbiBpbiIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMCIsImp0aSI6ImNkYzNmN2JlLTQ5MTMtNGQxZC04ZTI4LTRhNmJkZmJiYjYxOCIsInN1YiI6IjEwMTAxVjk2NDE0NCIsImV4cCI6MTcyNDg5ODk2MiwiaWF0IjoxNzI0ODk4NjYyLCJ2ZXJzaW9uIjoiVjAiLCJzY29wZXMiOlsiaHR0cHM6Ly9taHYtaW50Yi1hcGkubXloZWFsdGgudmEuZ292L21odmFwaS92MS91c2VybWdtdC9hY2NvdW50LXNlcnZpY2UvYWNjb3VudCJdLCJzZXJ2aWNlX2FjY291bnRfaWQiOiJjMzRiODZmMjEzMGZmM2NkNGIxZDMwOWJjMDlkODc0MCIsInVzZXJfYXR0cmlidXRlcyI6e319.Ld_KvqHnm2HDuZE0sO5LAbILSA9ccPahuZXBDbvnDI2Vl9n1TPUovCo7V1iQr50T_kttgZtE4fz5FIs8wpbsTfC2G2CtT2TEaT6wKODBAXb2Fdyskv7lkN29K_PlhW8_HJIFiaSpxIcg2AQxvByTnfAvOZ4qWjBu16OXqnJjC4koLpyL-tcj0yO9tMzd_Cup8irdmLcDruqIjfkG1sIyuFHTAKThBX0_3oDs5eNSEM20Iwd3pxylfP8RmN67WrMo38oH53skJNg2BorfsLwebcr3JjLmJQJcRR7fypovBqXSMjDiXLMOkg6NTr23XfOmxmnEbJLx936U1uOuWpg4hA + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Vets.gov Agent + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 400 + message: Bad Request + headers: + Content-Type: + - application/json; charset=utf-8 + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Runtime: + - '0.026178' + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + Vary: + - Accept-Encoding + Expires: + - Wed, 28 Aug 2024 19:56:07 GMT + Cache-Control: + - max-age=0, no-cache, no-store + Pragma: + - no-cache + Date: + - Wed, 28 Aug 2024 19:56:07 GMT + Content-Length: + - '14658' + body: + encoding: UTF-8 + string: '{"errorCode":812,"message":"Required ICN field is missing or invalid in the JWT"}' + recorded_at: Wed, 28 Aug 2024 19:56:07 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_500_response.yml b/spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_500_response.yml new file mode 100644 index 00000000000..4e66d5f6412 --- /dev/null +++ b/spec/support/vcr_cassettes/mhv/account_creation/account_creation_service_500_response.yml @@ -0,0 +1,109 @@ + +http_interactions: +- request: + method: post + uri: https://staging-api.va.gov/v0/sign_in/token + body: + encoding: UTF-8 + string: '{"grant_type":"urn:ietf:params:oauth:grant-type:jwt-bearer","assertion":"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJzdWIiOiIxMDEwMVY5NjQxNDQiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvdjAvc2lnbl9pbi90b2tlbiIsImlhdCI6MTcyNDg5ODY2MiwiZXhwIjoxNzI0ODk4OTYyLCJqdGkiOiI3N2NhZmRlNTdkZWI4OTdkY2Y3Yjg2YmM1YjNjMDZmNyIsInNjb3BlcyI6WyJodHRwczovL21odi1pbnRiLWFwaS5teWhlYWx0aC52YS5nb3YvbWh2YXBpL3YxL3VzZXJtZ210L2FjY291bnQtc2VydmljZS9hY2NvdW50Il0sInNlcnZpY2VfYWNjb3VudF9pZCI6ImMzNGI4NmYyMTMwZmYzY2Q0YjFkMzA5YmMwOWQ4NzQwIn0.g0ZaRIXyYLLUgYRn8yJqdT2BHrRDgXLZIVOjsdYbuqzqWEKEMXZJQsQPseM903XXM5vZ6LMoXC48uU19ZZs9Yz-QBbm8S4s9N6EayLP0ZyigUhtYIJI0FIDdkUrZSn3q3f7s0t9lNL-SlxFRUmwU-vpJrlT0MvkQ571d626TDKvaLl44reCsNoY3Kwk1xgbZHqDj0x3oGB-_YRFG5EkvPHrrXMYxlV0N8MQEAeZcW_AcM0CIZKI54slRyUCiLUurf3EzDFp0TPn9h7IN8x3XwylJu6FB89pTVR9vHir06iL_egxtkK0p0C9G5um-Cmi_Sk36eD-tyNr_SoO50eKQ8FZ4Lump-UhzxCuAbbCpjLlmnykSXbwwkl41t5IICRxKz5_-zTfyhfRqpwrM8hjbdxWDOpbpgN5MLB8EX6GmJo1UGSnhu86y-9hWGm3RMLItR_uuXyx6N-CN-Wb8LVWw00elikhj_dyPLARkiYmbyYu-h0cuW38M1FLgzlA4nTPx0831EAkM75Y_gPQd6mKrZpgcRVA3nQgazYeykYW7cmA4oLJ5S0sWwVX6c5WjpMEJ8KiccUf7-IHXi4_8UKHBmK_HXEk0dTWYc3cvmtlu_eF7oiXt-ZL61pFWBjzAeu18JN0QyJj4nKtr-J9kDhbVEjbuqm_CqPd6ionzRJgGIRE"}' + headers: + User-Agent: + - "" + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - '0' + X-Content-Type-Options: + - nosniff + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Git-Sha: + - MISSING_GIT_REVISION + X-Github-Repository: + - https://github.com/department-of-veterans-affairs/vets-api + Content-Type: + - application/json; charset=utf-8 + Etag: + - W/"8f1609ce8a01221b218e183b578a7857" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - 78e70a5a-0576-4343-a6c3-a44aae71c000 + X-Runtime: + - '0.138483' + Vary: + - Accept, Origin + Content-Length: + - '844' + body: + encoding: UTF-8 + string: '{"data":{"access_token":"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJ2YS5nb3Ygc2lnbiBpbiIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMCIsImp0aSI6ImNkYzNmN2JlLTQ5MTMtNGQxZC04ZTI4LTRhNmJkZmJiYjYxOCIsInN1YiI6IjEwMTAxVjk2NDE0NCIsImV4cCI6MTcyNDg5ODk2MiwiaWF0IjoxNzI0ODk4NjYyLCJ2ZXJzaW9uIjoiVjAiLCJzY29wZXMiOlsiaHR0cHM6Ly9taHYtaW50Yi1hcGkubXloZWFsdGgudmEuZ292L21odmFwaS92MS91c2VybWdtdC9hY2NvdW50LXNlcnZpY2UvYWNjb3VudCJdLCJzZXJ2aWNlX2FjY291bnRfaWQiOiJjMzRiODZmMjEzMGZmM2NkNGIxZDMwOWJjMDlkODc0MCIsInVzZXJfYXR0cmlidXRlcyI6e319.Ld_KvqHnm2HDuZE0sO5LAbILSA9ccPahuZXBDbvnDI2Vl9n1TPUovCo7V1iQr50T_kttgZtE4fz5FIs8wpbsTfC2G2CtT2TEaT6wKODBAXb2Fdyskv7lkN29K_PlhW8_HJIFiaSpxIcg2AQxvByTnfAvOZ4qWjBu16OXqnJjC4koLpyL-tcj0yO9tMzd_Cup8irdmLcDruqIjfkG1sIyuFHTAKThBX0_3oDs5eNSEM20Iwd3pxylfP8RmN67WrMo38oH53skJNg2BorfsLwebcr3JjLmJQJcRR7fypovBqXSMjDiXLMOkg6NTr23XfOmxmnEbJLx936U1uOuWpg4hA"}}' + recorded_at: Thu, 29 Aug 2024 02:31:02 GMT +- request: + method: post + uri: "https://mhv-intb-api.myhealth.va.gov/mhvapi/v1/usermgmt/account-service/account" + body: + encoding: UTF-8 + string: '{"icn":"10101V964144","email":"some-email@email.com","vaTermsOfUseStatus":"accepted","vaTermsOfUseDateTime":"2017-07-26T19:56:07Z","vaTermsOfUseRevision":"3","vaTermsOfUseLegalVersion":"1.0","vaTermsOfUseDocTitle":"VA Enterprise Terms of Use"}' + headers: + Authorization: + - Bearer eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJ2YS5nb3Ygc2lnbiBpbiIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMCIsImp0aSI6ImNkYzNmN2JlLTQ5MTMtNGQxZC04ZTI4LTRhNmJkZmJiYjYxOCIsInN1YiI6IjEwMTAxVjk2NDE0NCIsImV4cCI6MTcyNDg5ODk2MiwiaWF0IjoxNzI0ODk4NjYyLCJ2ZXJzaW9uIjoiVjAiLCJzY29wZXMiOlsiaHR0cHM6Ly9taHYtaW50Yi1hcGkubXloZWFsdGgudmEuZ292L21odmFwaS92MS91c2VybWdtdC9hY2NvdW50LXNlcnZpY2UvYWNjb3VudCJdLCJzZXJ2aWNlX2FjY291bnRfaWQiOiJjMzRiODZmMjEzMGZmM2NkNGIxZDMwOWJjMDlkODc0MCIsInVzZXJfYXR0cmlidXRlcyI6e319.Ld_KvqHnm2HDuZE0sO5LAbILSA9ccPahuZXBDbvnDI2Vl9n1TPUovCo7V1iQr50T_kttgZtE4fz5FIs8wpbsTfC2G2CtT2TEaT6wKODBAXb2Fdyskv7lkN29K_PlhW8_HJIFiaSpxIcg2AQxvByTnfAvOZ4qWjBu16OXqnJjC4koLpyL-tcj0yO9tMzd_Cup8irdmLcDruqIjfkG1sIyuFHTAKThBX0_3oDs5eNSEM20Iwd3pxylfP8RmN67WrMo38oH53skJNg2BorfsLwebcr3JjLmJQJcRR7fypovBqXSMjDiXLMOkg6NTr23XfOmxmnEbJLx936U1uOuWpg4hA + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Vets.gov Agent + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 500 + message: Internal Server Error + headers: + Content-Type: + - application/json; charset=utf-8 + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Runtime: + - '0.026178' + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + Vary: + - Accept-Encoding + Expires: + - Wed, 28 Aug 2024 19:56:07 GMT + Cache-Control: + - max-age=0, no-cache, no-store + Pragma: + - no-cache + Date: + - Wed, 28 Aug 2024 19:56:07 GMT + Content-Length: + - '14658' + body: + encoding: UTF-8 + string: Internal Server Error + recorded_at: Wed, 28 Aug 2024 19:56:07 GMT +recorded_with: VCR 6.1.0 diff --git a/spec/support/vcr_cassettes/sign_in_service/sts/sts_token_400_response.yml b/spec/support/vcr_cassettes/sign_in_service/sts/sts_token_400_response.yml new file mode 100644 index 00000000000..c68f7c20ac3 --- /dev/null +++ b/spec/support/vcr_cassettes/sign_in_service/sts/sts_token_400_response.yml @@ -0,0 +1,53 @@ +--- +http_interactions: +- request: + method: post + uri: https://staging-api.va.gov/v0/sign_in/token + body: + encoding: UTF-8 + string: '{"grant_type":"urn:ietf:params:oauth:grant-type:jwt-bearer","assertion":"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ0ZXN0QGVtYWlsLmNvbSIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMC92MC9zaWduX2luL3Rva2VuIiwiaWF0IjoxNzIxMjQ1MjU2LCJleHAiOjE3MjEyNDU1NTYsImp0aSI6IjJmYjFiYjc4NzFlNmYwYTJlNTkxYzFiYzQyNjQxMWVmIiwic2NvcGVzIjpbImh0dHA6Ly9sb2NhbGhvc3Q6MzAwMC9zaWduX2luL2NsaWVudF9jb25maWdzIl0sInNlcnZpY2VfYWNjb3VudF9pZCI6ImludmFsaWQiLCJ1c2VyX2F0dHJpYnV0ZXMiOnsiaWNuIjoiMTIzNDU2In19.T6IJFzaWd7Q3IM8bJqCLm5jWhb49kc_Y6iFJtkIHFnYaDUbxeGB-n_ldGygtO76wsmXOp8fuw1hfupXlchIKCUGsIQFP8l7nhoGkzCsAdzXxll-zmNGhSq8KChNwfc3MsjgBh9IIrEvek1Rr24nUeAh2EVuwz8KPN95ENnAWbNLSsSq23Qw_jfubTtjYGeCprfkvyuia2QyBkLyPSRotFz7cfF2naL-uVnTMLayBA-JEnYeLvH3sCPqNChvmWL7A_9VRa4_2eN21TnnuCptYXjp30f0LgcXg0PwFh-msTUshnRSh0T5emUNmG1EYOTbM_-T62jmdkCOCpc3agTAkqA"}' + headers: + User-Agent: + - Faraday v2.10.0 + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 400 + message: Bad Request + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - '0' + X-Content-Type-Options: + - nosniff + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + X-Git-Sha: + - MISSING_GIT_REVISION + X-Github-Repository: + - https://github.com/department-of-veterans-affairs/vets-api + Content-Type: + - application/json; charset=utf-8 + Cache-Control: + - no-cache + X-Request-Id: + - 70899a4b-2c90-46ce-a6aa-93e6ae7ecc08 + X-Runtime: + - '0.034253' + Vary: + - Accept, Origin + Content-Length: + - '45' + body: + encoding: UTF-8 + string: '{"errors":"Service account config not found"}' + recorded_at: Wed, 17 Jul 2024 19:40:56 GMT +recorded_with: VCR 6.2.0 From 8867120a7f20e51a96447b0bfd3cf5e6310c03a0 Mon Sep 17 00:00:00 2001 From: Ryan Johnson <72466113+rjohnson2011@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:57:56 -0400 Subject: [PATCH 07/31] Bug fix: Include hidden files (#18286) * Include hidden files * Update coverage report --- .github/workflows/code_checks.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/code_checks.yml b/.github/workflows/code_checks.yml index 45442dd21f7..e9cacbcc77e 100644 --- a/.github/workflows/code_checks.yml +++ b/.github/workflows/code_checks.yml @@ -150,6 +150,7 @@ jobs: with: name: Coverage Report path: coverage + include-hidden-files: true - name: Upload Test Results uses: actions/upload-artifact@v4 From 904b66215d7fccf33011410351159dfc85a92483 Mon Sep 17 00:00:00 2001 From: Austin Covrig Date: Tue, 3 Sep 2024 17:13:25 -0400 Subject: [PATCH 08/31] Break out PDF 526v2 test (#18135) * Break out PDF 526v2 test * Remove duplicate tests * Rename spec * Consolidate structs * Fix typo in controller * Remove DuplicateMethodCall --- .../disability_compensation_controller.rb | 2 +- ...disability_compensation_pdf_mapper_spec.rb | 4 +- .../spec/requests/v2/veterans/526_spec.rb | 275 +++++------------- 3 files changed, 79 insertions(+), 202 deletions(-) diff --git a/modules/claims_api/app/controllers/claims_api/v2/veterans/disability_compensation_controller.rb b/modules/claims_api/app/controllers/claims_api/v2/veterans/disability_compensation_controller.rb index 62568953fca..d3b8156596c 100644 --- a/modules/claims_api/app/controllers/claims_api/v2/veterans/disability_compensation_controller.rb +++ b/modules/claims_api/app/controllers/claims_api/v2/veterans/disability_compensation_controller.rb @@ -165,7 +165,7 @@ def process_claim(auto_claim) # Only value required by background jobs that is missing in headers is middle name def veteran_middle_initial - @target_veteran.middle_name ? @target_veteran.middle_name[0].uppercase : '' + target_veteran.middle_name&.first&.upcase || '' end def flashes diff --git a/modules/claims_api/spec/lib/claims_api/v2/disability_compensation_pdf_mapper_spec.rb b/modules/claims_api/spec/lib/claims_api/v2/disability_compensation_pdf_mapper_spec.rb index 21ae81922f1..08498f10eb5 100644 --- a/modules/claims_api/spec/lib/claims_api/v2/disability_compensation_pdf_mapper_spec.rb +++ b/modules/claims_api/spec/lib/claims_api/v2/disability_compensation_pdf_mapper_spec.rb @@ -213,13 +213,13 @@ context 'international address' do it 'maps the address to overflow' do form_attributes['veteranIdentification']['mailingAddress']['country'] = 'Afghanistan' - form_attributes['veteranIdentification']['mailingAddress']['internationalPostalCode'] = 'asdf1234' + form_attributes['veteranIdentification']['mailingAddress']['internationalPostalCode'] = '151-8557' form_attributes['veteranIdentification']['mailingAddress']['zipFirstFive'] = nil form_attributes['veteranIdentification']['mailingAddress']['zipLastFour'] = nil mapper.map_claim zip = pdf_data[:data][:attributes][:identificationInformation][:mailingAddress][:zip] - expect(zip).to eq('asdf1234') + expect(zip).to eq('151-8557') end end end diff --git a/modules/claims_api/spec/requests/v2/veterans/526_spec.rb b/modules/claims_api/spec/requests/v2/veterans/526_spec.rb index aa81a229147..b3884e1e512 100644 --- a/modules/claims_api/spec/requests/v2/veterans/526_spec.rb +++ b/modules/claims_api/spec/requests/v2/veterans/526_spec.rb @@ -6,45 +6,12 @@ RSpec.describe 'ClaimsApi::V2::Veterans::526', type: :request do let(:scopes) { %w[claim.write claim.read] } let(:claim_date) { Time.find_zone!('Central Time (US & Canada)').today } - let(:no_first_name_target_veteran) do - OpenStruct.new( - icn: '1012832025V743496', - first_name: '', - last_name: 'Ford', - birth_date: '19630211', - loa: { current: 3, highest: 3 }, - edipi: nil, - ssn: '796043735', - participant_id: '600061742', - mpi: OpenStruct.new( - icn: '1012832025V743496', - profile: OpenStruct.new(ssn: '796043735') - ) - ) - end - - let(:no_last_name_target_veteran) do + let(:target_veteran) do OpenStruct.new( icn: '1012832025V743496', first_name: 'Wesley', - last_name: '', - birth_date: '19630211', - loa: { current: 3, highest: 3 }, - edipi: nil, - ssn: '796043735', - participant_id: '600061742', - mpi: OpenStruct.new( - icn: '1012832025V743496', - profile: OpenStruct.new(ssn: '796043735') - ) - ) - end - - let(:no_first_last_name_target_veteran) do - OpenStruct.new( - icn: '1012832025V743496', - first_name: '', - last_name: '', + last_name: 'Ford', + middle_name: 'John', birth_date: '19630211', loa: { current: 3, highest: 3 }, edipi: nil, @@ -148,8 +115,9 @@ context 'without the first name present' do it 'does not allow the submit to occur' do mock_ccg(scopes) do |auth_header| + target_veteran.first_name = '' allow_any_instance_of(ClaimsApi::V2::ApplicationController) - .to receive(:target_veteran).and_return(no_first_name_target_veteran) + .to receive(:target_veteran).and_return(target_veteran) post submit_path, params: data, headers: auth_header expect(response).to have_http_status(:unprocessable_entity) expect(response.parsed_body['errors'][0]['detail']).to eq('Missing first name') @@ -160,8 +128,9 @@ context 'without the last name present' do it 'does not allow the submit to occur' do mock_ccg(scopes) do |auth_header| + target_veteran.last_name = '' allow_any_instance_of(ClaimsApi::V2::ApplicationController) - .to receive(:target_veteran).and_return(no_last_name_target_veteran) + .to receive(:target_veteran).and_return(target_veteran) post submit_path, params: data, headers: auth_header expect(response).to have_http_status(:unprocessable_entity) expect(response.parsed_body['errors'][0]['detail']).to eq('Missing last name') @@ -4498,167 +4467,54 @@ def update_json_and_submit(updated_json_lambda) end end end - end - - describe 'POST #submit not using md5 lookup' do - let(:anticipated_separation_date) { 2.days.from_now.strftime('%Y-%m-%d') } - let(:active_duty_end_date) { 2.days.from_now.strftime('%Y-%m-%d') } - let(:data) do - temp = Rails.root.join('modules', 'claims_api', 'spec', 'fixtures', 'v2', 'veterans', 'disability_compensation', - 'form_526_json_api.json').read - temp = JSON.parse(temp) - attributes = temp['data']['attributes'] - attributes['serviceInformation']['federalActivation']['anticipatedSeparationDate'] = anticipated_separation_date - attributes['serviceInformation']['servicePeriods'][-1]['activeDutyEndDate'] = active_duty_end_date - - temp.to_json - end - let(:schema) { Rails.root.join('modules', 'claims_api', 'config', 'schemas', 'v2', '526.json').read } - let(:veteran_id) { '1013062086V794840' } - let(:submit_path) { "/services/claims/v2/veterans/#{veteran_id}/526" } - - it 'creates a new claim if duplicate submit occurs (does not use md5 lookup)' do - mock_ccg(scopes) do |auth_header| - VCR.use_cassette('claims_api/disability_comp') do - json = JSON.parse(data) - post submit_path, params: json.to_json, headers: auth_header - expect(response).to have_http_status(:accepted) - first_submit_parsed = JSON.parse(response.body) - @original_id = first_submit_parsed['data']['id'] - end - end - mock_ccg(scopes) do |auth_header| - VCR.use_cassette('claims_api/disability_comp') do - json = JSON.parse(data) - post submit_path, params: json.to_json, headers: auth_header - expect(response).to have_http_status(:accepted) - duplicate_submit_parsed = JSON.parse(response.body) - duplicate_id = duplicate_submit_parsed['data']['id'] - expect(@original_id).not_to eq(duplicate_id) - end - end - end - end - - describe 'POST #generatePDF/minimum-validations', vcr: 'claims_api/disability_comp' do - let(:anticipated_separation_date) { 2.days.from_now.strftime('%Y-%m-%d') } - let(:active_duty_end_date) { 2.days.from_now.strftime('%Y-%m-%d') } - let(:data) do - temp = Rails.root.join('modules', 'claims_api', 'spec', 'fixtures', 'v2', 'veterans', - 'disability_compensation', 'form_526_generate_pdf_json_api.json').read - temp = JSON.parse(temp) - attributes = temp['data']['attributes'] - attributes['serviceInformation']['federalActivation']['anticipatedSeparationDate'] = anticipated_separation_date - attributes['serviceInformation']['servicePeriods'][-1]['activeDutyEndDate'] = active_duty_end_date - - temp.to_json - end - - let(:schema) { Rails.root.join('modules', 'claims_api', 'config', 'schemas', 'v2', 'generate_pdf_526.json').read } - let(:veteran_id) { '1012832025V743496' } - let(:generate_pdf_scopes) { %w[system/526-pdf.override] } - let(:invalid_scopes) { %w[claim.write claim.read] } - let(:generate_pdf_path) { "/services/claims/v2/veterans/#{veteran_id}/526/generatePDF/minimum-validations" } - let(:special_issues) { ['POW'] } - - context 'submission to generatePDF' do - it 'returns a 200 response when successful' do - mock_ccg_for_fine_grained_scope(generate_pdf_scopes) do |auth_header| - post generate_pdf_path, params: data, headers: auth_header - expect(response.header['Content-Disposition']).to include('filename') - expect(response).to have_http_status(:ok) - end - end - - it 'returns a 200 response when specialIssues is present for a disability' do - json = JSON.parse data - json['data']['attributes']['disabilities'][0]['specialIssues'] = special_issues - data = json.to_json - mock_ccg_for_fine_grained_scope(generate_pdf_scopes) do |auth_header| - post generate_pdf_path, params: data, headers: auth_header - expect(response).to have_http_status(:ok) - end - end - it 'returns a 401 unauthorized with incorrect scopes' do - mock_ccg_for_fine_grained_scope(invalid_scopes) do |auth_header| - post generate_pdf_path, params: data, headers: auth_header - expect(response).to have_http_status(:unauthorized) - end - end + describe '#generate_pdf' do + let(:invalid_scopes) { %w[claim.write claim.read] } + let(:generate_pdf_scopes) { %w[system/526-pdf.override] } + let(:generate_pdf_path) { "/services/claims/v2/veterans/#{veteran_id}/526/generatePDF/minimum-validations" } - context 'when invalid JSON is submitted' do - it 'returns a 422 response' do + context 'valid data' do + it 'responds with a 200' do mock_ccg_for_fine_grained_scope(generate_pdf_scopes) do |auth_header| - post generate_pdf_path, params: {}, headers: auth_header - expect(response).to have_http_status(:unprocessable_entity) + post generate_pdf_path, params: data, headers: auth_header + expect(response.header['Content-Disposition']).to include('filename') + expect(response).to have_http_status(:ok) end end end - context 'handling for missing first and last name' do - context 'without the first and last name present' do - it 'does not allow the generatePDF call to occur' do - mock_ccg_for_fine_grained_scope(generate_pdf_scopes) do |auth_header| - allow_any_instance_of(ClaimsApi::V2::ApplicationController) - .to receive(:target_veteran).and_return(no_first_last_name_target_veteran) - allow_any_instance_of(ClaimsApi::V2::Veterans::DisabilityCompensationController) - .to receive(:veteran_middle_initial).and_return('') - - post generate_pdf_path, params: data, headers: auth_header - expect(response).to have_http_status(:unprocessable_entity) - expect(response.parsed_body['errors'][0]['detail']).to eq('Must have either first or last name') - end - end - end - - context 'without the first name present' do - it 'allows the generatePDF call to occur' do - mock_ccg_for_fine_grained_scope(generate_pdf_scopes) do |auth_header| - allow_any_instance_of(ClaimsApi::V2::ApplicationController) - .to receive(:target_veteran).and_return(no_first_name_target_veteran) - allow_any_instance_of(ClaimsApi::V2::Veterans::DisabilityCompensationController) - .to receive(:veteran_middle_initial).and_return('') - - post generate_pdf_path, params: data, headers: auth_header - expect(response).to have_http_status(:ok) - end + context 'invalid scopes' do + it 'returns a 401 unauthorized' do + mock_ccg_for_fine_grained_scope(invalid_scopes) do |auth_header| + post generate_pdf_path, params: data, headers: auth_header + expect(response).to have_http_status(:unauthorized) end end end - def set_international_address(json, address_type) - address_hash = address_type.reduce(json['data']['attributes']) { |acc, key| acc[key] } - address_hash.merge!( - 'addressLine1' => '1-1', - 'addressLine2' => 'Yoyogi Kamizono-cho', - 'addressLine3' => 'Shibuya-ku', - 'city' => 'Tokyo', - 'internationalPostalCode' => '151-8557', - 'country' => 'Japan' - ) - address_hash.delete('state') - end - - context 'when the mailing address is international' do - it 'returns a 200 response' do + context 'without the first and last name present' do + it 'does not allow the generatePDF call to occur' do mock_ccg_for_fine_grained_scope(generate_pdf_scopes) do |auth_header| - json = JSON.parse(data) - set_international_address(json, %w[veteranIdentification mailingAddress]) - data = json.to_json - post(generate_pdf_path, params: data, headers: auth_header) - expect(response).to have_http_status(:ok) + target_veteran.first_name = '' + target_veteran.last_name = '' + allow_any_instance_of(ClaimsApi::V2::ApplicationController) + .to receive(:target_veteran).and_return(target_veteran) + + post generate_pdf_path, params: data, headers: auth_header + expect(response).to have_http_status(:unprocessable_entity) + expect(response.parsed_body['errors'][0]['detail']).to eq('Must have either first or last name') end end end - context 'when the change of address is international' do - it 'returns a 200 response' do + context 'without the first name present' do + it 'allows the generatePDF call to occur' do mock_ccg_for_fine_grained_scope(generate_pdf_scopes) do |auth_header| - json = JSON.parse(data) - set_international_address(json, ['changeOfAddress']) - data = json.to_json - post(generate_pdf_path, params: data, headers: auth_header) + target_veteran.first_name = '' + allow_any_instance_of(ClaimsApi::V2::ApplicationController) + .to receive(:target_veteran).and_return(target_veteran) + + post generate_pdf_path, params: data, headers: auth_header expect(response).to have_http_status(:ok) end end @@ -4687,25 +4543,44 @@ def set_international_address(json, address_type) end end end + end + end - context 'when overflow text is provided' do - it 'responds with a 200' do - mock_ccg_for_fine_grained_scope(generate_pdf_scopes) do |auth_header| - post generate_pdf_path, params: data, headers: auth_header - expect(response).to have_http_status(:ok) - end + describe 'POST #submit not using md5 lookup' do + let(:anticipated_separation_date) { 2.days.from_now.strftime('%Y-%m-%d') } + let(:active_duty_end_date) { 2.days.from_now.strftime('%Y-%m-%d') } + let(:data) do + temp = Rails.root.join('modules', 'claims_api', 'spec', 'fixtures', 'v2', 'veterans', 'disability_compensation', + 'form_526_json_api.json').read + temp = JSON.parse(temp) + attributes = temp['data']['attributes'] + attributes['serviceInformation']['federalActivation']['anticipatedSeparationDate'] = anticipated_separation_date + attributes['serviceInformation']['servicePeriods'][-1]['activeDutyEndDate'] = active_duty_end_date + + temp.to_json + end + let(:schema) { Rails.root.join('modules', 'claims_api', 'config', 'schemas', 'v2', '526.json').read } + let(:veteran_id) { '1013062086V794840' } + let(:submit_path) { "/services/claims/v2/veterans/#{veteran_id}/526" } + + it 'creates a new claim if duplicate submit occurs (does not use md5 lookup)' do + mock_ccg(scopes) do |auth_header| + VCR.use_cassette('claims_api/disability_comp') do + json = JSON.parse(data) + post submit_path, params: json.to_json, headers: auth_header + expect(response).to have_http_status(:accepted) + first_submit_parsed = JSON.parse(response.body) + @original_id = first_submit_parsed['data']['id'] end end - - context 'when overflow text is not provided' do - it 'responds with a 200' do - mock_ccg_for_fine_grained_scope(generate_pdf_scopes) do |auth_header| - json = JSON.parse(data) - json['data']['attributes']['claimNotes'] = nil - data = json.to_json - post generate_pdf_path, params: data, headers: auth_header - expect(response).to have_http_status(:ok) - end + mock_ccg(scopes) do |auth_header| + VCR.use_cassette('claims_api/disability_comp') do + json = JSON.parse(data) + post submit_path, params: json.to_json, headers: auth_header + expect(response).to have_http_status(:accepted) + duplicate_submit_parsed = JSON.parse(response.body) + duplicate_id = duplicate_submit_parsed['data']['id'] + expect(@original_id).not_to eq(duplicate_id) end end end @@ -4814,8 +4689,10 @@ def set_international_address(json, address_type) it 'does not allow the submit to occur' do mock_ccg_for_fine_grained_scope(synchronous_scopes) do |auth_header| VCR.use_cassette('claims_api/disability_comp') do + target_veteran.first_name = '' + target_veteran.last_name = '' allow_any_instance_of(ClaimsApi::V2::ApplicationController) - .to receive(:target_veteran).and_return(no_first_last_name_target_veteran) + .to receive(:target_veteran).and_return(target_veteran) post synchronous_path, params: data, headers: auth_header expect(response).to have_http_status(:unprocessable_entity) expect(response.parsed_body['errors'][0]['detail']).to eq('Missing first and last name') From 27bcb31ed983be7d8b03c66b9934c70f1568f057 Mon Sep 17 00:00:00 2001 From: Jennica Stiehl <25069483+stiehlrod@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:34:50 -0600 Subject: [PATCH 09/31] API-37992-remove-vbms-from-healthchecks (#18244) * WIP: tests refactor. * Refactors metadata_spec. --- .../config/initializers/okcomputer.rb | 21 --------- .../claims_api/spec/requests/metadata_spec.rb | 47 ++++++++++++------- 2 files changed, 29 insertions(+), 39 deletions(-) diff --git a/modules/claims_api/config/initializers/okcomputer.rb b/modules/claims_api/config/initializers/okcomputer.rb index 3bd1b57d290..a44cb242b1d 100644 --- a/modules/claims_api/config/initializers/okcomputer.rb +++ b/modules/claims_api/config/initializers/okcomputer.rb @@ -83,23 +83,6 @@ def name end end -class VbmsCheck < BaseCheck - def check - connection = Faraday::Connection.new - connection.options.timeout = 10 - response = connection.get("#{Settings.vbms.url}/vbms-efolder-svc/upload-v1/eFolderUploadService?wsdl") - response.status == 200 ? process_success : process_failure - rescue - process_failure - end - - protected - - def name - 'VBMS' - end -end - OkComputer::Registry.register 'mpi', MpiCheck.new OkComputer::Registry.register 'bgs-vet_record', BgsCheck.new('vet_record') OkComputer::Registry.register 'bgs-corporate_update', BgsCheck.new('corporate_update') @@ -119,7 +102,3 @@ def name FaradayBGSCheck.new('IntentToFileWebServiceBean/IntentToFileWebService') OkComputer::Registry.register 'localbgs-trackeditem', FaradayBGSCheck.new('TrackedItemService/TrackedItemService') - -OkComputer::Registry.register 'vbms', VbmsCheck.new - -OkComputer.make_optional %w[vbms bgs-vet_record bgs-corporate_update bgs-contention] diff --git a/modules/claims_api/spec/requests/metadata_spec.rb b/modules/claims_api/spec/requests/metadata_spec.rb index adc35057982..b0f643d1ee6 100644 --- a/modules/claims_api/spec/requests/metadata_spec.rb +++ b/modules/claims_api/spec/requests/metadata_spec.rb @@ -50,25 +50,36 @@ expect(response).to have_http_status(:ok) end - required_upstream_services = %w[mpi] - optional_upstream_services = %w[vbms bgs-vet_record bgs-corporate_update bgs-contention - localbgs-healthcheck] - (required_upstream_services + optional_upstream_services).each do |upstream_service| - it "returns correct status when #{upstream_service} is not healthy" do - allow(MPI::Service).to receive(:service_is_up?).and_return(upstream_service != 'mpi') - allow_any_instance_of(BGS::Services).to receive(:vet_record) - .and_return(Struct.new(:healthy?).new(upstream_service != 'bgs-vet_record')) - allow_any_instance_of(BGS::Services).to receive(:corporate_update) - .and_return(Struct.new(:healthy?).new(upstream_service != 'bgs-corporate_update')) - allow_any_instance_of(BGS::Services).to receive(:contention) - .and_return(Struct.new(:healthy?).new(upstream_service != 'bgs-contention')) - allow_any_instance_of(ClaimsApi::LocalBGS).to receive(:healthcheck) - .and_return(200) - allow_any_instance_of(Faraday::Connection).to receive(:get) - .and_return(upstream_service == 'vbms' ? Struct.new(:status).new(500) : Struct.new(:status).new(200)) + it 'returns the correct status when MPI is not healthy' do + allow(MPI::Service).to receive(:service_is_up?).and_return(false) + get "/services/claims/#{version}/upstream_healthcheck" + result = JSON.parse(response.body) + expect(result['mpi']['success']).to eq(false) + end + + local_bgs_services = %i[claimant person org ebenefitsbenftclaim intenttofile trackeditem].freeze + local_bgs_methods = %i[find_poa_by_participant_id find_by_ssn find_poa_history_by_ptcpnt_id + find_benefit_claims_status_by_ptcpnt_id insert_intent_to_file find_tracked_items].freeze + local_bgs_services.each do |local_bgs_service| + it "returns the correct status when the local bgs #{local_bgs_service} is not healthy" do + local_bgs_methods.each do |local_bgs_method| + allow_any_instance_of(ClaimsApi::LocalBGS).to receive(local_bgs_method.to_sym) + .and_return(Struct.new(:healthy?).new(false)) + get "/services/claims/#{version}/upstream_healthcheck" + result = JSON.parse(response.body) + expect(result["localbgs-#{local_bgs_service}"]['success']).to eq(false) + end + end + end + + bgs_services = %i[vet_record corporate_update contention].freeze + bgs_services.each do |service| + it "returns the correct status when the BGS #{service} is not healthy" do + allow_any_instance_of(BGS::Services).to receive(service.to_sym) + .and_return(Struct.new(:healthy?).new(false)) get "/services/claims/#{version}/upstream_healthcheck" - expected_status = required_upstream_services.include?(upstream_service) ? :internal_server_error : :success - expect(response).to have_http_status(expected_status) + result = JSON.parse(response.body) + expect(result["bgs-#{service}"]['success']).to eq(false) end end end From e4517739205329f2c2f15cd9271c8ca706264b18 Mon Sep 17 00:00:00 2001 From: Jennica Stiehl <25069483+stiehlrod@users.noreply.github.com> Date: Tue, 3 Sep 2024 17:53:35 -0600 Subject: [PATCH 10/31] API-39630-handle-brd-timeouts (#18260) * Adds lighthouse common exception for bad gateway. Adds catch for exteranl timeout and returns a bad gateway in custom error. Adds a corresponding test. Adds the bad_gateway to lighthouse_error_handler, and corresponding test. * Fixes minor spelling error in spec. --- .../exceptions/lighthouse/bad_gateway.rb | 25 +++++++++++++++ .../v2/error/lighthouse_error_handler.rb | 2 ++ modules/claims_api/lib/custom_error.rb | 8 +++++ .../v2/error/lighthouse_error_handler_spec.rb | 22 +++++++++++++ .../spec/sidekiq/claim_custom_error_spec.rb | 31 +++++++++++++++++++ 5 files changed, 88 insertions(+) create mode 100644 modules/claims_api/lib/claims_api/common/exceptions/lighthouse/bad_gateway.rb diff --git a/modules/claims_api/lib/claims_api/common/exceptions/lighthouse/bad_gateway.rb b/modules/claims_api/lib/claims_api/common/exceptions/lighthouse/bad_gateway.rb new file mode 100644 index 00000000000..4d45fb9edfd --- /dev/null +++ b/modules/claims_api/lib/claims_api/common/exceptions/lighthouse/bad_gateway.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module ClaimsApi + module Common + module Exceptions + module Lighthouse + class BadGateway < StandardError + def errors + errors_array = [] + errors_array << { + status: status_code.to_s, # LH standards want this be a string + title: 'Bad gateway', + detail: 'The server received an invalid or null response from an upstream server.' + } + errors_array + end + + def status_code + 502 + end + end + end + end + end +end diff --git a/modules/claims_api/lib/claims_api/v2/error/lighthouse_error_handler.rb b/modules/claims_api/lib/claims_api/v2/error/lighthouse_error_handler.rb index 656f3dfe2e3..4ce7e8939b3 100644 --- a/modules/claims_api/lib/claims_api/v2/error/lighthouse_error_handler.rb +++ b/modules/claims_api/lib/claims_api/v2/error/lighthouse_error_handler.rb @@ -8,6 +8,7 @@ require 'claims_api/common/exceptions/lighthouse/unprocessable_entity' require 'claims_api/common/exceptions/lighthouse/resource_not_found' require 'claims_api/common/exceptions/lighthouse/bad_request' +require 'claims_api/common/exceptions/lighthouse/bad_gateway' require 'claims_api/common/exceptions/lighthouse/timeout' module ClaimsApi @@ -28,6 +29,7 @@ def self.included(clazz) # rubocop:disable Metrics/MethodLength ::ClaimsApi::Common::Exceptions::Lighthouse::BadRequest, ::Common::Exceptions::BackendServiceException, ::ClaimsApi::Common::Exceptions::Lighthouse::Timeout, + ::ClaimsApi::Common::Exceptions::Lighthouse::BadGateway, ::ClaimsApi::Common::Exceptions::Lighthouse::BackendServiceException do |err| render_non_source_error(err) end diff --git a/modules/claims_api/lib/custom_error.rb b/modules/claims_api/lib/custom_error.rb index 6383a154453..b383ddcd1cb 100644 --- a/modules/claims_api/lib/custom_error.rb +++ b/modules/claims_api/lib/custom_error.rb @@ -1,8 +1,10 @@ # frozen_string_literal: true require 'claims_api/common/exceptions/lighthouse/backend_service_exception' +require 'claims_api/common/exceptions/lighthouse/bad_gateway' require 'claims_api/common/exceptions/lighthouse/timeout' require 'claims_api/v2/error/lighthouse_error_mapper' + module ClaimsApi class CustomError def initialize(error, detail = nil, async = true) # rubocop:disable Style/OptionalBooleanParameter @@ -29,6 +31,7 @@ def build_error when ::Common::Exceptions::BackendServiceException raise ::Common::Exceptions::Forbidden if @original_status == 403 + raise_bad_gateway_exception if @original_status == 504 raise_backend_exception if @original_status == 400 raise ::Common::Exceptions::Unauthorized if @original_status == 401 @@ -50,6 +53,11 @@ def raise_timeout_exception raise ::ClaimsApi::Common::Exceptions::Lighthouse::Timeout, error_details end + def raise_bad_gateway_exception + error_details = get_error_info if @original_body.present? + raise ::ClaimsApi::Common::Exceptions::Lighthouse::BadGateway, error_details + end + def get_error_info all_errors = [] diff --git a/modules/claims_api/spec/lib/claims_api/v2/error/lighthouse_error_handler_spec.rb b/modules/claims_api/spec/lib/claims_api/v2/error/lighthouse_error_handler_spec.rb index b69e556211f..01de5c0142e 100644 --- a/modules/claims_api/spec/lib/claims_api/v2/error/lighthouse_error_handler_spec.rb +++ b/modules/claims_api/spec/lib/claims_api/v2/error/lighthouse_error_handler_spec.rb @@ -51,6 +51,10 @@ def raise_expired_token_signature def raise_timeout raise ClaimsApi::Common::Exceptions::Lighthouse::Timeout end + + def raise_bad_gateway + raise ClaimsApi::Common::Exceptions::Lighthouse::BadGateway + end end before do @@ -62,6 +66,7 @@ def raise_timeout get 'raise_invalid_token' => 'anonymous#raise_invalid_token' get 'raise_expired_token_signature' => 'anonymous#raise_expired_token_signature' get 'raise_timeout' => 'anonymous#raise_timeout' + get 'raise_bad_gateway' => 'anonymous#raise_bad_gateway' end end @@ -169,4 +174,21 @@ def raise_timeout expect(parsed_body['errors'][0]['status']).to be_a(String) end end + + it 'catches an external timeout and returns bad gateway' do + mock_ccg(scopes) do |auth_header| + request.headers.merge!(auth_header) + + get :raise_bad_gateway + + expect(response).to have_http_status(:bad_gateway) + parsed_body = JSON.parse(response.body) + expect(parsed_body['errors'][0]['title']).to eq('Bad gateway') + expect(parsed_body['errors'][0]['detail']).to eq( + 'The server received an invalid or null response from an upstream server.' + ) + expect(parsed_body['errors'][0]['status']).to eq('502') + expect(parsed_body['errors'][0]['status']).to be_a(String) + end + end end diff --git a/modules/claims_api/spec/sidekiq/claim_custom_error_spec.rb b/modules/claims_api/spec/sidekiq/claim_custom_error_spec.rb index 2ca90b5b1c1..0f8defaccac 100644 --- a/modules/claims_api/spec/sidekiq/claim_custom_error_spec.rb +++ b/modules/claims_api/spec/sidekiq/claim_custom_error_spec.rb @@ -164,4 +164,35 @@ end end end + + context 'an external service returns a 504' do + error_original_body = { + messages: [ + { + 'key' => 'timeout', + 'severity' => 'ERROR', + 'text' => 'external service timeout' + } + ] + } + + let(:external_timeout) do + Common::Exceptions::BackendServiceException.new( + backtrace.backtrace, + { status: 504, detail: 'timeout' }, + 504, + error_original_body + ) + end + + let(:external_timeout_submit) { ClaimsApi::CustomError.new(external_timeout) } + + it 'raises a 502' do + external_timeout_submit.build_error + rescue => e + expect(e.errors[0][:status]).to eq('502') + expect(e.errors[0][:title]).to eq('Bad gateway') + expect(e.errors[0][:detail]).to eq('The server received an invalid or null response from an upstream server.') + end + end end From c2ace3f5ec439be3cf74507e2f143f38ada4ffa2 Mon Sep 17 00:00:00 2001 From: Kristen Brown <11942904+kristen-brown@users.noreply.github.com> Date: Wed, 4 Sep 2024 08:50:52 -0400 Subject: [PATCH 11/31] API-37520: Updated `VAForms::FormBuilder` Logic for Handling 404s (#18287) * API-37520: Don't raise exceptions for 404s on form URLs, simply mark invalid and move on * API-37520: Add comment for 404 section * API-37520: Fix form url in Slack alert * API-37520: Use updated form name * API-37520: Update Slack notify comment * API-37520: Update FormBuilder specs for updated 404 handling * API-37520: Resolve rubocop offense --- .../app/sidekiq/va_forms/form_builder.rb | 18 ++-- .../spec/sidekiq/form_builder_spec.rb | 72 ++++++++++++++-- .../va_forms/pdf_internal_server_error.yml | 84 +++++++++++++++++++ 3 files changed, 162 insertions(+), 12 deletions(-) create mode 100644 spec/support/vcr_cassettes/va_forms/pdf_internal_server_error.yml diff --git a/modules/va_forms/app/sidekiq/va_forms/form_builder.rb b/modules/va_forms/app/sidekiq/va_forms/form_builder.rb index 24a1245654e..2b2fecc9070 100644 --- a/modules/va_forms/app/sidekiq/va_forms/form_builder.rb +++ b/modules/va_forms/app/sidekiq/va_forms/form_builder.rb @@ -33,7 +33,7 @@ class FormFetchError < StandardError; end VAForms::Slack::Messenger.new( { class: job_class.to_s, - message: "URL for form_name: #{form_name}, row_id: #{row_id} no longer returns a valid PDF or web page.", + message: "URL for form #{form_name} no longer returns a valid PDF or web page.", form_url: url } ).notify! @@ -89,16 +89,16 @@ def build_and_save_form(form_data) # and sends Slack notifications; if response is unsuccessful, raises an error def check_form_validity(form, attrs, url) response = fetch_form(url) - if response.success? - attrs[:valid_pdf] = true - attrs[:sha256] = Digest::SHA256.hexdigest(response.body) + if response.success? || response.status == 404 # 404s are non-recoverable and should not be retried + attrs[:valid_pdf] = response.success? + attrs[:sha256] = response.success? ? Digest::SHA256.hexdigest(response.body) : nil attrs[:url] = url send_slack_notifications(form, attrs, response.headers['Content-Type']) attrs else - raise FormFetchError, 'The form could not be fetched from the url provided.' + raise FormFetchError, "The form could not be fetched from the url provided. Response code: #{response.status}" end end @@ -116,7 +116,13 @@ def fetch_form(url) # Given a +existing_form+ instance of +VAForms::Form+, +updated_attributes+ for that form, and the +content_type+ # returned by the form URL, sends appropriate Slack notifications def send_slack_notifications(existing_form, updated_attrs, content_type) - if existing_form.url != updated_attrs[:url] + if existing_form.valid_pdf && !updated_attrs[:valid_pdf] + # If the PDF was valid but is no longer valid, notify + notify_slack( + "URL for form #{updated_attrs[:form_name]} no longer returns a valid PDF or web page.", + form_url: updated_attrs[:url] + ) + elsif existing_form.url != updated_attrs[:url] # If the URL has changed, we notify regardless of content notify_slack( "Form #{updated_attrs[:form_name]} has been updated.", diff --git a/modules/va_forms/spec/sidekiq/form_builder_spec.rb b/modules/va_forms/spec/sidekiq/form_builder_spec.rb index 838393b2b4a..4ee13faa26d 100644 --- a/modules/va_forms/spec/sidekiq/form_builder_spec.rb +++ b/modules/va_forms/spec/sidekiq/form_builder_spec.rb @@ -11,13 +11,14 @@ let(:slack_messenger) { instance_double(VAForms::Slack::Messenger) } let(:default_form_data) { JSON.parse(File.read(VAForms::Engine.root.join('spec', 'fixtures', 'gql_form.json'))) } - let(:bad_url_form_data) { JSON.parse(File.read(VAForms::Engine.root.join('spec', 'fixtures', 'gql_form_invalid_url.json'))) } + let(:invalid_url_form_data) { JSON.parse(File.read(VAForms::Engine.root.join('spec', 'fixtures', 'gql_form_invalid_url.json'))) } let(:deleted_form_data) { JSON.parse(File.read(VAForms::Engine.root.join('spec', 'fixtures', 'gql_form_deleted.json'))) } let(:valid_pdf_cassette) { 'va_forms/valid_pdf' } let(:not_found_pdf_cassette) { 'va_forms/pdf_not_found' } + let(:server_error_pdf_cassette) { 'va_forms/pdf_internal_server_error' } - let(:form_fetch_error_message) { 'The form could not be fetched from the url provided.' } + let(:form_fetch_error_message) { 'The form could not be fetched from the url provided. Response code: 500' } before do Sidekiq::Job.clear_all @@ -47,7 +48,7 @@ form.reload end - context 'when the form url returns a valid body' do + context 'when the form url returns a successful response' do it 'correctly updates attributes based on the new form data' do expect(result).to have_attributes( form_name: '21-0966', @@ -76,10 +77,69 @@ end context 'when the form url returns a 404' do - let(:form_data) { bad_url_form_data } + let(:form_data) { invalid_url_form_data } + let(:invalid_form_url) { 'https://www.vba.va.gov/pubs/forms/not_a_valid_url.pdf' } + let(:result) do + form = VAForms::Form.create!(url:, form_name:, sha256:, title:, valid_pdf:, row_id:) + with_settings(Settings.va_forms.slack, enabled: enable_notifications) do + VCR.use_cassette(not_found_pdf_cassette) do + form_builder.perform(form_data) + end + end + form.reload + end + + it 'marks the form as invalid' do + expect(result.valid_pdf).to be(false) + end + + it 'updates the form url' do + expect(result.url).to eql(invalid_form_url) + end + + it 'clears the sha256' do + expect(result.sha256).to be_nil + end + + it 'correctly updates the remaining attributes based on the form data' do + expect(result).to have_attributes( + form_name: '21-0966', + row_id: 5382, + title: 'Intent to File a Claim for Compensation and/or Pension, or Survivors Pension and/or DIC', + first_issued_on: Date.new(2019, 11, 7), + last_revision_on: Date.new(2018, 8, 22), + pages: 1, + ranking: nil, + tags: '21-0966', + language: 'en', + related_forms: ['10-10d'], + benefit_categories: [{ 'name' => 'Pension', 'description' => 'VA pension benefits' }], + va_form_administration: 'Veterans Benefits Administration', + form_type: 'benefit', + form_usage: 'Someusagehtml', + form_tool_intro: 'some intro text', + form_tool_url: 'https://www.va.gov/education/apply-for-education-benefits/application/1995/introduction', + form_details_url: 'https://www.va.gov/find-forms/about-form-21-0966', + deleted_at: nil + ) + end + + it 'notifies slack that the form url no longer returns a valid form' do + result + expect(VAForms::Slack::Messenger).to have_received(:new).with( + { + class: described_class.to_s, + message: "URL for form #{form_name} no longer returns a valid PDF or web page.", + form_url: invalid_form_url + } + ) + expect(slack_messenger).to have_received(:notify!) + end + end + context 'when the form url returns a 500' do it 'raises an error' do - VCR.use_cassette(not_found_pdf_cassette) do + VCR.use_cassette(server_error_pdf_cassette) do expect { form_builder.perform(form_data) } .to raise_error(described_class::FormFetchError, form_fetch_error_message) end @@ -227,7 +287,7 @@ let(:expected_notify) do { class: described_class.to_s, - message: "URL for form_name: #{form_name}, row_id: #{row_id} no longer returns a valid PDF or web page.", + message: "URL for form #{form_name} no longer returns a valid PDF or web page.", form_url: url } end diff --git a/spec/support/vcr_cassettes/va_forms/pdf_internal_server_error.yml b/spec/support/vcr_cassettes/va_forms/pdf_internal_server_error.yml new file mode 100644 index 00000000000..4bb7777cf1a --- /dev/null +++ b/spec/support/vcr_cassettes/va_forms/pdf_internal_server_error.yml @@ -0,0 +1,84 @@ +--- +http_interactions: + - request: + method: get + uri: http://www.vba.va.gov/pubs/forms/VBA-21-0966-ARE.pdf + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Faraday v0.17.6 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 302 + message: Moved Temporarily + headers: + Location: + - https://www.vba.va.gov/pubs/forms/VBA-21-0966-ARE.pdf + Server: + - BigIP + Connection: + - Keep-Alive + Content-Length: + - '0' + body: + encoding: UTF-8 + string: '' + recorded_at: Fri, 07 Jul 2023 20:12:46 GMT + - request: + method: get + uri: https://www.vba.va.gov/pubs/forms/VBA-21-0966-ARE.pdf + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Faraday v0.17.6 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 500 + message: Internal Server Error + headers: + Content-Type: + - text/html + Server: + - Microsoft-IIS/8.5 + X-Powered-By: + - ASP.NET + Strict-Transport-Security: + - max-age=31536000; includeSubDomains + Date: + - Fri, 07 Jul 2023 20:12:46 GMT + Content-Length: + - '1245' + Set-Cookie: + - BIGipServerwww.vba.va.gov_http=444976650.20480.0000; path=/; Httponly; Secure + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Referrer-Policy: + - '' + body: + encoding: UTF-8 + string: "\r\n\r\n\r\n\r\n500 - Internal Server Error\r\n\r\n\r\n\r\n

Server Error

\r\n
\r\n
\r\n

500 - Internal Server Error

\r\n
\r\n
\r\n\r\n\r\n" + recorded_at: Fri, 07 Jul 2023 20:12:46 GMT +recorded_with: VCR 6.2.0 From 03842418c62e7d29054caf8b9fa2935e291d6aae Mon Sep 17 00:00:00 2001 From: Austin Covrig Date: Wed, 4 Sep 2024 09:50:44 -0400 Subject: [PATCH 12/31] Api 38956 tracked item service (#18018) * Fix alphabetization * Add IntentToFileWebService * Add TrackedItemService * Fix typo --- .../claims_api/bgs_client/definitions.rb | 32 +++++++++++++++++++ .../claims_api/lib/bgs_service/local_bgs.rb | 1 + .../lib/claims_api/find_definition_spec.rb | 27 ++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/modules/claims_api/app/clients/claims_api/bgs_client/definitions.rb b/modules/claims_api/app/clients/claims_api/bgs_client/definitions.rb index 8cb2541c3a4..1579cf8cdcb 100644 --- a/modules/claims_api/app/clients/claims_api/bgs_client/definitions.rb +++ b/modules/claims_api/app/clients/claims_api/bgs_client/definitions.rb @@ -211,6 +211,38 @@ module FindPersonBySSN end end + ## + # TrackedItemService + # + # Adding 'Bean' to the end to differentiate from the service + module TrackedItemServiceBean + DEFINITION = + Bean.new( + path: 'TrackedItemService', + namespaces: Namespaces.new( + target: 'http://services.mapd.benefits.vba.va.gov/', + data: nil + ) + ) + end + + module TrackedItemService + DEFINITION = + Service.new( + bean: TrackedItemServiceBean::DEFINITION, + path: 'TrackedItemService' + ) + + module FindTrackedItems + DEFINITION = + Action.new( + service: TrackedItemService::DEFINITION, + name: 'findTrackedItems', + key: 'BenefitClaim' + ) + end + end + ## # VdcBean # diff --git a/modules/claims_api/lib/bgs_service/local_bgs.rb b/modules/claims_api/lib/bgs_service/local_bgs.rb index cbc014aceb9..a8d35e117b7 100644 --- a/modules/claims_api/lib/bgs_service/local_bgs.rb +++ b/modules/claims_api/lib/bgs_service/local_bgs.rb @@ -19,6 +19,7 @@ class LocalBGS IntentToFileWebServiceBean/IntentToFileWebService OrgWebServiceBean/OrgWebService PersonWebServiceBean/PersonWebService + TrackedItemService/TrackedItemService VDC/VeteranRepresentativeService VdcBean/ManageRepresentativeService VnpAtchmsWebServiceBean/VnpAtchmsService diff --git a/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb b/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb index 624da476ca6..e344b5430b2 100644 --- a/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb +++ b/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb @@ -78,6 +78,21 @@ end end + # This one doesn't have `Bean` at the end + context 'TrackedItemService' do + let(:endpoint) { 'TrackedItemService/TrackedItemService' } + let(:action) { 'findTrackedItems' } + let(:key) { 'BenefitClaim' } + + it 'response with the correct attributes' do + result = subject.for_action(endpoint, action) + parsed_result = JSON.parse(result.to_json) + expect(parsed_result['service']['bean']['path']).to eq 'TrackedItemService' + expect(parsed_result['service']['path']).to eq 'TrackedItemService' + expect(parsed_result['service']['bean']['namespaces']['target']).to eq 'http://services.mapd.benefits.vba.va.gov/' + end + end + context 'VdcBean' do let(:endpoint) { 'VDC/ManageRepresentativeService' } let(:action) { 'readPOARequest' } @@ -249,6 +264,18 @@ end end + context 'TrackedItemService' do + let(:endpoint) { 'TrackedItemService/TrackedItemService' } + + it 'response with the correct namespace' do + result = subject.for_service(endpoint) + parsed_result = JSON.parse(result.to_json) + expect(parsed_result['bean']['path']).to eq 'TrackedItemService' + expect(parsed_result['path']).to eq 'TrackedItemService' + expect(parsed_result['bean']['namespaces']['target']).to eq 'http://services.mapd.benefits.vba.va.gov/' + end + end + context 'VdcBean' do let(:endpoint) { 'VDC/ManageRepresentativeService' } From a8fc909039c67f7dd79449e5b8d078b6b3fdd73f Mon Sep 17 00:00:00 2001 From: Liz Townsend <72234279+liztownd@users.noreply.github.com> Date: Wed, 4 Sep 2024 09:13:03 -0500 Subject: [PATCH 13/31] remove travel-pay pings (#18261) --- .../travel_pay/pings_controller.rb | 26 --------- .../app/services/travel_pay/client.rb | 23 -------- modules/travel_pay/config/routes.rb | 2 - .../spec/controllers/pings_controller_spec.rb | 58 ------------------- .../travel_pay/spec/services/client_spec.rb | 51 ---------------- 5 files changed, 160 deletions(-) delete mode 100644 modules/travel_pay/app/controllers/travel_pay/pings_controller.rb delete mode 100644 modules/travel_pay/spec/controllers/pings_controller_spec.rb diff --git a/modules/travel_pay/app/controllers/travel_pay/pings_controller.rb b/modules/travel_pay/app/controllers/travel_pay/pings_controller.rb deleted file mode 100644 index 92ea3f59aa8..00000000000 --- a/modules/travel_pay/app/controllers/travel_pay/pings_controller.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -module TravelPay - class PingsController < ApplicationController - skip_before_action :authenticate, only: :ping - - def ping - btsss_ping_response = client.ping - - render json: { data: "Received ping from upstream server with status #{btsss_ping_response.status}." } - end - - def authorized_ping - btsss_authorized_ping_response = client.authorized_ping(@current_user) - render json: { - data: "Received authorized ping from upstream server with status #{btsss_authorized_ping_response.status}." - } - end - - private - - def client - TravelPay::Client.new - end - end -end diff --git a/modules/travel_pay/app/services/travel_pay/client.rb b/modules/travel_pay/app/services/travel_pay/client.rb index f92f5f24301..16b45ff8f32 100644 --- a/modules/travel_pay/app/services/travel_pay/client.rb +++ b/modules/travel_pay/app/services/travel_pay/client.rb @@ -43,29 +43,6 @@ def request_btsss_token(veis_token, sts_token) response.body['data']['accessToken'] end - ## - # HTTP GET call to the BTSSS 'ping' endpoint to test liveness - # - # @return [Faraday::Response] - # - def ping - veis_token = request_veis_token - request_ping(veis_token) - end - - ## - # HTTP GET call to the BTSSS 'authorized-ping' endpoint to test liveness - # - # @return [Faraday::Response] - # - def authorized_ping(current_user) - sts_token = request_sts_token(current_user) - veis_token = request_veis_token - btsss_token = request_btsss_token(veis_token, sts_token) - - request_authorized_ping(veis_token, btsss_token) - end - ## # HTTP GET call to the BTSSS 'claims' endpoint # API responds with travel pay claims including status diff --git a/modules/travel_pay/config/routes.rb b/modules/travel_pay/config/routes.rb index 0f62badc5ae..a142e0ba333 100644 --- a/modules/travel_pay/config/routes.rb +++ b/modules/travel_pay/config/routes.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true TravelPay::Engine.routes.draw do - get '/pings/ping', to: 'pings#ping' - get '/pings/authorized_ping', to: 'pings#authorized_ping' resources :claims end diff --git a/modules/travel_pay/spec/controllers/pings_controller_spec.rb b/modules/travel_pay/spec/controllers/pings_controller_spec.rb deleted file mode 100644 index d9d86cc9116..00000000000 --- a/modules/travel_pay/spec/controllers/pings_controller_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe TravelPay::PingsController, type: :request do - let(:user) { build(:user) } - - before do - sign_in(user) - Flipper.disable :travel_pay_power_switch - end - - describe '#ping' do - context 'the feature switch is enabled' do - before do - Flipper.enable :travel_pay_power_switch - end - - it 'requests a token and sends a ping to BTSSS' do - VCR.use_cassette('travel_pay/ping') do - get '/travel_pay/pings/ping' - expect(response.body).to include('Received ping from upstream server with status 200') - end - end - end - - context 'the feature switch is disabled' do - it 'raises the proper error' do - get '/travel_pay/pings/ping' - expect(response).to have_http_status(:forbidden) - expect(response.body).to include('You do not have access to travel pay') - end - end - end - - describe '#authorized_ping' do - context 'the feature switch is enabled' do - before do - Flipper.enable :travel_pay_power_switch - end - - it 'requests a token and sends a ping to BTSSS' do - VCR.use_cassette('travel_pay/auth_ping', match_requests_on: %i[method path]) do - get '/travel_pay/pings/authorized_ping', headers: { 'Authorization' => 'Bearer vagov_token' } - expect(response.body).to include('Received authorized ping from upstream server with status 200') - end - end - end - - context 'the feature switch is disabled' do - it 'raises the proper error' do - get '/travel_pay/pings/authorized_ping', headers: { 'Authorization' => 'Bearer vagov_token' } - expect(response).to have_http_status(:forbidden) - expect(response.body).to include('You do not have access to travel pay') - end - end - end -end diff --git a/modules/travel_pay/spec/services/client_spec.rb b/modules/travel_pay/spec/services/client_spec.rb index 9983bf59768..f10ba2c6962 100644 --- a/modules/travel_pay/spec/services/client_spec.rb +++ b/modules/travel_pay/spec/services/client_spec.rb @@ -74,28 +74,6 @@ end end - context 'ping' do - before do - allow_any_instance_of(TravelPay::Client) - .to receive(:request_veis_token) - .and_return('veis_token') - end - - it 'receives response from ping endpoint' do - @stubs.get('/api/v1/Sample/ping') do - [ - 200, - { 'Content-Type': 'application/json' } - ] - end - client = TravelPay::Client.new - response = client.ping - - expect(response).to be_success - @stubs.verify_stubbed_calls - end - end - context '/claims' do before do allow_any_instance_of(TravelPay::Client) @@ -159,35 +137,6 @@ end end - context 'authorized_ping' do - before do - allow_any_instance_of(TravelPay::Client) - .to receive(:request_veis_token) - .and_return('veis_token') - allow_any_instance_of(TravelPay::Client) - .to receive(:request_sts_token) - .and_return('sts_token') - allow_any_instance_of(TravelPay::Client) - .to receive(:request_btsss_token) - .with('veis_token', 'sts_token') - .and_return('btsss_token') - end - - it 'receives response from authorized-ping endpoint' do - @stubs.get('/api/v1/Sample/authorized-ping') do - [ - 200, - { 'Content-Type': 'application/json' } - ] - end - client = TravelPay::Client.new - response = client.authorized_ping(user) - - expect(response).to be_success - @stubs.verify_stubbed_calls - end - end - context 'request_sts_token' do let(:assertion) do { From 5cf9addb7f84e800458e6f07a9b705fe799f5fcd Mon Sep 17 00:00:00 2001 From: Matt Long Date: Wed, 4 Sep 2024 09:46:34 -0500 Subject: [PATCH 14/31] Add feature toggle for HCA insurance section (#18271) --- config/features.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/features.yml b/config/features.yml index 3b7df234fa1..e012a5eddc1 100644 --- a/config/features.yml +++ b/config/features.yml @@ -72,6 +72,10 @@ features: hca_enrollment_status_override_enabled: actor_type: user description: Enables override of enrollment status for a user, to allow multiple submissions with same user. + hca_insurance_v2_enabled: + actor_type: user + description: Enables the the upgraded insurance section of the Health Care Application + enable_in_development: true hca_performance_alert_enabled: actor_type: user description: Enables alert notifying users of a potential issue with application performance. From aacdd797e1f403f941f3d6134bd19d2019112935 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 10:50:00 -0400 Subject: [PATCH 15/31] Bump rubocop from 1.65.1 to 1.66.1 (#18292) Bumps [rubocop](https://github.com/rubocop/rubocop) from 1.65.1 to 1.66.1. - [Release notes](https://github.com/rubocop/rubocop/releases) - [Changelog](https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md) - [Commits](https://github.com/rubocop/rubocop/compare/v1.65.1...v1.66.1) --- updated-dependencies: - dependency-name: rubocop dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index dba8d2547d7..8f7563749b1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -857,8 +857,7 @@ GEM hashie (>= 1.2.0, < 6.0) jwt (>= 1.5.6) retriable (3.1.2) - rexml (3.3.6) - strscan + rexml (3.3.7) rgeo (3.0.1) rgeo-activerecord (7.0.1) activerecord (>= 5.0) @@ -914,18 +913,17 @@ GEM actionpack (>= 5.2, < 8.0) railties (>= 5.2, < 8.0) rtesseract (3.1.3) - rubocop (1.65.1) + rubocop (1.66.1) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.4, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.31.1, < 2.0) + rubocop-ast (>= 1.32.2, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.32.1) + rubocop-ast (1.32.2) parser (>= 3.3.1.0) rubocop-capybara (2.21.0) rubocop (~> 1.41) @@ -1019,8 +1017,6 @@ GEM stringio (3.1.1) strong_migrations (2.0.0) activerecord (>= 6.1) - strscan (3.1.0) - strscan (3.1.0-java) super_diff (0.12.1) attr_extras (>= 6.2.4) diff-lcs From 4c841e20f74181985f67d33c0fc74a41243e1fd8 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 4 Sep 2024 10:50:13 -0400 Subject: [PATCH 16/31] Remove va_online_scheduling_appointment_details_redesign feature toggle (#18281) --- config/features.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/config/features.yml b/config/features.yml index e012a5eddc1..f8be1e58cef 100644 --- a/config/features.yml +++ b/config/features.yml @@ -1349,10 +1349,6 @@ features: actor_type: user enable_in_development: true description: Toggle for routing appointment requests to the VetsAPI Gateway Service(VPG) instead of vaos-service. - va_online_scheduling_appointment_details_redesign: - actor_type: user - enable_in_development: true - description: Toggle for redesigning the appointment details page. va_online_scheduling_recent_locations_filter: actor_type: user enable_in_development: true @@ -1671,7 +1667,7 @@ features: description: >- A frontend-focused switch that toggles visibility of and access to the Travel Pay claim details page and entry point (features toggled together). Enabled - Entry point link and claim details page are viewable. - Disabled - Entry point link and claim details page are not viewable. + Disabled - Entry point link and claim details page are not viewable. travel_pay_submit_mileage_expense: actor_type: user enable_in_development: true From d0a2f030cd75e178711d1201bbdcecbb9fb53e43 Mon Sep 17 00:00:00 2001 From: Eric Tillberg Date: Wed, 4 Sep 2024 11:57:23 -0400 Subject: [PATCH 17/31] Add lighthouse_updated_at to form_submission_attempts table (#18270) --- ..._add_lighthouse_updated_at_to_form_submission_attempts.rb | 5 +++++ db/schema.rb | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20240903124855_add_lighthouse_updated_at_to_form_submission_attempts.rb diff --git a/db/migrate/20240903124855_add_lighthouse_updated_at_to_form_submission_attempts.rb b/db/migrate/20240903124855_add_lighthouse_updated_at_to_form_submission_attempts.rb new file mode 100644 index 00000000000..6a566efd598 --- /dev/null +++ b/db/migrate/20240903124855_add_lighthouse_updated_at_to_form_submission_attempts.rb @@ -0,0 +1,5 @@ +class AddLighthouseUpdatedAtToFormSubmissionAttempts < ActiveRecord::Migration[7.1] + def change + add_column :form_submission_attempts, :lighthouse_updated_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 4560cbd163b..3928a740160 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_08_21_145040) do +ActiveRecord::Schema[7.1].define(version: 2024_09_03_124855) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gin" enable_extension "fuzzystrmatch" @@ -735,6 +735,7 @@ t.datetime "created_at", null: false t.datetime "updated_at", null: false t.uuid "benefits_intake_uuid" + t.datetime "lighthouse_updated_at" t.index ["form_submission_id"], name: "index_form_submission_attempts_on_form_submission_id" end From 99befc0f2dc9a5ada534e9aa8185ac930c2f6498 Mon Sep 17 00:00:00 2001 From: Gabriel Zurita Date: Wed, 4 Sep 2024 10:09:33 -0600 Subject: [PATCH 18/31] Clean up stale ARP engine 2122 code (#18289) Mock data and controllers are no longe needed given the below changes to the way 2122 POA requests will be stored.: https://github.com/department-of-veterans-affairs/va.gov-team/pull/89536/files --- .../services/fetch_poa_requests.rb | 50 - .../power_of_attorney_requests_controller.rb | 83 -- .../spec/fixtures/poa_records.json | 1144 ----------------- .../v0/power_of_attorney_requests_spec.rb | 107 -- 4 files changed, 1384 deletions(-) delete mode 100644 modules/accredited_representative_portal/app/controllers/accredited_representative_portal/services/fetch_poa_requests.rb delete mode 100644 modules/accredited_representative_portal/app/controllers/accredited_representative_portal/v0/power_of_attorney_requests_controller.rb delete mode 100644 modules/accredited_representative_portal/spec/fixtures/poa_records.json delete mode 100644 modules/accredited_representative_portal/spec/requests/accredited_representative_portal/v0/power_of_attorney_requests_spec.rb diff --git a/modules/accredited_representative_portal/app/controllers/accredited_representative_portal/services/fetch_poa_requests.rb b/modules/accredited_representative_portal/app/controllers/accredited_representative_portal/services/fetch_poa_requests.rb deleted file mode 100644 index ff5d92440fb..00000000000 --- a/modules/accredited_representative_portal/app/controllers/accredited_representative_portal/services/fetch_poa_requests.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -module AccreditedRepresentativePortal - module Services - # The FetchPoaRequests service is responsible for retrieving Power of Attorney (POA) request records - # based on provided Power of Attorney codes. This class currently reads from a JSON file as a temporary - # source of data. In the future, this service will be updated to fetch POA requests directly from the - # Lighthouse API once the appropriate endpoint is ready. - # - # This service is a part of the interim solution to support development and testing of the Accredited - # Representative portal. The use of a static JSON file allows for the simulation of interacting with - # an API and facilitates the frontend development process. - # - # Example usage: - # fetcher = AccreditedRepresentativePortal::Services::FetchPoaRequests.new(['A1Q', '091']) - # result = fetcher.call - # puts result # => { 'records': [...], 'meta': { 'totalRecords': '...' } } - # - # TODO: This class is slated for update to use the Lighthouse API once the appropriate endpoint - # is available. For more information on the transition plan, refer to: - # https://app.zenhub.com/workspaces/accredited-representative-facing-team-65453a97a9cc36069a2ad1d6/issues/gh/department-of-veterans-affairs/va.gov-team/80195 - class FetchPoaRequests - # Initializes the FetchPoaRequests service with the given POA codes. - # @param poa_codes [Array] an array of POA codes to filter the POA requests. - def initialize(poa_codes) - @poa_codes = poa_codes - end - - # Fetches POA request records filtered by the initialized POA codes. - # Currently reads from a static JSON file as a data source. - # @return [Hash] A hash containing the filtered records and metadata. - def call - file_path = Rails.root.join('modules', 'accredited_representative_portal', 'spec', 'fixtures', - 'poa_records.json') - file_data = File.read(file_path) - all_records_json = JSON.parse(file_data) - all_records = all_records_json['data'] - - filtered_records = all_records.select do |record| - @poa_codes.include?(record['attributes']['powerOfAttorneyCode']) - end - - { 'records' => filtered_records, 'meta' => { 'totalRecords' => filtered_records.count.to_s } } - rescue => e - Rails.logger.error "Failed to fetch POA requests: #{e.message}" - { 'data' => [], 'meta' => { 'totalRecords' => '0' } } - end - end - end -end diff --git a/modules/accredited_representative_portal/app/controllers/accredited_representative_portal/v0/power_of_attorney_requests_controller.rb b/modules/accredited_representative_portal/app/controllers/accredited_representative_portal/v0/power_of_attorney_requests_controller.rb deleted file mode 100644 index 0e398a13b56..00000000000 --- a/modules/accredited_representative_portal/app/controllers/accredited_representative_portal/v0/power_of_attorney_requests_controller.rb +++ /dev/null @@ -1,83 +0,0 @@ -# frozen_string_literal: true - -module AccreditedRepresentativePortal - module V0 - class PowerOfAttorneyRequestsController < ApplicationController - before_action :verify_pilot_enabled_for_user - - def accept - id = params[:id] - result = update_poa_request(id, 'Accepted') - - if result[:success] - render json: { message: 'Accepted' }, status: :ok - else - render json: { error: result[:error] }, status: :unprocessable_entity - end - end - - def decline - id = params[:id] - result = update_poa_request(id, 'Declined') - - if result[:success] - render json: { message: 'Declined' }, status: :ok - else - render json: { error: result[:error] }, status: :unprocessable_entity - end - end - - def index - poa_codes = permitted_params[:poa_codes]&.split(',') || [] - - return render json: { error: 'POA codes are required' }, status: :bad_request if poa_codes.blank? - - poa_requests = AccreditedRepresentativePortal::Services::FetchPoaRequests.new(poa_codes).call - - render json: { records: poa_requests['records'], records_count: poa_requests['meta']['totalRecords'].to_i }, - status: :ok - end - - private - - def permitted_params - params.permit(:poa_codes) - end - - # TODO: This class is slated for update to use the Lighthouse API once the appropriate endpoint - # is available. For more information on the transition plan, refer to: - # https://app.zenhub.com/workspaces/accredited-representative-facing-team-65453a97a9cc36069a2ad1d6/issues/gh/department-of-veterans-affairs/va.gov-team/80195 - def update_poa_request(id, action) - # TODO: Update the below to use the RepresentativeUser's profile data - # representative = { - # first_name: 'John', - # last_name: 'Doe' - # } - - # Simulating the interaction with an external service to update POA. - # In real implementation, this method will make an actual API call. - # service_response = ClaimsApi::ManageRepresentativeService.new.update_poa_request( - # representative:, - # id: - # ) - - if %w[Accepted Declined].include?(action) - { - success: true, - response: { - id:, - action:, - responseStatus: 'updated', - acceptedOrDeclinedAt: Time.current.iso8601, - status: action == 'Accepted' ? 'obsolete' : 'cancelled' - } - } - else - { success: false, error: 'Invalid action' } - end - rescue => e - { success: false, error: e.message } - end - end - end -end diff --git a/modules/accredited_representative_portal/spec/fixtures/poa_records.json b/modules/accredited_representative_portal/spec/fixtures/poa_records.json deleted file mode 100644 index a1aee1d90e8..00000000000 --- a/modules/accredited_representative_portal/spec/fixtures/poa_records.json +++ /dev/null @@ -1,1144 +0,0 @@ -{ - "data": [ - { - "id": "3669867961", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-05-08T17:10:12Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Ramon", - "middleName": null, - "lastName": "Cassin", - "participantId": "9219494146" - }, - "representative": { - "email": "haley_cormier@harvey-friesen.example", - "firstName": "Jeremiah", - "lastName": "Torp" - }, - "claimant": { - "firstName": "Marvin", - "lastName": "Nienow", - "participantId": "6390486155", - "relationshipToVeteran": "Child" - }, - "claimantAddress": { - "city": "Hansbury", - "state": "MI", - "zip": "76609", - "country": "AM", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "2405911812", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-04-30T11:03:17Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Herlinda", - "middleName": null, - "lastName": "Kertzmann", - "participantId": "5814279075" - }, - "representative": { - "email": "nyla_russel@king-skiles.example", - "firstName": "Genaro", - "lastName": "Thompson" - }, - "claimant": { - "firstName": "Earline", - "lastName": "McGlynn", - "participantId": "2052137776", - "relationshipToVeteran": "Child" - }, - "claimantAddress": { - "city": "Reedview", - "state": "MD", - "zip": "16300", - "country": "GU", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "6045976630", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-05-18T07:20:28Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Franklyn", - "middleName": null, - "lastName": "Dickinson", - "participantId": "6821280074" - }, - "representative": { - "email": "caterina.corwin@kassulke.example", - "firstName": "Waylon", - "lastName": "Emmerich" - }, - "claimant": { - "firstName": "Matthew", - "lastName": "Windler", - "participantId": "1024141458", - "relationshipToVeteran": "Child" - }, - "claimantAddress": { - "city": "East Hana", - "state": "FL", - "zip": "36235", - "country": "GN", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "7384151070", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-05-13T15:08:36Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Alonso", - "middleName": "Reichel", - "lastName": "Hand", - "participantId": "6052657886" - }, - "representative": { - "email": "arnita.stamm@casper.example", - "firstName": "Maxine", - "lastName": "Stiedemann" - }, - "claimant": { - "firstName": "Rolando", - "lastName": "Koepp", - "participantId": "9779682967", - "relationshipToVeteran": "Friend" - }, - "claimantAddress": { - "city": "Turnerville", - "state": "MS", - "zip": "58123-1738", - "country": "PG", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "2396886392", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-04-29T00:01:23Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Erlinda", - "middleName": "Brakus", - "lastName": "Schroeder", - "participantId": "2727705661" - }, - "representative": { - "email": "wilbur@boehm-terry.test", - "firstName": "Albina", - "lastName": "Stark" - }, - "claimant": { - "firstName": "Frida", - "lastName": "Dibbert", - "participantId": "3157798228", - "relationshipToVeteran": "Spouse" - }, - "claimantAddress": { - "city": "East Vickie", - "state": "IA", - "zip": "41117-2774", - "country": "PN", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "2586634552", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-04-29T03:28:34Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Adina", - "middleName": "Yundt", - "lastName": "Bergstrom", - "participantId": "8667163565" - }, - "representative": { - "email": "ileana@johnston.example", - "firstName": "Dane", - "lastName": "Abernathy" - }, - "claimant": { - "firstName": "Demetria", - "lastName": "Becker", - "participantId": "9461656855", - "relationshipToVeteran": "Child" - }, - "claimantAddress": { - "city": "Delindamouth", - "state": "MA", - "zip": "63320", - "country": "PF", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "5900282516", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-04-25T05:08:42Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "King", - "middleName": null, - "lastName": "Farrell", - "participantId": "3491291514" - }, - "representative": { - "email": "valentine.grady@franecki-hackett.example", - "firstName": "Geneva", - "lastName": "Barton" - }, - "claimant": { - "firstName": "Britt", - "lastName": "Botsford", - "participantId": "2521415304", - "relationshipToVeteran": "Parent" - }, - "claimantAddress": { - "city": "Lashundabury", - "state": "DE", - "zip": "93618-0588", - "country": "NZ", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "1861596426", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-04-27T15:50:40Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Salvatore", - "middleName": null, - "lastName": "Morar", - "participantId": "9406912302" - }, - "representative": { - "email": "elbert.kshlerin@runolfsdottir.example", - "firstName": "Jerrold", - "lastName": "Hilll" - }, - "claimant": { - "firstName": "Daryl", - "lastName": "Turcotte", - "participantId": "9238224255", - "relationshipToVeteran": "Child" - }, - "claimantAddress": { - "city": "Bartelltown", - "state": "KY", - "zip": "52599", - "country": "AT", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "4855093638", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-04-20T12:50:30Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Archie", - "middleName": "Kiehn", - "lastName": "Kertzmann", - "participantId": "3214723941" - }, - "representative": { - "email": "jerold_tillman@heaney.test", - "firstName": "Arie", - "lastName": "Mitchell" - }, - "claimant": { - "firstName": "Ebony", - "lastName": "Kessler", - "participantId": "8723730021", - "relationshipToVeteran": "Friend" - }, - "claimantAddress": { - "city": "Angelesstad", - "state": "NH", - "zip": "56767-3403", - "country": "RO", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "1928781875", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-05-02T22:39:35Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Hayden", - "middleName": "Schimmel", - "lastName": "Haley", - "participantId": "8314512472" - }, - "representative": { - "email": "theda@waters-erdman.example", - "firstName": "Dale", - "lastName": "Bosco" - }, - "claimant": { - "firstName": "Isabella", - "lastName": "Bosco", - "participantId": "2699835872", - "relationshipToVeteran": "Friend" - }, - "claimantAddress": { - "city": "South Reggiefurt", - "state": "AR", - "zip": "88007", - "country": "HN", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "3922000248", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-04-30T04:44:34Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Jaye", - "middleName": "Schuppe", - "lastName": "Hamill", - "participantId": "8854627741" - }, - "representative": { - "email": "josette.ferry@frami.test", - "firstName": "Verlene", - "lastName": "Thiel" - }, - "claimant": { - "firstName": "Aldo", - "lastName": "Gottlieb", - "participantId": "6121157907", - "relationshipToVeteran": "Spouse" - }, - "claimantAddress": { - "city": "Hueymouth", - "state": "HI", - "zip": "22593", - "country": "FJ", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "4594888539", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-05-07T13:34:20Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Andres", - "middleName": "Marks", - "lastName": "Schamberger", - "participantId": "3688509103" - }, - "representative": { - "email": "alexis@wintheiser.test", - "firstName": "Leonel", - "lastName": "Ferry" - }, - "claimant": { - "firstName": "Miles", - "lastName": "Little", - "participantId": "1612417473", - "relationshipToVeteran": "Parent" - }, - "claimantAddress": { - "city": "Olliehaven", - "state": "OK", - "zip": "87118-5691", - "country": "GD", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "8203481834", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-05-11T17:48:38Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Elmer", - "middleName": "Simonis", - "lastName": "Altenwerth", - "participantId": "6532400139" - }, - "representative": { - "email": "eleanore.medhurst@haag-jast.example", - "firstName": "Robert", - "lastName": "Hayes" - }, - "claimant": { - "firstName": "Cammy", - "lastName": "Wehner", - "participantId": "5115975834", - "relationshipToVeteran": "Child" - }, - "claimantAddress": { - "city": "Valentineville", - "state": "VA", - "zip": "07537", - "country": "BB", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "4614631772", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-05-05T09:58:42Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Lera", - "middleName": "Borer", - "lastName": "Cronin", - "participantId": "8050254519" - }, - "representative": { - "email": "debora@hudson.test", - "firstName": "Frankie", - "lastName": "Von" - }, - "claimant": { - "firstName": "Mellissa", - "lastName": "Stracke", - "participantId": "8686935237", - "relationshipToVeteran": "Child" - }, - "claimantAddress": { - "city": "West Bellaton", - "state": "AZ", - "zip": "27375-4104", - "country": "TC", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "3055669388", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-05-01T21:36:39Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Vania", - "middleName": null, - "lastName": "Bauch", - "participantId": "8508953996" - }, - "representative": { - "email": "carley@bergnaum.test", - "firstName": "September", - "lastName": "Leffler" - }, - "claimant": { - "firstName": "Patria", - "lastName": "Bartoletti", - "participantId": "8838702605", - "relationshipToVeteran": "Spouse" - }, - "claimantAddress": { - "city": "Port Lawerencemouth", - "state": "OK", - "zip": "05315-9148", - "country": "FO", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "2522558090", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-05-10T02:46:30Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Dena", - "middleName": null, - "lastName": "Nicolas", - "participantId": "7370639845" - }, - "representative": { - "email": "kirk@cassin.example", - "firstName": "Alita", - "lastName": "Rogahn" - }, - "claimant": { - "firstName": "Tenesha", - "lastName": "Lesch", - "participantId": "1445294621", - "relationshipToVeteran": "Friend" - }, - "claimantAddress": { - "city": "East Shera", - "state": "RI", - "zip": "21148-7062", - "country": "IQ", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "8598017133", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-05-11T01:20:33Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Bennie", - "middleName": null, - "lastName": "Strosin", - "participantId": "8194559210" - }, - "representative": { - "email": "guadalupe_harvey@pacocha.example", - "firstName": "Melinda", - "lastName": "Klocko" - }, - "claimant": { - "firstName": "Alejandro", - "lastName": "Koelpin", - "participantId": "5957884898", - "relationshipToVeteran": "Spouse" - }, - "claimantAddress": { - "city": "Kubside", - "state": "WY", - "zip": "73346-9466", - "country": "HR", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "3042455297", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-05-16T16:43:40Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Trinidad", - "middleName": null, - "lastName": "Adams", - "participantId": "2033758112" - }, - "representative": { - "email": "florencia@fay.example", - "firstName": "Lane", - "lastName": "Gerlach" - }, - "claimant": { - "firstName": "Karl", - "lastName": "Tillman", - "participantId": "2491980667", - "relationshipToVeteran": "Parent" - }, - "claimantAddress": { - "city": "Lake Marcosmouth", - "state": "TX", - "zip": "69366-1798", - "country": "BM", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "3775263387", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-05-03T19:04:59Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Elli", - "middleName": "Goodwin", - "lastName": "Hane", - "participantId": "5372062756" - }, - "representative": { - "email": "lindsay@yost-collier.test", - "firstName": "Micheal", - "lastName": "Mohr" - }, - "claimant": { - "firstName": "Marcell", - "lastName": "Kihn", - "participantId": "6104236204", - "relationshipToVeteran": "Spouse" - }, - "claimantAddress": { - "city": "Kihnhaven", - "state": "NY", - "zip": "43844-2852", - "country": "LV", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "1806713940", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-04-22T00:15:28Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Sang", - "middleName": null, - "lastName": "Cummerata", - "participantId": "3973661988" - }, - "representative": { - "email": "lakeshia.cummings@pacocha.test", - "firstName": "Robert", - "lastName": "Smitham" - }, - "claimant": { - "firstName": "Roman", - "lastName": "Turcotte", - "participantId": "1599325330", - "relationshipToVeteran": "Child" - }, - "claimantAddress": { - "city": "Hauckshire", - "state": "AK", - "zip": "91411", - "country": "TJ", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "4244691241", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-05-10T00:35:26Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Denny", - "middleName": "Hyatt", - "lastName": "Roberts", - "participantId": "8789191323" - }, - "representative": { - "email": "elliot.gutkowski@reinger-hegmann.example", - "firstName": "Cinthia", - "lastName": "Tremblay" - }, - "claimant": { - "firstName": "Gina", - "lastName": "Dibbert", - "participantId": "9884126972", - "relationshipToVeteran": "Friend" - }, - "claimantAddress": { - "city": "Port Sonny", - "state": "MN", - "zip": "60433-1981", - "country": "MK", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "1893497804", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-05-03T04:28:45Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Emmett", - "middleName": null, - "lastName": "Stoltenberg", - "participantId": "6450131926" - }, - "representative": { - "email": "latrina_kovacek@spinka-mitchell.test", - "firstName": "Carol", - "lastName": "Pacocha" - }, - "claimant": { - "firstName": "Tyree", - "lastName": "Pfannerstill", - "participantId": "2334720473", - "relationshipToVeteran": "Child" - }, - "claimantAddress": { - "city": "Kassulkeland", - "state": "KS", - "zip": "54610-4046", - "country": "KN", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "8348900781", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-04-21T01:37:10Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Rochelle", - "middleName": null, - "lastName": "Stanton", - "participantId": "2358860846" - }, - "representative": { - "email": "shara@bechtelar.test", - "firstName": "Brett", - "lastName": "Hettinger" - }, - "claimant": { - "firstName": "Cordell", - "lastName": "Kutch", - "participantId": "7289841281", - "relationshipToVeteran": "Spouse" - }, - "claimantAddress": { - "city": "East Giuseppeville", - "state": "GA", - "zip": "91938", - "country": "PA", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "1593006776", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "091", - "submittedAt": "2024-05-14T07:19:32Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Hollis", - "middleName": "Ondricka", - "lastName": "Braun", - "participantId": "9808805905" - }, - "representative": { - "email": "conchita@nienow.test", - "firstName": "Adrian", - "lastName": "Ward" - }, - "claimant": { - "firstName": "Katina", - "lastName": "Koss", - "participantId": "7748234521", - "relationshipToVeteran": "Child" - }, - "claimantAddress": { - "city": "Kihnton", - "state": "NV", - "zip": "69794", - "country": "CN", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "1181625713", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Pending", - "declinedReason": null, - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-05-05T16:01:23Z", - "acceptedOrDeclinedAt": null, - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Horace", - "middleName": null, - "lastName": "Sporer", - "participantId": "7901356031" - }, - "representative": { - "email": "dione@thompson-mcglynn.test", - "firstName": "Thad", - "lastName": "Bashirian" - }, - "claimant": { - "firstName": "Frederic", - "lastName": "Spencer", - "participantId": "1422670200", - "relationshipToVeteran": "Parent" - }, - "claimantAddress": { - "city": "Lake Averyberg", - "state": "CA", - "zip": "79794", - "country": "KM", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "4188574027", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "New", - "declinedReason": "Adipisci aut nisi explicabo.", - "powerOfAttorneyCode": "091", - "submittedAt": "2024-04-20T19:37:13Z", - "acceptedOrDeclinedAt": "2024-06-08T12:05:25Z", - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Treena", - "middleName": "Lubowitz", - "lastName": "Wyman", - "participantId": "2173648168" - }, - "representative": { - "email": "jina.koch@schinner.test", - "firstName": "Carter", - "lastName": "Kulas" - }, - "claimant": { - "firstName": "Casandra", - "lastName": "Schumm", - "participantId": "8241368541", - "relationshipToVeteran": "Spouse" - }, - "claimantAddress": { - "city": "Murphyton", - "state": "FL", - "zip": "95959-1897", - "country": "NZ", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "4409858651", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Declined", - "declinedReason": "Vitae officiis dolores deserunt.", - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-05-16T05:00:07Z", - "acceptedOrDeclinedAt": "2024-05-31T20:12:26Z", - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Jed", - "middleName": "Okuneva", - "lastName": "Stiedemann", - "participantId": "4026340233" - }, - "representative": { - "email": "jackie@beer.example", - "firstName": "Ollie", - "lastName": "Abshire" - }, - "claimant": { - "firstName": "Pasquale", - "lastName": "Harvey", - "participantId": "2465670108", - "relationshipToVeteran": "Spouse" - }, - "claimantAddress": { - "city": "Kozeyfort", - "state": "IN", - "zip": "81195-0550", - "country": "IN", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "5686545584", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Accepted", - "declinedReason": "Mollitia non molestias nesciunt.", - "powerOfAttorneyCode": "091", - "submittedAt": "2024-05-13T17:48:07Z", - "acceptedOrDeclinedAt": "2024-06-17T18:57:46Z", - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Cortez", - "middleName": null, - "lastName": "Bednar", - "participantId": "9736248754" - }, - "representative": { - "email": "jeannetta@pfannerstill-oberbrunner.test", - "firstName": "Emile", - "lastName": "Reinger" - }, - "claimant": { - "firstName": "Jesse", - "lastName": "Lowe", - "participantId": "4947242466", - "relationshipToVeteran": "Parent" - }, - "claimantAddress": { - "city": "New Kraigport", - "state": "AL", - "zip": "55956-0584", - "country": "NZ", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "6280239852", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "New", - "declinedReason": "Et sapiente rerum omnis.", - "powerOfAttorneyCode": "A1Q", - "submittedAt": "2024-04-22T19:05:18Z", - "acceptedOrDeclinedAt": "2024-06-18T00:25:50Z", - "isAddressChangingAuthorized": true, - "isTreatmentDisclosureAuthorized": false, - "veteran": { - "firstName": "Stanton", - "middleName": "Deckow", - "lastName": "Rohan", - "participantId": "4996529852" - }, - "representative": { - "email": "brendan@von.example", - "firstName": "Barrie", - "lastName": "Balistreri" - }, - "claimant": { - "firstName": "Luetta", - "lastName": "Zboncak", - "participantId": "3842051478", - "relationshipToVeteran": "Child" - }, - "claimantAddress": { - "city": "New Beauville", - "state": "ND", - "zip": "62244-0284", - "country": "LA", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - }, - { - "id": "3536650225", - "type": "powerOfAttorneyRequest", - "attributes": { - "status": "Accepted", - "declinedReason": "Assumenda modi blanditiis atque.", - "powerOfAttorneyCode": "091", - "submittedAt": "2024-04-21T03:49:40Z", - "acceptedOrDeclinedAt": "2024-06-12T20:31:08Z", - "isAddressChangingAuthorized": false, - "isTreatmentDisclosureAuthorized": true, - "veteran": { - "firstName": "Charlotte", - "middleName": null, - "lastName": "Harvey", - "participantId": "5071393642" - }, - "representative": { - "email": "porfirio@roob.example", - "firstName": "Jackie", - "lastName": "Dibbert" - }, - "claimant": { - "firstName": "Micha", - "lastName": "Jacobs", - "participantId": "1245715555", - "relationshipToVeteran": "Friend" - }, - "claimantAddress": { - "city": "Raynorburgh", - "state": "AR", - "zip": "18134", - "country": "YT", - "militaryPostOffice": null, - "militaryPostalCode": null - } - } - } - ] -} \ No newline at end of file diff --git a/modules/accredited_representative_portal/spec/requests/accredited_representative_portal/v0/power_of_attorney_requests_spec.rb b/modules/accredited_representative_portal/spec/requests/accredited_representative_portal/v0/power_of_attorney_requests_spec.rb deleted file mode 100644 index c1e6c41fc10..00000000000 --- a/modules/accredited_representative_portal/spec/requests/accredited_representative_portal/v0/power_of_attorney_requests_spec.rb +++ /dev/null @@ -1,107 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require_relative '../../../support/authentication' - -RSpec.describe 'AccreditedRepresentativePortal::V0::PowerOfAttorneyRequests', type: :request do - let(:representative_user) { create(:representative_user) } - - before do - Flipper.disable(:accredited_representative_portal_pilot) - login_as(representative_user) - end - - describe 'POST /accept' do - let(:id) { '123' } - - it 'returns a successful response with an accepted message' do - Flipper.enable(:accredited_representative_portal_pilot, representative_user) - post "/accredited_representative_portal/v0/power_of_attorney_requests/#{id}/accept" - expect(response).to have_http_status(:ok) - json = JSON.parse(response.body) - expect(json['message']).to eq('Accepted') - end - end - - describe 'POST /decline' do - let(:id) { '123' } - - it 'returns a successful response with a declined message' do - Flipper.enable(:accredited_representative_portal_pilot, representative_user) - post "/accredited_representative_portal/v0/power_of_attorney_requests/#{id}/decline" - expect(response).to have_http_status(:ok) - json = JSON.parse(response.body) - expect(json['message']).to eq('Declined') - end - end - - describe 'GET /index' do - context 'when valid POA codes are provided' do - it 'returns a successful response with matching POA requests' do - Flipper.enable(:accredited_representative_portal_pilot, representative_user) - get '/accredited_representative_portal/v0/power_of_attorney_requests', params: { poa_codes: '091,A1Q' } - expect(response).to have_http_status(:ok) - json = JSON.parse(response.body) - expect(json['records']).to be_an_instance_of(Array) - expect(json['records_count']).to eq(json['records'].size) - end - end - - context 'when no POA codes are provided' do - it 'returns a bad request status with an error message' do - Flipper.enable(:accredited_representative_portal_pilot, representative_user) - get '/accredited_representative_portal/v0/power_of_attorney_requests' - expect(response).to have_http_status(:bad_request) - json = JSON.parse(response.body) - expect(json['error']).to eq('POA codes are required') - end - end - - context 'when POA codes parameter is empty' do - it 'returns a bad request status with an error message' do - Flipper.enable(:accredited_representative_portal_pilot, representative_user) - get '/accredited_representative_portal/v0/power_of_attorney_requests', params: { poa_codes: '' } - expect(response).to have_http_status(:bad_request) - expect(JSON.parse(response.body)['error']).to eq('POA codes are required') - end - end - - context 'when there are no records for the provided POA codes' do - it 'returns an empty records array and zero records count' do - Flipper.enable(:accredited_representative_portal_pilot, representative_user) - get '/accredited_representative_portal/v0/power_of_attorney_requests', params: { poa_codes: 'XYZ,ABC' } - expect(response).to have_http_status(:ok) - json = JSON.parse(response.body) - expect(json['records']).to be_an_instance_of(Array) - expect(json['records']).to be_empty - expect(json['records_count']).to eq(0) - end - end - - context 'when pilot feature flag not enabled for the user' do - let(:id) { '123' } - let(:representative_user) { create(:representative_user) } - let(:non_enabled_representative_user) { create(:representative_user) } - - before do - Flipper.enable(:accredited_representative_portal_pilot, representative_user) - login_as(non_enabled_representative_user) - end - - it 'returns a forbidden status for POST /accept' do - post "/accredited_representative_portal/v0/power_of_attorney_requests/#{id}/accept" - expect(response).to have_http_status(:forbidden) - end - - it 'returns a forbidden status for POST /decline' do - post "/accredited_representative_portal/v0/power_of_attorney_requests/#{id}/decline" - expect(response).to have_http_status(:forbidden) - end - - it 'returns a forbidden status for GET POA codes' do - get '/accredited_representative_portal/v0/power_of_attorney_requests', params: { poa_codes: 'XYZ,ABC' } - expect(response).to have_http_status(:forbidden) - end - end - end -end From 65e8b9557b446426ade62f9c533686845094355f Mon Sep 17 00:00:00 2001 From: Bryan Alexander Date: Wed, 4 Sep 2024 13:32:20 -0400 Subject: [PATCH 19/31] 91997: Fix checkbox mapping (#18297) --- .../app/form_mappings/vha_10_7959c.json.erb | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/modules/ivc_champva/app/form_mappings/vha_10_7959c.json.erb b/modules/ivc_champva/app/form_mappings/vha_10_7959c.json.erb index 86743ee9af2..7befccdb6e4 100644 --- a/modules/ivc_champva/app/form_mappings/vha_10_7959c.json.erb +++ b/modules/ivc_champva/app/form_mappings/vha_10_7959c.json.erb @@ -3,7 +3,7 @@ "form1[0].#subform[0].applicantFirstName2[0]": "<%= form.data.dig('applicant_name', 'first') %>", "form1[0].#subform[0].applicantMiddleInitial2[0]": "<%= form.data.dig('applicant_name', 'middle') %>", "form1[0].#subform[0].applicantSocialSecurityNumber2[0]": "<%= form.data.dig('applicant_ssn') %>", - "form1[0].#subform[0].#area[0].Doyouhaveotherinsyesno[0]": "<%= form.data.dig('has_other_health_insurance') ? 0 : 1 %>", + "form1[0].#subform[0].#area[0].Doyouhaveotherinsyesno[0]": "<%= ['true', true].include?(form.data.dig('has_other_health_insurance')) ? 0 : 1 %>", "form1[0].#subform[0].applicantStreetAddress2[0]": "<%= form.data.dig('applicant_address', 'street_combined') %>", "form1[0].#subform[0].applicantCity2[0]": "<%= form.data.dig('applicant_address', 'city') %>", "form1[0].#subform[0].applicantState2[0]": "<%= form.data.dig('applicant_address', 'state') %>", @@ -12,46 +12,46 @@ "form1[0].#subform[0].#area[4].applicantSexRadioButtons2[0]": "<%= form.data.dig('applicant_gender') == 'male' ? 1 : 2 %>", "form1[0].#subform[0].#area[0]": "<%= form.data.dig('') %>", "form1[0].#subform[0].NewAddressBox-1[0]": "<%= form.data.dig('applicant_new_address') != 'no' ? 1 : 0 %>", - "form1[0].#subform[0].PartABDBkgrnd[0].PartARadioButtonList[0]": "<%= form.data.dig('applicant_medicare_status') ? 0 : 1 %>", - "form1[0].#subform[0].PartABDBkgrnd[0].PartBRadioButtonList[0]": "<%= form.data.dig('applicant_medicare_status') ? 0 : 1 %>", - "form1[0].#subform[0].PartABDBkgrnd[0].PartDRadioButtonList[0]": "<%= form.data.dig('applicant_medicare_status_d') ? 0 : 1 %>", + "form1[0].#subform[0].PartABDBkgrnd[0].PartARadioButtonList[0]": "<%= ['true', true].include?(form.data.dig('applicant_medicare_status')) ? 0 : 1 %>", + "form1[0].#subform[0].PartABDBkgrnd[0].PartBRadioButtonList[0]": "<%= ['true', true].include?(form.data.dig('applicant_medicare_status')) ? 0 : 1 %>", + "form1[0].#subform[0].PartABDBkgrnd[0].PartDRadioButtonList[0]": "<%= ['true', true].include?(form.data.dig('applicant_medicare_status_d')) ? 0 : 1 %>", "form1[0].#subform[0].PartABDBkgrnd[0]": "<%= form.data.dig('') %>", "form1[0].#subform[0].Date-PartA[0]": "<%= form.data.dig('applicant_medicare_part_a_effective_date') %>", "form1[0].#subform[0].Date-PartB[0]": "<%= form.data.dig('applicant_medicare_part_b_effective_date') %>", "form1[0].#subform[0].PartA_CarrierName[0]": "<%= form.data.dig('applicant_medicare_part_a_carrier') %>", "form1[0].#subform[0].PartB_CarrierName[0]": "<%= form.data.dig('applicant_medicare_part_b_carrier') %>", - "form1[0].#subform[0].PharmacyBenefitsRadioButtonList[0]": "<%= form.data.dig('applicant_medicare_pharmacy_benefits') ? 0 : 1 %>", - "form1[0].#subform[0].MedicareAdvantageRadioButtonList[0]": "<%= form.data.dig('applicant_medicare_advantage') ? 0 : 1 %>", + "form1[0].#subform[0].PharmacyBenefitsRadioButtonList[0]": "<%= ['true', true].include?(form.data.dig('applicant_medicare_pharmacy_benefits')) ? 0 : 1 %>", + "form1[0].#subform[0].MedicareAdvantageRadioButtonList[0]": "<%= ['true', true].include?(form.data.dig('applicant_medicare_advantage')) ? 0 : 1 %>", "form1[0].#subform[0].Date-PartD[0]": "<%= form.data.dig('applicant_medicare_part_d_effective_date') %>", "form1[0].#subform[0].PartD_CarrierName[0]": "<%= form.data.dig('applicant_medicare_part_d_carrier') %>", "form1[0].#subform[0].NameofInsurance-1[0]": "<%= form.data.dig('applicant_primary_provider') %>", "form1[0].#subform[0].Date-NameInsurance-1[0]": "<%= form.data.dig('applicant_primary_effective_date') %>", "form1[0].#subform[0].Date-TermnNameInsurance-1[0]": "<%= form.data.dig('applicant_primary_expiration_date') %>", - "form1[0].#subform[0].#area[2].CheckBox-HMO-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'hmo' ? 1 : 0%>", - "form1[0].#subform[0].#area[2].CheckBox-PPO-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'ppo' ? 1 : 0%>", - "form1[0].#subform[0].#area[2].CheckBox1-MedicaidSA-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'medicaid' ? 1 : 0%>", - "form1[0].#subform[0].#area[2].CheckBox-RxDiscount-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'rxDiscount' ? 1 : 0%>", - "form1[0].#subform[0].#area[2].#area[3].CheckBox-Medigap-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'medigap' ? 1 : 0%>", + "form1[0].#subform[0].#area[2].CheckBox-HMO-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'hmo' ? 1 : 0 %>", + "form1[0].#subform[0].#area[2].CheckBox-PPO-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'ppo' ? 1 : 0 %>", + "form1[0].#subform[0].#area[2].CheckBox1-MedicaidSA-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'medicaid' ? 1 : 0 %>", + "form1[0].#subform[0].#area[2].CheckBox-RxDiscount-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'rxDiscount' ? 1 : 0 %>", + "form1[0].#subform[0].#area[2].#area[3].CheckBox-Medigap-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'medigap' ? 1 : 0 %>", "form1[0].#subform[0].#area[2].#area[3].DropDownList-Medigap-1[0]": "<%= form.data.dig('primary_medigap_plan') %>", - "form1[0].#subform[0].#area[2].CheckBox-Other-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'other' ? 1 : 0%>", + "form1[0].#subform[0].#area[2].CheckBox-Other-1[0]": "<%= form.data.dig('applicant_primary_insurance_type') == 'other' ? 1 : 0 %>", "form1[0].#subform[0].Comments-Ins-1[0]": "<%= form.data.dig('primary_additional_comments' ) %>", - "form1[0].#subform[0].#area[6].#area[7].RadioButtonList[1]": "<%= form.data.dig('applicant_primary_through_employer') ? 0 : 1 %>", - "form1[0].#subform[0].RadioButtonList[0]": "<%= form.data.dig('applicant_primary_eob') ? 0 : 1 %>", - "form1[0].#subform[0].RadioButtonList[2]": "<%= form.data.dig('applicant_primary_has_prescription') ? 0 : 1 %>", - "form1[0].#subform[0].#area[8].CheckBox-HMO-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'hmo' ? 1 : 0%>", - "form1[0].#subform[0].#area[8].CheckBox-PPO-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'ppo' ? 1 : 0%>", - "form1[0].#subform[0].#area[8].CheckBox1-MedicaidSA-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'medicaid' ? 1 : 0%>", - "form1[0].#subform[0].#area[8].CheckBox-RxDiscount-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'rxDiscount' ? 1 : 0%>", - "form1[0].#subform[0].#area[8].#area[9].CheckBox-Medigap-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'medigap' ? 1 : 0%>", + "form1[0].#subform[0].#area[6].#area[7].RadioButtonList[1]": "<%= ['true', true].include?(form.data.dig('applicant_primary_through_employer')) ? 0 : 1 %>", + "form1[0].#subform[0].RadioButtonList[0]": "<%= ['true', true].include?(form.data.dig('applicant_primary_eob')) ? 0 : 1 %>", + "form1[0].#subform[0].RadioButtonList[2]": "<%= ['true', true].include?(form.data.dig('applicant_primary_has_prescription')) ? 0 : 1 %>", + "form1[0].#subform[0].#area[8].CheckBox-HMO-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'hmo' ? 1 : 0 %>", + "form1[0].#subform[0].#area[8].CheckBox-PPO-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'ppo' ? 1 : 0 %>", + "form1[0].#subform[0].#area[8].CheckBox1-MedicaidSA-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'medicaid' ? 1 : 0 %>", + "form1[0].#subform[0].#area[8].CheckBox-RxDiscount-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'rxDiscount' ? 1 : 0 %>", + "form1[0].#subform[0].#area[8].#area[9].CheckBox-Medigap-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'medigap' ? 1 : 0 %>", "form1[0].#subform[0].#area[8].#area[9].DropDownList-Medigap-2[0]": "<%= form.data.dig('secondary_medigap_plan') %>", - "form1[0].#subform[0].#area[8].CheckBox-Other-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'other' ? 1 : 0%>", + "form1[0].#subform[0].#area[8].CheckBox-Other-2[0]": "<%= form.data.dig('applicant_secondary_insurance_type') == 'other' ? 1 : 0 %>", "form1[0].#subform[0].Comments-Ins-2[0]": "<%= form.data.dig('secondary_additional_comments' ) %>", "form1[0].#subform[0].NameofInsurance-2[0]": "<%= form.data.dig('applicant_secondary_provider') %>", "form1[0].#subform[0].Date-NameInsurance-2[0]": "<%= form.data.dig('applicant_secondary_effective_date') %>", "form1[0].#subform[0].Date-TermnNameInsurance-2[0]": "<%= form.data.dig('applicant_secondary_expiration_date') %>", - "form1[0].#subform[0].RadioButtonList[3]": "<%= form.data.dig('applicant_secondary_eob') ? 0 : 1 %>", - "form1[0].#subform[0].RadioButtonList[4]": "<%= form.data.dig('applicant_secondary_through_employer') ? 0 : 1 %>", - "form1[0].#subform[0].RadioButtonList[5]": "<%= form.data.dig('applicant_secondary_has_prescription') ? 0 : 1 %>", + "form1[0].#subform[0].RadioButtonList[3]": "<%= ['true', true].include?(form.data.dig('applicant_secondary_eob')) ? 0 : 1 %>", + "form1[0].#subform[0].RadioButtonList[4]": "<%= ['true', true].include?(form.data.dig('applicant_secondary_through_employer')) ? 0 : 1 %>", + "form1[0].#subform[0].RadioButtonList[5]": "<%= ['true', true].include?(form.data.dig('applicant_secondary_has_prescription')) ? 0 : 1 %>", "form1[0].#subform[0].Signature[0]": "<%= form.data['statement_of_truth_signature'] %>", "form1[0].#subform[0].DateTimeField1[0]": "<%= form.data.dig('certification_date') %>", "form1[0]": "<%= form.data.dig('form1') %>", From d5a98b5a521ad400b13cc7bb33432c9895429c88 Mon Sep 17 00:00:00 2001 From: Bryan Alexander Date: Wed, 4 Sep 2024 13:32:37 -0400 Subject: [PATCH 20/31] 91849: Wire up 10-7959F-2 (#18283) --- .../app/form_mappings/vha_10_7959f_2.json.erb | 26 ++++----- .../app/models/ivc_champva/vha_10_7959f_2.rb | 29 +++++++--- .../fixtures/form_json/vha_10_7959f_2.json | 57 ++++++++++--------- .../spec/models/vha_10_7959f_2_spec.rb | 26 +++++---- 4 files changed, 82 insertions(+), 56 deletions(-) diff --git a/modules/ivc_champva/app/form_mappings/vha_10_7959f_2.json.erb b/modules/ivc_champva/app/form_mappings/vha_10_7959f_2.json.erb index 6d5a307c362..4977af8a6f7 100644 --- a/modules/ivc_champva/app/form_mappings/vha_10_7959f_2.json.erb +++ b/modules/ivc_champva/app/form_mappings/vha_10_7959f_2.json.erb @@ -1,17 +1,17 @@ { - "vha107959fform[0].#subform[0].RadioButtonList[0]": "<%= form.data['payment_to_be_sent_type'] == 'Veteran' ? 0 : 1 %>", - "vha107959fform[0].#subform[0].LastName-1[0]": "<%= form.data.dig('veteran', 'full_name', 'last') %>", - "vha107959fform[0].#subform[0].FirstName-1[0]": "<%= form.data.dig('veteran', 'full_name', 'first') %>", - "vha107959fform[0].#subform[0].MiddleInitial-1[0]": "<%= form.data.dig('veteran', 'full_name', 'middle') %>", - "vha107959fform[0].#subform[0].SSN-1[0]": "<%= form.data.dig('veteran', 'ssn') %>", - "vha107959fform[0].#subform[0].VAClaimNumber-1[0]": "<%= form.data.dig('veteran', 'va_claim_number') %>", - "vha107959fform[0].#subform[0].DateofBirth-1[0]": "<%= form.data.dig('veteran', 'va_claim_number') %>", - "vha107959fform[0].#subform[0].PhysicalAddress1-1[0]": "<%= form.data.dig('veteran', 'physical_address', 'street') + '\n' + form.data.dig('veteran', 'physical_address', 'city') + ', ' + form.data.dig('veteran', 'physical_address', 'state') + '\n' + form.data.dig('veteran', 'physical_address', 'postal_code') %>", - "vha107959fform[0].#subform[0].PhysicalAddressCountry-1[0]": "<%= form.data.dig('veteran', 'physical_address', 'country') %>", - "vha107959fform[0].#subform[0].MailingAddress1-2[0]": "<%= form.data.dig('veteran', 'mailing_address', 'street') + '\n' + form.data.dig('veteran', 'mailing_address', 'city') + ', ' + form.data.dig('veteran', 'mailing_address', 'state') + '\n' + form.data.dig('veteran', 'mailing_address', 'postal_code') %>", - "vha107959fform[0].#subform[0].MailingAddressCountry[0]": "<%= form.data.dig('veteran', 'mailing_address', 'country') %>", - "vha107959fform[0].#subform[0].Telephone-1[0]": "<%= form.data.dig('veteran', 'phone_number') %>", - "vha107959fform[0].#subform[0].EmailAddress[0]": "<%= form.data.dig('veteran', 'email_address') %>", + "vha107959fform[0].#subform[0].RadioButtonList[0]": "<%= ['true', true].include?(form.data['send_payment']) ? 0 : 1 %>", + "vha107959fform[0].#subform[0].LastName-1[0]": "<%= form.data.dig('veteran_full_name', 'last') %>", + "vha107959fform[0].#subform[0].FirstName-1[0]": "<%= form.data.dig('veteran_full_name', 'first') %>", + "vha107959fform[0].#subform[0].MiddleInitial-1[0]": "<%= form.data.dig('veteran_full_name', 'middle') %>", + "vha107959fform[0].#subform[0].SSN-1[0]": "<%= form.data.dig('veteran_social_security_number', 'ssn') %>", + "vha107959fform[0].#subform[0].VAClaimNumber-1[0]": "<%= form.data.dig('veteran_social_security_number', 'va_file_number') %>", + "vha107959fform[0].#subform[0].DateofBirth-1[0]": "<%= form.data.dig('veteran_date_of_birth') %>", + "vha107959fform[0].#subform[0].PhysicalAddress1-1[0]": "<%= form.data.dig('physical_address', 'street') + '\n' + form.data.dig('physical_address', 'city') + ', ' + form.data.dig('physical_address', 'state') + '\n' + form.data.dig('physical_address', 'postal_code') %>", + "vha107959fform[0].#subform[0].PhysicalAddressCountry-1[0]": "<%= form.data.dig('physical_address', 'country') %>", + "vha107959fform[0].#subform[0].MailingAddress1-2[0]": "<%= form.data.dig('veteran_address', 'street') + '\n' + form.data.dig('veteran_address', 'city') + ', ' + form.data.dig('veteran_address', 'state') + '\n' + form.data.dig('veteran_address', 'postal_code') %>", + "vha107959fform[0].#subform[0].MailingAddressCountry[0]": "<%= form.data.dig('veteran_address', 'country') %>", + "vha107959fform[0].#subform[0].Telephone-1[0]": "<%= form.data.dig('veteran_phone_number') %>", + "vha107959fform[0].#subform[0].EmailAddress[0]": "<%= form.data.dig('veteran_email_address') %>", "vha107959fform[0].#subform[0].SignatureDate-1[0]": "<%= form.data['current_date'] %>", "vha107959fform[0].#subform[0].VeteranFiduciarySignature-1[0]": "<%= form.data['statement_of_truth_signature'] %>" } diff --git a/modules/ivc_champva/app/models/ivc_champva/vha_10_7959f_2.rb b/modules/ivc_champva/app/models/ivc_champva/vha_10_7959f_2.rb index a53aaea2e64..941a033940c 100644 --- a/modules/ivc_champva/app/models/ivc_champva/vha_10_7959f_2.rb +++ b/modules/ivc_champva/app/models/ivc_champva/vha_10_7959f_2.rb @@ -2,6 +2,8 @@ module IvcChampva class VHA107959f2 + STATS_KEY = 'api.ivc_champva_form.10_7959f_2' + include Virtus.model(nullify_blank: true) include Attachments @@ -16,13 +18,14 @@ def initialize(data) def metadata { - 'veteranFirstName' => @data.dig('veteran', 'full_name', 'first'), - 'veteranMiddleName' => @data.dig('veteran', 'full_name', 'middle'), - 'veteranLastName' => @data.dig('veteran', 'full_name', 'last'), - 'fileNumber' => @data.dig('veteran', 'va_claim_number').presence || @data.dig('veteran', 'ssn'), - 'ssn_or_tin' => @data.dig('veteran', 'ssn'), - 'zipCode' => @data.dig('veteran', 'mailing_address', 'postal_code') || '00000', - 'country' => @data.dig('veteran', 'mailing_address', 'country') || 'USA', + 'veteranFirstName' => @data.dig('veteran_full_name', 'first'), + 'veteranMiddleName' => @data.dig('veteran_full_name', 'middle'), + 'veteranLastName' => @data.dig('veteran_full_name', 'last'), + 'fileNumber' => @data.dig('veteran_social_security_number', + 'va_file_number').presence || @data.dig('veteran_social_security_number', 'ssn'), + 'ssn_or_tin' => @data.dig('veteran_social_security_number', 'ssn'), + 'zipCode' => @data.dig('veteran_address', 'postal_code') || '00000', + 'country' => @data.dig('veteran_address', 'country') || 'USA', 'source' => 'VA Platform Digital Forms', 'docType' => @data['form_number'], 'businessLine' => 'CMP', @@ -31,6 +34,18 @@ def metadata } end + def track_current_user_loa(current_user) + current_user_loa = current_user&.loa&.[](:current) || 0 + StatsD.increment("#{STATS_KEY}.#{current_user_loa}") + Rails.logger.info('IVC ChampVA Forms - 10-7959F-2 Current User LOA', current_user_loa:) + end + + def track_email_usage + email_used = metadata&.dig('primaryContactInfo', 'email') ? 'yes' : 'no' + StatsD.increment("#{STATS_KEY}.#{email_used}") + Rails.logger.info('IVC ChampVA Forms - 10-7959F-2 Email Used', email_used:) + end + def method_missing(_, *args) args&.first end diff --git a/modules/ivc_champva/spec/fixtures/form_json/vha_10_7959f_2.json b/modules/ivc_champva/spec/fixtures/form_json/vha_10_7959f_2.json index 1d95c465a1d..1186a6dacc3 100644 --- a/modules/ivc_champva/spec/fixtures/form_json/vha_10_7959f_2.json +++ b/modules/ivc_champva/spec/fixtures/form_json/vha_10_7959f_2.json @@ -7,33 +7,38 @@ }, "email": "email@address.com" }, - "veteran": { - "date_of_birth": "02/02/1987", - "full_name": { - "first": "Veteran", - "middle": "B", - "last": "Surname" - }, - "physical_address": { - "country": "USA", - "street": "1 Physical Ln", - "city": "Place", - "state": "AL", - "postal_code": "12345" - }, - "mailing_address": { - "country": "USA", - "street": "1 Mail Ln", - "city": "Place", - "state": "PA", - "postal_code": "12345" - }, - "ssn": "222554444", - "va_claim_number": "123456789", - "phone_number": "9876543213", - "email_address": "veteran@mail.com" + "veteran_full_name": { "first": "First", "middle": "middle", "last": "last" }, + "veteran_date_of_birth": "2000-01-01", + "veteran_social_security_number": { + "ssn": "123123123", + "va_file_number": "123123123" + }, + "veteran_address": { + "country": "USA", + "street": "123 Street Lane", + "city": "Cityburg", + "state": "AL", + "postal_code": "12312" + }, + "physical_address": { + "country": "USA", + "street": "222 Street Lane", + "city": "Cityland", + "state": "MD", + "postal_code": "15312" }, + "veteran_phone_number": "2341232345", + "veteran_email_address": "email@mail.gov", + "same_mailing_address": false, + "send_payment": true, + "supporting_docs": [ + { + "name": "file.png", + "confirmationCode": "36650811-4af5-4992-87d2-1aea872245c9", + "attachmentId": "", + "isEncrypted": false + } + ], "statement_of_truth_signature": "Veteran B Surname", - "payment_to_be_sent_type": "Veteran", "current_date": "01/01/2024" } \ No newline at end of file diff --git a/modules/ivc_champva/spec/models/vha_10_7959f_2_spec.rb b/modules/ivc_champva/spec/models/vha_10_7959f_2_spec.rb index 85db151ed3a..c1be2c0c9e7 100644 --- a/modules/ivc_champva/spec/models/vha_10_7959f_2_spec.rb +++ b/modules/ivc_champva/spec/models/vha_10_7959f_2_spec.rb @@ -5,6 +5,7 @@ RSpec.describe IvcChampva::VHA107959f2 do let(:data) do { + 'form_number' => '10-7959F-2', 'primary_contact_info' => { 'name' => { 'first' => 'Veteran', @@ -12,14 +13,19 @@ }, 'email' => 'email@address.com' }, - 'veteran' => { - 'full_name' => { 'first' => 'John', 'middle' => 'P', 'last' => 'Doe' }, - 'va_claim_number' => '123456789', - 'ssn' => '123456789', - 'mailing_address' => { 'country' => 'USA', 'postal_code' => '12345' } + 'veteran_full_name' => { 'first' => 'John', 'middle' => 'P', 'last' => 'Doe' }, + 'veteran_social_security_number' => { + 'ssn' => '123123123', + 'va_file_number' => '123123123' }, - 'form_number' => '10-7959F-2', - 'veteran_supporting_documents' => [ + 'veteran_address' => { + 'country' => 'USA', + 'street' => '123 Street Lane', + 'city' => 'Cityburg', + 'state' => 'AL', + 'postal_code' => '12312' + }, + 'supporting_docs' => [ { 'confirmation_code' => 'abc123' }, { 'confirmation_code' => 'def456' } ] @@ -35,9 +41,9 @@ 'veteranFirstName' => 'John', 'veteranMiddleName' => 'P', 'veteranLastName' => 'Doe', - 'fileNumber' => '123456789', - 'ssn_or_tin' => '123456789', - 'zipCode' => '12345', + 'fileNumber' => '123123123', + 'ssn_or_tin' => '123123123', + 'zipCode' => '12312', 'country' => 'USA', 'source' => 'VA Platform Digital Forms', 'docType' => '10-7959F-2', From b8512b147ed9cf581a83d5ac4badd875e4508920 Mon Sep 17 00:00:00 2001 From: Max Antonucci Date: Wed, 4 Sep 2024 13:33:32 -0400 Subject: [PATCH 21/31] VA-90998: Add caching and metrics to VBS copayments (#18265) * VA-90998: Add medical copay feature flag * VA-90998: Add caching and metrics to VBS copayments * VA-90998: Extract redis method to module --- app/models/concerns/redis_caching.rb | 7 +++ app/services/medical_copays/vbs/service.rb | 36 ++++++++++++- config/features.yml | 3 ++ lib/debt_management_center/debts_service.rb | 10 +--- .../medical_copays/vbs/service_spec.rb | 51 +++++++++++++++++++ 5 files changed, 98 insertions(+), 9 deletions(-) diff --git a/app/models/concerns/redis_caching.rb b/app/models/concerns/redis_caching.rb index bce49375e49..cc3f2001638 100644 --- a/app/models/concerns/redis_caching.rb +++ b/app/models/concerns/redis_caching.rb @@ -30,5 +30,12 @@ def set_cached(key, data) def clear_cache(key) @redis.del(key) end + + def time_until_5am_utc + now = Time.now.utc + five_am_utc = Time.utc(now.year, now.month, now.day, 5) + five_am_utc += 1.day if now >= five_am_utc + five_am_utc - now + end end end diff --git a/app/services/medical_copays/vbs/service.rb b/app/services/medical_copays/vbs/service.rb index aad4acc96e8..27ae4df1562 100644 --- a/app/services/medical_copays/vbs/service.rb +++ b/app/services/medical_copays/vbs/service.rb @@ -12,6 +12,7 @@ module VBS # @!attribute response_data # @return [ResponseData] class Service + include RedisCaching class StatementNotFound < StandardError end @@ -43,7 +44,11 @@ def initialize(opts) def get_copays raise InvalidVBSRequestError, request_data.errors unless request_data.valid? - response = request.post("#{settings.base_path}/GetStatementsByEDIPIAndVistaAccountNumber", request_data.to_hash) + response = if Flipper.enabled?(:debts_cache_vbs_copays_empty_response) + get_cached_copay_response + else + get_copay_response + end # enable zero balance debt feature if flip is on if Flipper.enabled?(:medical_copays_zero_debt) @@ -57,6 +62,26 @@ def get_copays ResponseData.build(response:).handle end + def get_cached_copay_response + StatsD.increment("#{STATSD_KEY_PREFIX}.init_cached_copays.fired") + + cached_response = get_user_cached_response + if cached_response + StatsD.increment("#{STATSD_KEY_PREFIX}.init_cached_copays.cached_response_returned") + return cached_response + end + + response = get_copay_response + response_body = response.body + + if response_body.is_a?(Array) && response_body.empty? + StatsD.increment("#{STATSD_KEY_PREFIX}.init_cached_copays.empty_response_cached") + Rails.cache.write("vbs_copays_data_#{user.uuid}", response, expires_in: self.class.time_until_5am_utc) + end + + response + end + ## # Get's the users' medical copay by statement id from list # @@ -91,6 +116,15 @@ def get_pdf_statement_by_id(statement_id) raise e end + def get_copay_response + request.post("#{settings.base_path}/GetStatementsByEDIPIAndVistaAccountNumber", request_data.to_hash) + end + + def get_user_cached_response + cache_key = "vbs_copays_data_#{user.uuid}" + Rails.cache.read(cache_key) + end + def send_statement_notifications(statements_json_byte) CopayNotifications::ParseNewStatementsJob.perform_async(statements_json_byte) end diff --git a/config/features.yml b/config/features.yml index f8be1e58cef..42fc884049a 100644 --- a/config/features.yml +++ b/config/features.yml @@ -321,6 +321,9 @@ features: debts_cache_dmc_empty_response: actor_type: user description: Enables caching of empty DMC response + debts_cache_vbs_copays_empty_response: + actor_type: user + description: Enables caching of empty VBS medical copay response decision_review_hlr_email: actor_type: user description: Send email notification for successful HLR submission diff --git a/lib/debt_management_center/debts_service.rb b/lib/debt_management_center/debts_service.rb index 3e0eb7e2a78..0ca46ed7c23 100644 --- a/lib/debt_management_center/debts_service.rb +++ b/lib/debt_management_center/debts_service.rb @@ -6,6 +6,7 @@ module DebtManagementCenter class DebtsService < DebtManagementCenter::BaseService + include RedisCaching attr_reader :file_number class DebtNotFound < StandardError; end @@ -98,7 +99,7 @@ def init_cached_debts if response.is_a?(Array) && response.empty? # DMC refreshes DB at 5am every morning - Rails.cache.write(cache_key, response, expires_in: time_until_5am_utc) + Rails.cache.write(cache_key, response, expires_in: self.class.time_until_5am_utc) StatsD.increment("#{STATSD_KEY_PREFIX}.init_cached_debts.empty_response_cached") end @@ -116,12 +117,5 @@ def add_debts_to_redis def sort_by_date(debt_history) debt_history.sort_by { |d| Date.strptime(d['date'], '%m/%d/%Y') }.reverse end - - def time_until_5am_utc - now = Time.now.utc - five_am_utc = Time.utc(now.year, now.month, now.day, 5) - five_am_utc += 1.day if now >= five_am_utc - five_am_utc - now - end end end diff --git a/spec/services/medical_copays/vbs/service_spec.rb b/spec/services/medical_copays/vbs/service_spec.rb index 2f07da221cf..59a1e0aa3f6 100644 --- a/spec/services/medical_copays/vbs/service_spec.rb +++ b/spec/services/medical_copays/vbs/service_spec.rb @@ -33,6 +33,57 @@ def stub_get_copays(response) end describe '#get_copays' do + context 'with the cache empty response flipper disabled' do + before do + allow(Flipper).to receive(:enabled?).with(:debts_cache_vbs_copays_empty_response).and_return(false) + allow(Flipper).to receive(:enabled?).with(:medical_copays_api_key_change).and_return(true) + allow(Flipper).to receive(:enabled?).with(:medical_copays_zero_debt).and_return(false) + allow(Flipper).to receive(:enabled?).with(:medical_copays_six_mo_window).and_return(false) + end + + # rubocop:disable RSpec/SubjectStub + it 'does not log that a response was cached' do + empty_response = Faraday::Response.new(status: 200, body: []) + allow_any_instance_of(MedicalCopays::VBS::Service).to receive(:get_copay_response).and_return(empty_response) + + expect(subject).not_to receive(:get_cached_copay_response) + subject.get_copays + end + # rubocop:enable RSpec/SubjectStub + end + + context 'with the cache empty response flipper enabled' do + before do + allow(Flipper).to receive(:enabled?).with(:debts_cache_vbs_copays_empty_response).and_return(true) + allow(Flipper).to receive(:enabled?).with(:medical_copays_api_key_change).and_return(true) + allow(Flipper).to receive(:enabled?).with(:medical_copays_zero_debt).and_return(false) + allow(Flipper).to receive(:enabled?).with(:medical_copays_six_mo_window).and_return(false) + end + + context 'with a cached response' do + it 'logs that a cached response was returned' do + allow_any_instance_of(MedicalCopays::VBS::Service) + .to receive(:get_user_cached_response) + .and_return(Faraday::Response.new(status: 200, body: [])) + + expect { subject.get_copays } + .to trigger_statsd_increment('api.mcp.vbs.init_cached_copays.fired') + .and trigger_statsd_increment('api.mcp.vbs.init_cached_copays.cached_response_returned') + end + end + + context 'with an empty copay response' do + it 'logs that an empty response was cached' do + empty_response = Faraday::Response.new(status: 200, body: []) + allow_any_instance_of(MedicalCopays::VBS::Service).to receive(:get_copay_response).and_return(empty_response) + + expect { subject.get_copays } + .to trigger_statsd_increment('api.mcp.vbs.init_cached_copays.fired') + .and trigger_statsd_increment('api.mcp.vbs.init_cached_copays.empty_response_cached') + end + end + end + it 'raises a custom error when request data is invalid' do allow_any_instance_of(MedicalCopays::VBS::RequestData).to receive(:valid?).and_return(false) From 84d3cf1f9223fb7e35ba3dcc222fd2fa6c76d45c Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 4 Sep 2024 11:21:40 -0700 Subject: [PATCH 22/31] [API-39351] Add `find_poas` to `local_bgs` service (#18301) * Add `find_poas` to `local_bgs` service * Add findPOAs call to local BGS service * Add test and VCR cassette * Account for arrays in BGS result parsing * Rename path to cassette --- .../claims_api/bgs_client/definitions.rb | 31 + .../claims_api/lib/bgs_service/local_bgs.rb | 30 +- .../bgs_service/standard_data_web_service.rb | 13 + .../lib/claims_api/find_definition_spec.rb | 26 + .../standard_data_web_service_spec.rb | 19 + .../standard_data_web_service/find_poas.yml | 943 ++++++++++++++++++ 6 files changed, 1061 insertions(+), 1 deletion(-) create mode 100644 modules/claims_api/lib/bgs_service/standard_data_web_service.rb create mode 100644 modules/claims_api/spec/lib/claims_api/standard_data_web_service_spec.rb create mode 100644 spec/support/vcr_cassettes/claims_api/bgs/standard_data_web_service/find_poas.yml diff --git a/modules/claims_api/app/clients/claims_api/bgs_client/definitions.rb b/modules/claims_api/app/clients/claims_api/bgs_client/definitions.rb index 1579cf8cdcb..96421084068 100644 --- a/modules/claims_api/app/clients/claims_api/bgs_client/definitions.rb +++ b/modules/claims_api/app/clients/claims_api/bgs_client/definitions.rb @@ -211,6 +211,37 @@ module FindPersonBySSN end end + ## + # StandardDataWebServiceBean + # + module StandardDataWebServiceBean + DEFINITION = + Bean.new( + path: 'StandardDataWebServiceBean', + namespaces: Namespaces.new( + target: 'http://standarddata.services.vetsnet.vba.va.gov/', + data: nil + ) + ) + end + + module StandardDataWebService + DEFINITION = + Service.new( + bean: StandardDataWebServiceBean::DEFINITION, + path: 'StandardDataWebService' + ) + + module FindPOAs + DEFINITION = + Action.new( + service: StandardDataWebService::DEFINITION, + name: 'findPOAs', + key: 'PowerOfAttorneyDTO' + ) + end + end + ## # TrackedItemService # diff --git a/modules/claims_api/lib/bgs_service/local_bgs.rb b/modules/claims_api/lib/bgs_service/local_bgs.rb index a8d35e117b7..9210ad66035 100644 --- a/modules/claims_api/lib/bgs_service/local_bgs.rb +++ b/modules/claims_api/lib/bgs_service/local_bgs.rb @@ -19,6 +19,7 @@ class LocalBGS IntentToFileWebServiceBean/IntentToFileWebService OrgWebServiceBean/OrgWebService PersonWebServiceBean/PersonWebService + StandardDataWebServiceBean/StandardDataWebService TrackedItemService/TrackedItemService VDC/VeteranRepresentativeService VdcBean/ManageRepresentativeService @@ -326,7 +327,8 @@ def make_request(endpoint:, action:, body:, key: nil, namespaces: {}, transform_ soap_error_handler.handle_errors(response) if response log_duration(event: 'parsed_response', key:) do - parsed_response(response, action:, key:, transform: transform_response) + parsed_response = parse_response(response, action:, key:) + transform_response ? transform_keys(parsed_response) : parsed_response end end @@ -431,5 +433,31 @@ def jrn jrn_obj_id: Settings.bgs.application } end + + private + + def transform_keys(hash_or_array) + transformer = lambda do |object| + case object + when Hash + object.deep_transform_keys! { |k| k.underscore.to_sym } + when Array + object.map { |item| transformer.call(item) } + else + object + end + end + + transformer.call(hash_or_array) + end + + def parse_response(response, action:, key:) + keys = ['Envelope', 'Body', "#{action}Response"] + keys << key if key.present? + + result = Hash.from_xml(response.body).dig(*keys) + + result.is_a?(Array) ? result : result.to_h + end end end diff --git a/modules/claims_api/lib/bgs_service/standard_data_web_service.rb b/modules/claims_api/lib/bgs_service/standard_data_web_service.rb new file mode 100644 index 00000000000..d9dd9212d16 --- /dev/null +++ b/modules/claims_api/lib/bgs_service/standard_data_web_service.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module ClaimsApi + class StandardDataWebService < ClaimsApi::LocalBGS + def bean_name + 'StandardDataWebServiceBean/StandardDataWebService' + end + + def find_poas + make_request(endpoint: bean_name, action: 'findPOAs', body: nil, key: 'PowerOfAttorneyDTO') + end + end +end diff --git a/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb b/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb index e344b5430b2..2d4e6929a1f 100644 --- a/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb +++ b/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb @@ -78,6 +78,20 @@ end end + context 'StandardDataWebServiceBean' do + let(:endpoint) { 'StandardDataWebServiceBean/StandardDataWebService' } + let(:action) { 'findPOAs' } + let(:key) { 'PowerOfAttorneyDTO' } + + it 'responds with the correct attributes' do + result = subject.for_action(endpoint, action) + parsed_result = JSON.parse(result.to_json) + expect(parsed_result['service']['bean']['path']).to eq 'StandardDataWebServiceBean' + expect(parsed_result['service']['path']).to eq 'StandardDataWebService' + expect(parsed_result['service']['bean']['namespaces']['target']).to eq 'http://standarddata.services.vetsnet.vba.va.gov/' + end + end + # This one doesn't have `Bean` at the end context 'TrackedItemService' do let(:endpoint) { 'TrackedItemService/TrackedItemService' } @@ -264,6 +278,18 @@ end end + context 'StandardDataWebServiceBean' do + let(:endpoint) { 'StandardDataWebServiceBean/StandardDataWebService' } + + it 'responds with the correct namespace' do + result = subject.for_service(endpoint) + parsed_result = JSON.parse(result.to_json) + expect(parsed_result['bean']['path']).to eq 'StandardDataWebServiceBean' + expect(parsed_result['path']).to eq 'StandardDataWebService' + expect(parsed_result['bean']['namespaces']['target']).to eq 'http://standarddata.services.vetsnet.vba.va.gov/' + end + end + context 'TrackedItemService' do let(:endpoint) { 'TrackedItemService/TrackedItemService' } diff --git a/modules/claims_api/spec/lib/claims_api/standard_data_web_service_spec.rb b/modules/claims_api/spec/lib/claims_api/standard_data_web_service_spec.rb new file mode 100644 index 00000000000..f2f788a2480 --- /dev/null +++ b/modules/claims_api/spec/lib/claims_api/standard_data_web_service_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'bgs_service/standard_data_web_service' + +describe ClaimsApi::StandardDataWebService do + subject { described_class.new external_uid: 'xUid', external_key: 'xKey' } + + describe '#find_poas' do + it 'responds as expected' do + VCR.use_cassette('claims_api/bgs/standard_data_web_service/find_poas') do + result = subject.find_poas + expect(result).to be_a Array + expect(result.first).to be_a Hash + expect(result.first[:legacy_poa_cd]).to eq '002' + end + end + end +end diff --git a/spec/support/vcr_cassettes/claims_api/bgs/standard_data_web_service/find_poas.yml b/spec/support/vcr_cassettes/claims_api/bgs/standard_data_web_service/find_poas.yml new file mode 100644 index 00000000000..0380ce6f22f --- /dev/null +++ b/spec/support/vcr_cassettes/claims_api/bgs/standard_data_web_service/find_poas.yml @@ -0,0 +1,943 @@ +--- +http_interactions: +- request: + method: get + uri: "/StandardDataWebServiceBean/StandardDataWebService?WSDL" + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - "" + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 26 Aug 2024 22:02:22 GMT + Server: + - Apache + X-Frame-Options: + - SAMEORIGIN + Transfer-Encoding: + - chunked + Content-Type: + - text/xml;charset=utf-8 + Strict-Transport-Security: + - max-age=16000000; includeSubDomains; preload; + body: + encoding: UTF-8 + string: |- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + recorded_at: Mon, 26 Aug 2024 22:02:23 GMT +- request: + method: post + uri: "/StandardDataWebServiceBean/StandardDataWebService" + body: + encoding: UTF-8 + string: | + + + + + + VAgovAPI + + + 127.0.0.1 + 281 + VAgovAPI + xUid + xKey + + + + + + + + + headers: + User-Agent: + - "" + Content-Type: + - text/xml;charset=UTF-8 + Host: + - ".vba.va.gov" + Soapaction: + - '"findPOAs"' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 26 Aug 2024 22:02:23 GMT + Server: + - Apache + X-Frame-Options: + - SAMEORIGIN + Transfer-Encoding: + - chunked + Content-Type: + - text/xml; charset=utf-8 + Strict-Transport-Security: + - max-age=16000000; includeSubDomains; preload; + body: + encoding: UTF-8 + string: rO0ABXdUAB13ZWJsb2dpYy5hcHAuQ29ycG9yYXRlRGF0YUVBUgAAANYAAAAjd2VibG9naWMud29ya2FyZWEuU3RyaW5nV29ya0NvbnRleHQABjMuMy40MQAA002MAINE + VETERANS' SERVICESPOA State Organization46004003POLISH + LEGION OF AMERICAN VETERANS USAPOA National Organization46028 + recorded_at: Mon, 26 Aug 2024 22:02:26 GMT +recorded_with: VCR 6.3.1 From 0ba8b964ed96a622a4ae2b0fbe974a741bc47546 Mon Sep 17 00:00:00 2001 From: Josh Fike Date: Wed, 4 Sep 2024 13:42:47 -0500 Subject: [PATCH 23/31] VA Notify - Next Steps Email - Appoint a Rep (#18194) * [WIP] Start endpoint for sending next steps email * [WIP] Add email address * [WIP] Tests for data model and controller * [WIP] Enqueing email * Add test to check for email job enqueueing * Remove debugging output * Add comment about inconsistent key names * Simplify attr_accessor * Add feature flag check * Add request check with feature disabled * Add some documentation * Address PR review feedback --- config/settings.yml | 1 + .../v0/next_steps_email_controller.rb | 61 ++++++++++ .../next_steps_email_data.rb | 32 ++++++ .../config/routes.rb | 3 +- .../next_steps_email_data_spec.rb | 30 +++++ .../spec/requests/v0/next_steps_email_spec.rb | 106 ++++++++++++++++++ 6 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 modules/representation_management/app/controllers/representation_management/v0/next_steps_email_controller.rb create mode 100644 modules/representation_management/app/models/representation_management/next_steps_email_data.rb create mode 100644 modules/representation_management/spec/models/representation_management/next_steps_email_data_spec.rb create mode 100644 modules/representation_management/spec/requests/v0/next_steps_email_spec.rb diff --git a/config/settings.yml b/config/settings.yml index 75c3745daba..556f14ddb44 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -1284,6 +1284,7 @@ vanotify: va_gov: api_key: fake_secret template_id: + appoint_a_representative_confirmation_email: appoint_a_representative_confirmation_email_template_id burial_claim_confirmation_email_template_id: burial_claim_confirmation_email_template_id ch31_vbms_form_confirmation_email: ch31_vbms_fake_template_id ch31_central_mail_form_confirmation_email: ch31_central_mail_fake_template_id diff --git a/modules/representation_management/app/controllers/representation_management/v0/next_steps_email_controller.rb b/modules/representation_management/app/controllers/representation_management/v0/next_steps_email_controller.rb new file mode 100644 index 00000000000..ed3576a5029 --- /dev/null +++ b/modules/representation_management/app/controllers/representation_management/v0/next_steps_email_controller.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module RepresentationManagement + module V0 + class NextStepsEmailController < ApplicationController + service_tag 'representation-management' + skip_before_action :authenticate + before_action :feature_enabled + + # Creates and enqueues an email with the provided "next steps" information. This action + # validates the input parameters and, if valid, queues an email using the VANotify service. + # + # @return [JSON] Returns a success message if the email is enqueued, otherwise returns validation errors. + # + def create + data = RepresentationManagement::NextStepsEmailData.new(next_steps_email_params) + if data.valid? + VANotify::EmailJob.perform_async( + data.email_address, + Settings.vanotify.services.va_gov.template_id.appoint_a_representative_confirmation_email, + { + # The first_name is the only key here that has an underscore. + # That is intentional. All the keys here match the keys in the + # template. + 'first_name' => data.first_name, + 'form name' => data.form_name, + 'form number' => data.form_number, + 'representative type' => data.representative_type_humanized, + 'representative name' => data.representative_name, + 'representative address' => data.representative_address + } + ) + render json: { message: 'Email enqueued' }, status: :ok + else + render json: { errors: data.errors.full_messages }, status: :unprocessable_entity + end + end + + private + + def feature_enabled + routing_error unless Flipper.enabled?(:appoint_a_representative_enable_pdf) + end + + # Strong parameters method for sanitizing input data for the next steps email. + # + # @return [ActionController::Parameters] Filtered parameters permitted for the next steps email. + def next_steps_email_params + params.require(:next_steps_email).permit( + :email_address, + :first_name, + :form_name, + :form_number, + :representative_type, + :representative_name, + :representative_address + ) + end + end + end +end diff --git a/modules/representation_management/app/models/representation_management/next_steps_email_data.rb b/modules/representation_management/app/models/representation_management/next_steps_email_data.rb new file mode 100644 index 00000000000..519e0f50d2f --- /dev/null +++ b/modules/representation_management/app/models/representation_management/next_steps_email_data.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module RepresentationManagement + class NextStepsEmailData + include ActiveModel::Model + + next_steps_email_attrs = %i[ + email_address + first_name + form_name + form_number + representative_type + representative_name + representative_address + ] + + attr_accessor(*next_steps_email_attrs) + + validates :email_address, presence: true + validates :first_name, presence: true + validates :form_name, presence: true + validates :form_number, presence: true + validates :representative_type, presence: true + validates :representative_type, inclusion: { in: AccreditedIndividual.individual_types.keys } + validates :representative_name, presence: true + validates :representative_address, presence: true + + def representative_type_humanized + @representative_type_humanized ||= representative_type.humanize.titleize + end + end +end diff --git a/modules/representation_management/config/routes.rb b/modules/representation_management/config/routes.rb index 03afe0f6e55..dd0855049ed 100644 --- a/modules/representation_management/config/routes.rb +++ b/modules/representation_management/config/routes.rb @@ -2,9 +2,10 @@ RepresentationManagement::Engine.routes.draw do namespace :v0, defaults: { format: 'json' } do - resources :accredited_individuals, only: %i[index] resources :accredited_entities_for_appoint, only: %i[index] + resources :accredited_individuals, only: %i[index] resources :flag_accredited_representatives, only: %i[create] + resources :next_steps_email, only: %i[create] resources :pdf_generator2122, only: %i[create] resources :pdf_generator2122a, only: %i[create] resources :power_of_attorney, only: %i[index] diff --git a/modules/representation_management/spec/models/representation_management/next_steps_email_data_spec.rb b/modules/representation_management/spec/models/representation_management/next_steps_email_data_spec.rb new file mode 100644 index 00000000000..3deb03b197b --- /dev/null +++ b/modules/representation_management/spec/models/representation_management/next_steps_email_data_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe RepresentationManagement::NextStepsEmailData, type: :model do + describe 'validations' do + subject { described_class.new } + + it { expect(subject).to validate_presence_of(:email_address) } + it { expect(subject).to validate_presence_of(:first_name) } + it { expect(subject).to validate_presence_of(:form_name) } + it { expect(subject).to validate_presence_of(:form_number) } + it { expect(subject).to validate_presence_of(:representative_type) } + + it { + expect(subject).to validate_inclusion_of(:representative_type) + .in_array(AccreditedIndividual.individual_types.keys) + } + + it { expect(subject).to validate_presence_of(:representative_name) } + it { expect(subject).to validate_presence_of(:representative_address) } + end + + describe '#representative_type_humanized' do + it 'returns the humanized and titleized version of the representative type' do + next_steps_email_data = described_class.new(representative_type: 'claims_agent') + expect(next_steps_email_data.representative_type_humanized).to eq('Claims Agent') + end + end +end diff --git a/modules/representation_management/spec/requests/v0/next_steps_email_spec.rb b/modules/representation_management/spec/requests/v0/next_steps_email_spec.rb new file mode 100644 index 00000000000..a1cb904e583 --- /dev/null +++ b/modules/representation_management/spec/requests/v0/next_steps_email_spec.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'NextStepsEmailController', type: :request do + describe 'POST #create' do + let(:base_path) { '/representation_management/v0/next_steps_email' } + let(:params) do + { + next_steps_email: { + email_address: 'email@example.com', + first_name: 'First', + form_name: 'Form Name', + form_number: 'Form Number', + representative_type: 'attorney', + representative_name: 'Name', + representative_address: 'Address' + } + } + end + + context 'When submitting all fields with valid data' do + it 'responds with a ok status' do + post(base_path, params:) + expect(response).to have_http_status(:ok) + end + + it 'responds with the expected body' do + post(base_path, params:) + expect(response.body).to eq({ message: 'Email enqueued' }.to_json) + end + + it 'enqueues the email' do + expect(VANotify::EmailJob).to receive(:perform_async).with( + params[:next_steps_email][:email_address], + 'appoint_a_representative_confirmation_email_template_id', # This is the actual value from the settings file + { + # The first_name is the only key here that has an underscore. + # That is intentional. All the keys here match the keys in the + # template. + 'first_name' => 'First', + 'form name' => 'Form Name', + 'form number' => 'Form Number', + 'representative type' => 'Attorney', # We enqueue this as a humanized and titleized string + 'representative name' => 'Name', + 'representative address' => 'Address' + } + ) + post(base_path, params:) + end + end + + context 'when triggering validation errors' do + context 'when submitting without the single required attribute for a single validation error' do + before do + params[:next_steps_email][:email_address] = nil + post(base_path, params:) + end + + it 'responds with an unprocessable entity status' do + expect(response).to have_http_status(:unprocessable_entity) + end + + it 'responds with the expected body' do + expect(response.body).to eq({ errors: ["Email address can't be blank"] }.to_json) + end + end + + context 'when submitting without multiple required attributes' do + before do + params[:next_steps_email][:email_address] = nil + params[:next_steps_email][:first_name] = nil + params[:next_steps_email][:representative_type] = nil + params[:next_steps_email][:representative_name] = nil + post(base_path, params:) + end + + it 'responds with an unprocessable entity status' do + expect(response).to have_http_status(:unprocessable_entity) + end + + it 'responds with the expected body' do + expect(response.body).to include("Email address can't be blank") + expect(response.body).to include("First name can't be blank") + expect(response.body).to include("Representative type can't be blank") + expect(response.body).to include("Representative name can't be blank") + end + end + end + + context "when the feature flag 'appoint_a_representative_enable_pdf' is disabled" do + before do + Flipper.disable(:appoint_a_representative_enable_pdf) + end + + after do + Flipper.enable(:appoint_a_representative_enable_pdf) + end + + it 'returns a 404' do + post(base_path, params:) + expect(response).to have_http_status(:not_found) + end + end + end +end From 8d7560d3c09c03a73bfc1c186c2e1b96555cbf34 Mon Sep 17 00:00:00 2001 From: s-caso <94458706+s-caso@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:59:58 -0400 Subject: [PATCH 24/31] refactor forms letter call (#18302) --- .../meb_api/app/controllers/meb_api/v0/forms_controller.rb | 7 ++++--- modules/meb_api/config/routes.rb | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) 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 f6dcaae3f1a..ae1460c7759 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 @@ -3,6 +3,7 @@ require 'dgi/forms/service/sponsor_service' require 'dgi/forms/service/claimant_service' require 'dgi/forms/service/submission_service' +require 'dgi/forms/service/letter_service' module MebApi module V0 @@ -12,8 +13,8 @@ class FormsController < MebApi::V0::BaseController def claim_letter claimant_response = claimant_service.get_claimant_info('toe') claimant_id = claimant_response['claimant']['claimant_id'] - claim_status_response = claim_status_service.get_claim_status('toe', claimant_id) - claim_letter_response = letter_service.get_claim_letter('toe', claimant_id) + claim_status_response = claim_status_service.get_claim_status(params, claimant_id, 'toe') + claim_letter_response = letter_service.get_claim_letter(claimant_id, 'toe') is_eligible = claim_status_response.claim_status == 'ELIGIBLE' response = claimant_response.status == 201 ? claim_letter_response : claimant_response @@ -92,7 +93,7 @@ def claimant_service end def letter_service - MebApi::DGI::Forms::Letter::Service.new(@current_user) + MebApi::DGI::Forms::Letters::Service.new(@current_user) end def sponsor_service diff --git a/modules/meb_api/config/routes.rb b/modules/meb_api/config/routes.rb index 5ac1cab8daf..ed2b9a2d5e5 100644 --- a/modules/meb_api/config/routes.rb +++ b/modules/meb_api/config/routes.rb @@ -16,7 +16,7 @@ post 'duplicate_contact_info', to: 'education_benefits#duplicate_contact_info' - post 'forms_claim_letter', to: 'forms#claim_letter' + get 'forms_claim_letter', to: 'forms#claim_letter' post 'forms_sponsors', to: 'forms#sponsors' post 'forms_submit_claim', to: 'forms#submit_claim' post 'forms_send_confirmation_email', to: 'forms#send_confirmation_email' From 26a6a250895b596d7992f627a9fe5e1925f32382 Mon Sep 17 00:00:00 2001 From: Annie Tran Date: Wed, 4 Sep 2024 14:26:03 -0500 Subject: [PATCH 25/31] [DR-91508] Clean up v0 endpoints (#18253) --- .github/CODEOWNERS | 10 +- app/controllers/v0/apidocs_controller.rb | 1 - .../contestable_issues_controller.rb | 22 -- .../v0/higher_level_reviews_controller.rb | 48 ----- .../v0/notice_of_disagreements_controller.rb | 47 ---- .../decision_review_evidences_controller.rb | 92 ++++++++ .../swagger/requests/appeals/appeals.rb | 148 ------------- .../schemas/appeals/notice_of_disagreement.rb | 18 -- config/routes.rb | 8 +- ...cision_review_evidences_controller_spec.rb | 200 ++++++++++++++++++ spec/requests/swagger_spec.rb | 134 ------------ spec/requests/v0/appeals_spec.rb | 89 -------- .../contestable_issues_spec.rb | 38 ---- spec/requests/v0/higher_level_reviews_spec.rb | 51 ----- .../v0/notice_of_disagreements_spec.rb | 116 ---------- 15 files changed, 296 insertions(+), 726 deletions(-) delete mode 100644 app/controllers/v0/higher_level_reviews/contestable_issues_controller.rb delete mode 100644 app/controllers/v0/higher_level_reviews_controller.rb delete mode 100644 app/controllers/v0/notice_of_disagreements_controller.rb create mode 100644 app/controllers/v1/decision_review_evidences_controller.rb create mode 100644 spec/controllers/v1/decision_review_evidences_controller_spec.rb delete mode 100644 spec/requests/v0/higher_level_reviews/contestable_issues_spec.rb delete mode 100644 spec/requests/v0/higher_level_reviews_spec.rb delete mode 100644 spec/requests/v0/notice_of_disagreements_spec.rb diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 07dc0668afa..91ac3ceee6f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -98,8 +98,6 @@ app/controllers/v0/health_records_controller.rb @department-of-veterans-affairs/ app/controllers/v0/health_care_applications_controller.rb @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/v0/form1010_ezr_attachments_controller.rb @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/v0/form1010_ezrs_controller.rb @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -app/controllers/v0/higher_level_reviews_controller.rb @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/backend-review-group -app/controllers/v0/higher_level_reviews @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/backend-review-group app/controllers/v0/id_card_announcement_subscription_controller.rb @department-of-veterans-affairs/backend-review-group app/controllers/v0/id_card_attributes_controller.rb @department-of-veterans-affairs/backend-review-group app/controllers/v0/in_progress_forms_controller.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 @@ -119,9 +117,7 @@ app/controllers/v0/messages_controller.rb @department-of-veterans-affairs/vfs-he app/controllers/v0/messaging_preferences_controller.rb @department-of-veterans-affairs/vfs-mhv-secure-messaging @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/v0/mhv_opt_in_flags_controller.rb @department-of-veterans-affairs/vfs-mhv-secure-messaging @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/v0/mpi_users_controller.rb @department-of-veterans-affairs/octo-identity -app/controllers/v0/notice_of_disagreements @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/v0/notice_of_disagreements/contestable_issues_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/v0/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/v0/onsite_notifications_controller.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/v0/pension_claims_controller.rb @department-of-veterans-affairs/pensions @department-of-veterans-affairs/backend-review-group app/controllers/v0/ppiu_controller.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -161,6 +157,7 @@ app/controllers/v1/notice_of_disagreements @department-of-veterans-affairs/benef app/controllers/v1/post911_gi_bill_statuses_controller.rb @department-of-veterans-affairs/my-education-benefits @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group app/controllers/v1/profile @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @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 +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 @@ -1684,14 +1681,10 @@ spec/requests/v0/evss_claims/documents_spec.rb @department-of-veterans-affairs/b spec/requests/v0/form1010cg @department-of-veterans-affairs/vfs-10-10 @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/requests/v0/gi @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/requests/v0/my_va/submission_statuses_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/requests/v0/higher_level_reviews @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/backend-review-group -spec/requests/v0/higher_level_reviews_spec.rb @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/backend-review-group spec/requests/v0/in_progress_forms/5655_spec.rb @department-of-veterans-affairs/vsa-debt-resolution @department-of-veterans-affairs/backend-review-group spec/requests/v0/coe_spec.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/requests/v0/map_services_spec.rb @department-of-veterans-affairs/octo-identity -spec/requests/v0/notice_of_disagreements @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/requests/v0/notice_of_disagreements/contestable_issues_spec.rb @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group -spec/requests/v0/notice_of_disagreements_spec.rb @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/requests/v0/preneeds @department-of-veterans-affairs/mbs-core-team @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/requests/v0/profile @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group spec/requests/v0/profile/contacts_spec.rb @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/vfs-mhv-integration @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @@ -1715,6 +1708,7 @@ spec/requests/v1/apidoc @department-of-veterans-affairs/backend-review-group spec/requests/v1/higher_level_reviews_spec.rb @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/backend-review-group spec/requests/v1/notice_of_disagreements_spec.rb @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/benefits-decision-reviews-be spec/requests/v1/supplemental_claims_spec.rb @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/benefits-decision-reviews-be +spec/controllers/v1/decision_review_evidences_controller_spec.rb @department-of-veterans-affairs/benefits-decision-reviews-be @department-of-veterans-affairs/backend-review-group spec/requests/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/routing/v0/map_services_routing_spec.rb @department-of-veterans-affairs/octo-identity spec/rswag_override.rb @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group diff --git a/app/controllers/v0/apidocs_controller.rb b/app/controllers/v0/apidocs_controller.rb index ec383d05ae5..e1c04f1f309 100644 --- a/app/controllers/v0/apidocs_controller.rb +++ b/app/controllers/v0/apidocs_controller.rb @@ -190,7 +190,6 @@ class ApidocsController < ApplicationController Swagger::Responses::UnprocessableEntityError, Swagger::Schemas::Address, Swagger::Schemas::Appeals::Requests, - Swagger::Schemas::Appeals::HigherLevelReview, Swagger::Schemas::Appeals::NoticeOfDisagreement, Swagger::Schemas::ContactUs::SuccessfulInquiryCreation, Swagger::Schemas::ContactUs::InquiriesList, diff --git a/app/controllers/v0/higher_level_reviews/contestable_issues_controller.rb b/app/controllers/v0/higher_level_reviews/contestable_issues_controller.rb deleted file mode 100644 index 1e455ac095b..00000000000 --- a/app/controllers/v0/higher_level_reviews/contestable_issues_controller.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -module V0 - module HigherLevelReviews - class ContestableIssuesController < AppealsBaseController - service_tag 'higher-level-review' - - def index - render json: decision_review_service - .get_higher_level_review_contestable_issues(user: current_user, benefit_type: params[:benefit_type]) - .body - rescue => e - log_exception_to_personal_information_log( - e, - error_class: "#{self.class.name}#index exception #{e.class} (HLR)", - benefit_type: params[:benefit_type] - ) - raise - end - end - end -end diff --git a/app/controllers/v0/higher_level_reviews_controller.rb b/app/controllers/v0/higher_level_reviews_controller.rb deleted file mode 100644 index ea7c490af3f..00000000000 --- a/app/controllers/v0/higher_level_reviews_controller.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'decision_review/utilities/saved_claim/service' - -module V0 - class HigherLevelReviewsController < AppealsBaseController - include DecisionReview::SavedClaim::Service - service_tag 'higher-level-review' - - def show - render json: decision_review_service.get_higher_level_review(params[:id]).body - rescue => e - log_exception_to_personal_information_log( - e, error_class: error_class(method: 'show', exception_class: e.class), id: params[:id] - ) - raise - end - - def create - hlr_response_body = decision_review_service - .create_higher_level_review(request_body: request_body_hash, user: @current_user) - .body - submitted_appeal_uuid = hlr_response_body.dig('data', 'id') - AppealSubmission.create!(user_uuid: @current_user.uuid, user_account: @current_user.user_account, - type_of_appeal: 'HLR', submitted_appeal_uuid:) - store_saved_claim(claim_class: SavedClaim::HigherLevelReview, form: request_body_hash.to_json, - guid: submitted_appeal_uuid) - render json: hlr_response_body - rescue => e - request = begin - { body: request_body_hash } - rescue - request_body_debug_data - end - - log_exception_to_personal_information_log( - e, error_class: error_class(method: 'create', exception_class: e.class), request: - ) - raise - end - - private - - def error_class(method:, exception_class:) - "#{self.class.name}##{method} exception #{exception_class} (HLR)" - end - end -end diff --git a/app/controllers/v0/notice_of_disagreements_controller.rb b/app/controllers/v0/notice_of_disagreements_controller.rb deleted file mode 100644 index 945d9367d25..00000000000 --- a/app/controllers/v0/notice_of_disagreements_controller.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -require 'decision_review/utilities/saved_claim/service' - -module V0 - class NoticeOfDisagreementsController < AppealsBaseController - include DecisionReview::SavedClaim::Service - service_tag 'board-appeal' - def create - saved_claim_request_body = request_body_hash.to_json # serialize before modifications are made to request body - nod_response_body = AppealSubmission.submit_nod( - current_user: @current_user, - request_body_hash:, - decision_review_service: - ) - store_saved_claim(claim_class: SavedClaim::NoticeOfDisagreement, form: saved_claim_request_body, - guid: nod_response_body.dig('data', 'id')) - render json: nod_response_body - rescue => e - request = begin - { body: request_body_hash } - rescue - request_body_debug_data - end - - log_exception_to_personal_information_log( - e, error_class: error_class(method: 'create', exception_class: e.class), request: - ) - raise - end - - def show - render json: decision_review_service.get_notice_of_disagreement(params[:id]).body - rescue => e - log_exception_to_personal_information_log( - e, error_class: error_class(method: 'show', exception_class: e.class), id: params[:id] - ) - raise - end - - private - - def error_class(method:, exception_class:) - "#{self.class.name}##{method} exception #{exception_class} (NOD)" - end - end -end diff --git a/app/controllers/v1/decision_review_evidences_controller.rb b/app/controllers/v1/decision_review_evidences_controller.rb new file mode 100644 index 00000000000..43d3b92868a --- /dev/null +++ b/app/controllers/v1/decision_review_evidences_controller.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +require 'decision_review_v1/utilities/logging_utils' +require 'common/pdf_helpers' + +# Notice of Disagreement evidence submissions +module V1 + class DecisionReviewEvidencesController < ApplicationController + include FormAttachmentCreate + include DecisionReviewV1::Appeals::LoggingUtils + service_tag 'evidence-upload' + + FORM_ATTACHMENT_MODEL = DecisionReviewEvidenceAttachment + + private + + def serializer_klass + DecisionReviewEvidenceAttachmentSerializer + end + + # This method, declared in `FormAttachmentCreate`, is responsible for uploading file data to S3. + def save_attachment_to_cloud! + # `form_attachment` is declared in `FormAttachmentCreate`, included above. + form_attachment_guid = form_attachment&.guid + password = filtered_params[:password] + + log_params = { + form_attachment_guid:, + encrypted: password.present? + } + + # Unlock pdf with hexapdf instead of using pdftk + if password.present? + unlocked_pdf = unlock_pdf(filtered_params[:file_data], password) + form_attachment.set_file_data!(unlocked_pdf) + else + super + end + + log_formatted(**common_log_params.merge(params: log_params, is_success: true)) + rescue => e + log_formatted(**common_log_params.merge(params: log_params, is_success: false, response_error: e)) + raise e + end + + def common_log_params + { + key: :evidence_upload_to_s3, + form_id: get_form_id_from_request_headers, + user_uuid: current_user.uuid, + downstream_system: 'AWS S3' + } + end + + def unlock_pdf(file, password) + tmpf = Tempfile.new(['decrypted_form_attachment', '.pdf']) + ::Common::PdfHelpers.unlock_pdf(file.tempfile.path, password, tmpf) + tmpf.rewind + + file.tempfile.unlink + file.tempfile = tmpf + file + end + + def get_form_id_from_request_headers + # 'Source-App-Name', which specifies the form from which evidence was submitted, is taken from `window.appName`, + # which is taken from the `entryName` in the manifest.json files for each form. See: + # - vets-website/src/platform/utilities/api/index.js (apiRequest) + # - vets-website/src/platform/startup/setup.js (setUpCommonFunctionality) + # - vets-website/src/platform/startup/index.js (startApp) + # - vets-api/lib/source_app_middleware.rb + source_app_name = request.env['SOURCE_APP'] + # The higher-level review form (996) is not included in this list because it does not permit evidence uploads. + form_id = { + '10182-board-appeal' => '10182', + '995-supplemental-claim' => '995' + }[source_app_name] + + if form_id.present? + form_id + else + # If, for some odd reason, the `entryName`s are changed in these manifest.json files (or if the HLR form begins + # accepting additional evidence), we will trigger a DataDog alert hinging on the StatsD metric below. Upon + # receiving this alert, we can update the form_id hash above. + StatsD.increment('decision_review.evidence_upload_to_s3.unexpected_form_id') + # In this situation, there is no good reason to block the Veteran from uploading their evidence to S3, + # so we return the unexpected `source_app_name` to be logged by `log_formatted` above. + source_app_name + end + end + end +end diff --git a/app/swagger/swagger/requests/appeals/appeals.rb b/app/swagger/swagger/requests/appeals/appeals.rb index f84b69ec960..bf48fd5f02b 100644 --- a/app/swagger/swagger/requests/appeals/appeals.rb +++ b/app/swagger/swagger/requests/appeals/appeals.rb @@ -49,154 +49,6 @@ class Appeals end end - swagger_path '/v0/higher_level_reviews' do - operation :post do - key :tags, %w[higher_level_reviews] - key :summary, 'Creates a higher level review' - key :operationId, 'createHigherLevelReview' - description = 'Sends data to Lighthouse who Creates a filled-out HLR PDF and uploads it to Central Mail.' \ - ' NOTE: If `informalConference` is false, the fields `informalConferenceRep`' \ - ' and `informalConferenceTimes` cannot be present.' - key :description, description - - parameter do - key :name, :request - key :in, :body - key :required, true - schema '$ref': :hlrCreate - end - - response 200 do - key :description, 'Submitted' - schema '$ref': :hlrShowRoot - end - - response 422 do - key :description, 'Malformed request' - schema '$ref': :Errors - end - end - end - - swagger_path '/v0/higher_level_reviews/{uuid}' do - operation :get do - key :description, 'This endpoint returns the details of a specific Higher Level Review' - key :operationId, 'showHigherLevelReview' - key :tags, %w[higher_level_reviews] - - parameter do - key :name, :uuid - key :in, :path - key :description, 'UUID of a higher level review' - key :required, true - key :type, :string - key :format, :uuid - key :pattern, "^[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}$" - end - - response 200 do - key :description, 'Central Mail status and original payload for Higher-Level Review' - schema '$ref': :hlrShowRoot - end - - response 404 do - key :description, 'ID not found' - schema '$ref': :Errors - end - end - end - - swagger_path '/v0/higher_level_reviews/contestable_issues/{benefit_type}' do - operation :get do - description = - 'For the logged-in veteran, returns a list of issues that could be contested in a Higher-Level Review ' \ - 'for the specified benefit type.' - key :description, description - key :operationId, 'getContestableIssues' - key :tags, %w[higher_level_reviews] - - parameter do - key :name, :benefit_type - key :in, :path - key :required, true - key :type, :string - key :enum, VetsJsonSchema::SCHEMAS.fetch('HLR-GET-CONTESTABLE-ISSUES-REQUEST-BENEFIT-TYPE')['enum'] - end - - response 200 do - key :description, 'Issues' - schema '$ref': :hlrContestableIssues - end - - response 404 do - key :description, 'Veteran not found' - schema '$ref': :Errors - end - - response 422 do - key :description, 'Malformed request' - schema '$ref': :Errors - end - end - end - - swagger_path '/v0/notice_of_disagreements' do - operation :post do - key :tags, %w[notice_of_disagreements] - key :summary, 'Creates a notice of disagreement' - key :operationId, 'createNoticeOfDisagreement' - description = 'Submits an appeal of type Notice of Disagreement, to be passed on to lighthouse. ' \ - 'This endpoint is effectively the same as submitting VA Form 10182 via mail or fax directly' \ - ' to the Board of Veterans’ Appeals.' - key :description, description - - parameter do - key :name, :request - key :in, :body - key :required, true - schema '$ref': :nodCreateRoot - end - - response 200 do - key :description, 'Submitted' - schema '$ref': :nodShowRoot - end - - response 422 do - key :description, 'Malformed request' - schema '$ref': :Errors - end - end - end - - swagger_path '/v0/notice_of_disagreements/{uuid}' do - operation :get do - key :description, 'This endpoint returns the details of a specific notice of disagreement' - key :operationId, 'showNoticeOfDisagreement' - key :tags, %w[notice_of_disagreements] - - parameter do - key :name, :uuid - key :in, :path - key :description, 'UUID of a notice of disagreement' - key :required, true - key :type, :string - key :format, :uuid - key :pattern, "^[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}$" - end - - response 200 do - key :description, 'status and original payload for Notice of Disagreement' - schema '$ref': :nodShowRoot - end - - response 404 do - key :description, 'ID not found' - schema '$ref': :Errors - end - end - end - swagger_path '/v0/notice_of_disagreements/contestable_issues' do operation :get do description = diff --git a/app/swagger/swagger/schemas/appeals/notice_of_disagreement.rb b/app/swagger/swagger/schemas/appeals/notice_of_disagreement.rb index d46278cea88..85e5ce33753 100644 --- a/app/swagger/swagger/schemas/appeals/notice_of_disagreement.rb +++ b/app/swagger/swagger/schemas/appeals/notice_of_disagreement.rb @@ -7,24 +7,6 @@ module Appeals class NoticeOfDisagreement include Swagger::Blocks - DecisionReview::Schemas::NOD_CREATE_REQUEST['definitions'].each do |k, v| - # removed values that Swagger 2.0 doesn't recognize - value = v.except('if', 'then', '$comment') - swagger_schema k, value - end - - swagger_schema 'nodCreateRoot' do - example JSON.parse(File.read('spec/fixtures/notice_of_disagreements/valid_NOD_create_request.json')) - end - - DecisionReview::Schemas::NOD_SHOW_RESPONSE_200['definitions'].each do |k, v| - swagger_schema(k == 'root' ? 'nodShowRoot' : k, v) {} - end - - swagger_schema 'nodShowRoot' do - example JSON.parse(File.read('spec/fixtures/notice_of_disagreements/NOD_show_response_200.json')) - end - swagger_schema( 'nodContestableIssues', DecisionReview::Schemas::NOD_CONTESTABLE_ISSUES_RESPONSE_200.merge( diff --git a/config/routes.rb b/config/routes.rb index f23ab8b7b87..d593a3babff 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -214,15 +214,9 @@ resources :appeals, only: :index - namespace :higher_level_reviews do - get 'contestable_issues(/:benefit_type)', to: 'contestable_issues#index' - end - resources :higher_level_reviews, only: %i[create show] - namespace :notice_of_disagreements do get 'contestable_issues', to: 'contestable_issues#index' end - resources :notice_of_disagreements, only: %i[create show] scope :messaging do scope :health do @@ -414,6 +408,8 @@ resources :zipcode_rates, only: :show, defaults: { format: :json } end + resource :decision_review_evidence, only: :create + namespace :higher_level_reviews do get 'contestable_issues(/:benefit_type)', to: 'contestable_issues#index' end diff --git a/spec/controllers/v1/decision_review_evidences_controller_spec.rb b/spec/controllers/v1/decision_review_evidences_controller_spec.rb new file mode 100644 index 00000000000..5d8b7ef71ff --- /dev/null +++ b/spec/controllers/v1/decision_review_evidences_controller_spec.rb @@ -0,0 +1,200 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe V1::DecisionReviewEvidencesController, type: :controller do + describe '::FORM_ATTACHMENT_MODEL' do + it 'is a FormAttachment model' do + expect(described_class::FORM_ATTACHMENT_MODEL.ancestors).to include(FormAttachment) + end + end + + describe '#create' do + let(:form_attachment_guid) { SecureRandom.uuid } + let(:pdf_file) do + fixture_file_upload('doctors-note.pdf', 'application/pdf') + end + let(:form_attachment_model) { described_class::FORM_ATTACHMENT_MODEL } + let(:param_namespace) { form_attachment_model.to_s.underscore.split('/').last } + let(:resource_name) { form_attachment_model.name.remove('::').snakecase } + let(:json_api_type) { resource_name.pluralize } + let(:attachment_factory_id) { resource_name.to_sym } + let(:user) { build(:user, :loa1) } + + before do + sign_in_as(user) + end + + it 'requires params.`param_namespace`' do + empty_req_params = [nil, {}] + empty_req_params << { param_namespace => {} } + empty_req_params.each do |params| + post(:create, params:) + + expect(response).to have_http_status(:bad_request) + + response_body = JSON.parse(response.body) + + expect(response_body['errors'].size).to eq(1) + expect(response_body['errors'][0]).to eq( + 'title' => 'Missing parameter', + 'detail' => "The required parameter \"#{param_namespace}\", is missing", + 'code' => '108', + 'status' => '400' + ) + end + end + + it 'requires file_data to be a file' do + params = { param_namespace => { file_data: 'not_a_file_just_a_string' } } + post(:create, params:) + expect(response).to have_http_status(:bad_request) + response_body_errors = JSON.parse(response.body)['errors'] + + expect(response_body_errors.size).to eq(1) + expect(response_body_errors[0]).to eq( + 'title' => 'Invalid field value', + 'detail' => '"String" is not a valid value for "file_data"', + 'code' => '103', + 'status' => '400' + ) + end + + context 'with a param password' do + let(:encrypted_log_params_success) do + { + message: 'Evidence upload to s3 success!', + user_uuid: user.uuid, + action: 'Evidence upload to s3', + form_id: '10182', + upstream_system: nil, + downstream_system: 'AWS S3', + is_success: true, + http: { + status_code: nil, + body: nil + }, + form_attachment_guid:, + encrypted: true + } + end + + let(:expected_response_body) do + { + 'data' => { + 'id' => '99', + 'type' => json_api_type, + 'attributes' => { + 'guid' => form_attachment_guid + } + } + } + end + + it 'creates a FormAttachment, logs formatted success message, and increments statsd' do + request.env['SOURCE_APP'] = '10182-board-appeal' + params = { param_namespace => { file_data: pdf_file, password: 'test_password' } } + + expect(Common::PdfHelpers).to receive(:unlock_pdf) + allow(Rails.logger).to receive(:info) + expect(Rails.logger).to receive(:info).with(encrypted_log_params_success) + expect(StatsD).to receive(:increment).with('decision_review.form_10182.evidence_upload_to_s3.success') + form_attachment = build(attachment_factory_id, guid: form_attachment_guid) + + expect(form_attachment_model).to receive(:new) do + expect(form_attachment).to receive(:set_file_data!) + + expect(form_attachment).to receive(:save!) do + form_attachment.id = 99 + form_attachment + end + + form_attachment + end + + post(:create, params:) + + expect(response).to have_http_status(:ok) + expect(JSON.parse(response.body)).to eq(expected_response_body) + end + end + + context 'evidence is uploaded from the NOD (10182) form' do + it 'formatted success log and statsd metric are specific to NOD (10182)' do + request.env['SOURCE_APP'] = '10182-board-appeal' + params = { param_namespace => { file_data: pdf_file } } + allow(Rails.logger).to receive(:info) + expect(Rails.logger).to receive(:info).with(hash_including(form_id: '10182')) + expect(StatsD).to receive(:increment).with('decision_review.form_10182.evidence_upload_to_s3.success') + post(:create, params:) + end + end + + context 'evidence is uploaded from the SC (995) form' do + it 'formatted success log and statsd metric are specific to SC (995)' do + request.env['SOURCE_APP'] = '995-supplemental-claim' + params = { param_namespace => { file_data: pdf_file } } + allow(Rails.logger).to receive(:info) + expect(Rails.logger).to receive(:info).with(hash_including(form_id: '995')) + expect(StatsD).to receive(:increment).with('decision_review.form_995.evidence_upload_to_s3.success') + post(:create, params:) + end + end + + context 'evidence is uploaded from a form with an unexpected Source-App-Name' do + it 'logs formatted success log and increments success statsd metric, but also increments an `unexpected_form_id` statsd metric' do # rubocop:disable Layout/LineLength + request.env['SOURCE_APP'] = '997-supplemental-claim' + params = { param_namespace => { file_data: pdf_file } } + allow(Rails.logger).to receive(:info) + expect(Rails.logger).to receive(:info).with(hash_including(form_id: '997-supplemental-claim')) + expect(StatsD).to receive(:increment).with('decision_review.form_997-supplemental-claim.evidence_upload_to_s3.success') # rubocop:disable Layout/LineLength + expect(StatsD).to receive(:increment).with('decision_review.evidence_upload_to_s3.unexpected_form_id') + post(:create, params:) + end + end + + context 'an error is thrown during file upload' do + it 'logs formatted error, increments statsd, and raises error' do + request.env['SOURCE_APP'] = '10182-board-appeal' + params = { param_namespace => { file_data: pdf_file } } + expect(StatsD).to receive(:increment).with('decision_review.form_10182.evidence_upload_to_s3.failure') + allow(Rails.logger).to receive(:error) + expect(Rails.logger).to receive(:error).with({ + message: 'Evidence upload to s3 failure!', + user_uuid: user.uuid, + action: 'Evidence upload to s3', + form_id: '10182', + upstream_system: nil, + downstream_system: 'AWS S3', + is_success: false, + http: { + status_code: 422, + body: 'Unprocessable Entity' + }, + form_attachment_guid:, + encrypted: false + }) + form_attachment = build(attachment_factory_id, guid: form_attachment_guid) + expect(form_attachment_model).to receive(:new).and_return(form_attachment) + expected_error = Common::Exceptions::UnprocessableEntity.new( + detail: 'Test Error!', + source: 'FormAttachment.set_file_data' + ) + expect(form_attachment).to receive(:set_file_data!).and_raise(expected_error) + post(:create, params:) + expect(response).to have_http_status(:unprocessable_entity) + expect(JSON.parse(response.body)).to eq( + { + 'errors' => [{ + 'title' => 'Unprocessable Entity', + 'detail' => 'Test Error!', + 'code' => '422', + 'source' => 'FormAttachment.set_file_data', + 'status' => '422' + }] + } + ) + end + end + end +end diff --git a/spec/requests/swagger_spec.rb b/spec/requests/swagger_spec.rb index 5ba643b2a91..f9cd868be33 100644 --- a/spec/requests/swagger_spec.rb +++ b/spec/requests/swagger_spec.rb @@ -2057,97 +2057,6 @@ end end - describe 'higher_level_reviews' do - context 'GET' do - it 'documents higher_level_reviews 200' do - VCR.use_cassette('decision_review/HLR-SHOW-RESPONSE-200') do - expect(subject).to validate(:get, '/v0/higher_level_reviews/{uuid}', - 200, headers.merge('uuid' => '75f5735b-c41d-499c-8ae2-ab2740180254')) - end - end - - it 'documents higher_level_reviews 404' do - VCR.use_cassette('decision_review/HLR-SHOW-RESPONSE-404') do - expect(subject).to validate(:get, '/v0/higher_level_reviews/{uuid}', - 404, headers.merge('uuid' => '0')) - end - end - end - - context 'POST' do - it 'documents higher_level_reviews 200' do - VCR.use_cassette('decision_review/HLR-CREATE-RESPONSE-200') do - # HigherLevelReviewsController is a pass-through, and uses request.body directly (not params[]). - # The validate helper does not create a parsable request.body string that works with the controller. - allow_any_instance_of(V0::HigherLevelReviewsController).to receive(:request_body_hash).and_return( - VetsJsonSchema::EXAMPLES.fetch('HLR-CREATE-REQUEST-BODY') - ) - expect(subject).to validate(:post, '/v0/higher_level_reviews', 200, headers) - end - end - - it 'documents higher_level_reviews 422' do - VCR.use_cassette('decision_review/HLR-CREATE-RESPONSE-422') do - expect(subject).to validate( - :post, - '/v0/higher_level_reviews', - 422, - headers.merge('_data' => { '_json' => '' }) - ) - end - end - end - end - - describe 'HLR contestable_issues' do - let(:benefit_type) { 'compensation' } - let(:ssn) { '212222112' } - let(:status) { 200 } - - it 'documents contestable_issues 200' do - VCR.use_cassette("decision_review/HLR-GET-CONTESTABLE-ISSUES-RESPONSE-#{status}") do - expect(subject).to validate( - :get, - '/v0/higher_level_reviews/contestable_issues/{benefit_type}', - status, - headers.merge('benefit_type' => benefit_type) - ) - end - end - - context '404' do - let(:ssn) { '000000000' } - let(:status) { 404 } - - it 'documents contestable_issues 404' do - VCR.use_cassette("decision_review/HLR-GET-CONTESTABLE-ISSUES-RESPONSE-#{status}") do - expect(subject).to validate( - :get, - '/v0/higher_level_reviews/contestable_issues/{benefit_type}', - status, - headers.merge('benefit_type' => benefit_type) - ) - end - end - end - - context '422' do - let(:benefit_type) { 'apricot' } - let(:status) { 422 } - - it 'documents contestable_issues 422' do - VCR.use_cassette("decision_review/HLR-GET-CONTESTABLE-ISSUES-RESPONSE-#{status}") do - expect(subject).to validate( - :get, - '/v0/higher_level_reviews/contestable_issues/{benefit_type}', - status, - headers.merge('benefit_type' => benefit_type) - ) - end - end - end - end - describe 'NOD contestable_issues' do let(:ssn) { '212222112' } @@ -2178,49 +2087,6 @@ end end - describe 'notice_of_disagreements' do - context 'GET' do - it 'documents notice_of_disagreements 200' do - VCR.use_cassette('decision_review/NOD-SHOW-RESPONSE-200') do - expect(subject).to validate(:get, '/v0/notice_of_disagreements/{uuid}', - 200, headers.merge('uuid' => '1234567a-89b0-123c-d456-789e01234f56')) - end - end - - it 'documents higher_level_reviews 404' do - VCR.use_cassette('decision_review/NOD-SHOW-RESPONSE-404') do - expect(subject).to validate(:get, '/v0/notice_of_disagreements/{uuid}', - 404, headers.merge('uuid' => '0')) - end - end - end - - context 'POST' do - it 'documents notice_of_disagreements 200' do - VCR.use_cassette('decision_review/NOD-CREATE-RESPONSE-200') do - # NoticeOfDisagreementsController is a pass-through, and uses request.body directly (not params[]). - # The validate helper does not create a parsable request.body string that works with the controller. - allow_any_instance_of(V0::NoticeOfDisagreementsController).to receive(:request_body_hash).and_return( - JSON.parse(File.read(Rails.root.join('spec', 'fixtures', 'notice_of_disagreements', - 'valid_NOD_create_request.json'))) - ) - expect(subject).to validate(:post, '/v0/notice_of_disagreements', 200, headers) - end - end - - it 'documents notice_of_disagreements 422' do - VCR.use_cassette('decision_review/NOD-CREATE-RESPONSE--422') do - expect(subject).to validate( - :post, - '/v0/notice_of_disagreements', - 422, - headers.merge('_data' => { '_json' => '' }) - ) - end - end - end - end - describe 'appointments' do before do allow_any_instance_of(User).to receive(:icn).and_return('1234') diff --git a/spec/requests/v0/appeals_spec.rb b/spec/requests/v0/appeals_spec.rb index 35283fd279d..593f8ba0187 100644 --- a/spec/requests/v0/appeals_spec.rb +++ b/spec/requests/v0/appeals_spec.rb @@ -6,8 +6,6 @@ include SchemaMatchers appeals_endpoint = '/v0/appeals' - hlr_endpoint = '/v0/higher_level_reviews' - hlr_get_contestable_issues_endpoint = "#{hlr_endpoint}/contestable_issues" before { sign_in_as(user) } @@ -113,92 +111,5 @@ end end end - - describe 'GET /contestable_issues' do - let(:ssn_with_mockdata) { '212222112' } - let(:user) { build(:user, :loa3, ssn: ssn_with_mockdata) } - let(:benefit_type) { 'compensation' } - - it 'returns a valid response' do - VCR.use_cassette('decision_review/HLR-GET-CONTESTABLE-ISSUES-RESPONSE-200') do - get "#{hlr_get_contestable_issues_endpoint}/#{benefit_type}" - expect(response).to have_http_status(:ok) - expect { JSON.parse(response.body) }.not_to raise_error - expect(JSON.parse(response.body)).to be_a Hash - end - end - - context 'with invalid request' do - let(:benefit_type) { 'apricot' } - - it 'returns an invalid response' do - VCR.use_cassette('decision_review/HLR-GET-CONTESTABLE-ISSUES-RESPONSE-422') do - get "#{hlr_get_contestable_issues_endpoint}/#{benefit_type}" - expect(response).to have_http_status(:unprocessable_entity) - expect { JSON.parse(response.body) }.not_to raise_error - expect(JSON.parse(response.body)).to be_a Hash - end - end - end - - context 'with veteran not found' do - before do - allow_any_instance_of(User).to receive(:ssn).and_return('000000000') - end - - it 'returns 404' do - VCR.use_cassette('decision_review/HLR-GET-CONTESTABLE-ISSUES-RESPONSE-404') do - get "#{hlr_get_contestable_issues_endpoint}/#{benefit_type}" - expect(response).to have_http_status(:not_found) - end - end - end - end - - describe 'GET /higher_level_reviews' do - context 'with a valid higher review response' do - it 'higher level review endpoint returns a successful response' do - VCR.use_cassette('decision_review/HLR-SHOW-RESPONSE-200') do - get "#{hlr_endpoint}/75f5735b-c41d-499c-8ae2-ab2740180254" - expect(response).to have_http_status(:ok) - expect { JSON.parse(response.body) }.not_to raise_error - expect(JSON.parse(response.body)).to be_a Hash - end - end - end - - context 'with a higher review response id that does not exist' do - it 'returns a 404 error' do - VCR.use_cassette('decision_review/HLR-SHOW-RESPONSE-404') do - get "#{hlr_endpoint}/0" - expect(response).to have_http_status(:not_found) - end - end - end - end - - describe 'POST /higher_level_reviews' do - context 'with an accepted response' do - it 'higher level review endpoint returns a successful response' do - VCR.use_cassette('decision_review/HLR-CREATE-RESPONSE-200') do - request_body = VetsJsonSchema::EXAMPLES['HLR-CREATE-REQUEST-BODY'] - post hlr_endpoint, params: request_body.to_json - expect(response).to have_http_status(:ok) - expect { JSON.parse(response.body) }.not_to raise_error - expect(JSON.parse(response.body)).to be_a Hash - end - end - end - - context 'with a malformed request' do - it 'higher level review endpoint returns a 400 error' do - VCR.use_cassette('decision_review/HLR-CREATE-RESPONSE-422') do - post hlr_endpoint - expect(response).to have_http_status(:unprocessable_entity) - expect(JSON.parse(response.body)['errors'][0]['detail']).to eq "The request body isn't a JSON object" - end - end - end - end end end diff --git a/spec/requests/v0/higher_level_reviews/contestable_issues_spec.rb b/spec/requests/v0/higher_level_reviews/contestable_issues_spec.rb deleted file mode 100644 index ea83aa552ec..00000000000 --- a/spec/requests/v0/higher_level_reviews/contestable_issues_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'support/controller_spec_helper' - -RSpec.describe 'V0::HigherLevelReviews::ContestableIssues', type: :request do - let(:user) { build(:user, :loa3) } - - before { sign_in_as(user) } - - describe '#index' do - def personal_information_logs - PersonalInformationLog.where 'error_class like ?', - 'V0::HigherLevelReviews::ContestableIssuesController#index exception % (HLR)' - end - - subject { get '/v0/higher_level_reviews/contestable_issues/compensation' } - - it 'fetches issues that the Veteran could contest via a higher-level review' do - VCR.use_cassette('decision_review/HLR-GET-CONTESTABLE-ISSUES-RESPONSE-200') do - subject - expect(response).to be_successful - expect(JSON.parse(response.body)['data']).to be_an Array - end - end - - it 'adds to the PersonalInformationLog when an exception is thrown' do - VCR.use_cassette('decision_review/HLR-GET-CONTESTABLE-ISSUES-RESPONSE-404') do - expect(personal_information_logs.count).to be 0 - subject - expect(personal_information_logs.count).to be 1 - pil = personal_information_logs.first - expect(pil.data['user']).to be_truthy - expect(pil.data['error']).to be_truthy - end - end - end -end diff --git a/spec/requests/v0/higher_level_reviews_spec.rb b/spec/requests/v0/higher_level_reviews_spec.rb deleted file mode 100644 index c74d7ad67e6..00000000000 --- a/spec/requests/v0/higher_level_reviews_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'support/controller_spec_helper' - -RSpec.describe 'V0::HigherLevelReviews', type: :request do - let(:user) { build(:user, :loa3) } - let(:headers) { { 'CONTENT_TYPE' => 'application/json' } } - - before { sign_in_as(user) } - - describe '#create' do - def personal_information_logs - PersonalInformationLog.where 'error_class like ?', 'V0::HigherLevelReviewsController#create exception % (HLR)' - end - - subject do - post '/v0/higher_level_reviews', - params: VetsJsonSchema::EXAMPLES.fetch('HLR-CREATE-REQUEST-BODY').to_json, - headers: - end - - it 'creates an HLR' do - VCR.use_cassette('decision_review/HLR-CREATE-RESPONSE-200') do - subject - expect(response).to be_successful - appeal_uuid = JSON.parse(response.body)['data']['id'] - expect(AppealSubmission.where(submitted_appeal_uuid: appeal_uuid).first).to be_truthy - # SavedClaim should be created with request data - saved_claim = SavedClaim::HigherLevelReview.find_by(guid: appeal_uuid) - expect(saved_claim.form).to eq(VetsJsonSchema::EXAMPLES.fetch('HLR-CREATE-REQUEST-BODY').to_json) - end - end - - it 'adds to the PersonalInformationLog when an exception is thrown' do - VCR.use_cassette('decision_review/HLR-CREATE-RESPONSE-422') do - expect(personal_information_logs.count).to be 0 - subject - expect(personal_information_logs.count).to be 1 - pil = personal_information_logs.first - %w[ - first_name last_name birls_id icn edipi mhv_correlation_id - participant_id vet360_id ssn assurance_level birth_date - ].each { |key| expect(pil.data['user'][key]).to be_truthy } - %w[message backtrace key response_values original_status original_body] - .each { |key| expect(pil.data['error'][key]).to be_truthy } - expect(pil.data['additional_data']['request']['body']).not_to be_empty - end - end - end -end diff --git a/spec/requests/v0/notice_of_disagreements_spec.rb b/spec/requests/v0/notice_of_disagreements_spec.rb deleted file mode 100644 index 363cde0fe75..00000000000 --- a/spec/requests/v0/notice_of_disagreements_spec.rb +++ /dev/null @@ -1,116 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'support/controller_spec_helper' - -RSpec.describe 'V0::NoticeOfDisagreements', type: :request do - let(:user) { build(:user, :loa3) } - let(:headers) { { 'CONTENT_TYPE' => 'application/json' } } - - before { sign_in_as(user) } - - describe '#create' do - def personal_information_logs - PersonalInformationLog.where 'error_class like ?', 'V0::NoticeOfDisagreementsController#create exception % (NOD)' - end - - subject { post '/v0/notice_of_disagreements', params: body.to_json, headers: } - - let(:body) do - JSON.parse Rails.root.join('spec', 'fixtures', 'notice_of_disagreements', - 'valid_NOD_create_request.json').read - end - - it 'creates an NOD' do - VCR.use_cassette('decision_review/NOD-CREATE-RESPONSE-200') do - allow(Rails.logger).to receive(:info) - expect(Rails.logger).to receive(:info).with({ - message: 'Overall claim submission success!', - user_uuid: user.uuid, - action: 'Overall claim submission', - form_id: '10182', - upstream_system: nil, - downstream_system: 'Lighthouse', - is_success: true, - http: { - status_code: 200, - body: '[Redacted]' - }, - version_number: 'v1' - }) - allow(StatsD).to receive(:increment) - expect(StatsD).to receive(:increment).with('decision_review.form_10182.overall_claim_submission.success') - expect(StatsD).to receive(:increment).with('nod_evidence_upload.v1.queued') - previous_appeal_submission_ids = AppealSubmission.all.pluck :submitted_appeal_uuid - subject - expect(response).to be_successful - parsed_response = JSON.parse(response.body) - id = parsed_response['data']['id'] - expect(previous_appeal_submission_ids).not_to include id - appeal_submission = AppealSubmission.find_by(submitted_appeal_uuid: id) - expect(appeal_submission.board_review_option).to eq('evidence_submission') - expect(appeal_submission.upload_metadata).to eq({ - 'veteranFirstName' => user.first_name, - 'veteranLastName' => user.last_name, - 'zipCode' => user.postal_code, - 'fileNumber' => user.ssn.to_s.strip, - 'source' => 'Vets.gov', - 'businessLine' => 'BVA' - }.to_json) - appeal_submission_uploads = AppealSubmissionUpload.where(appeal_submission:) - expect(appeal_submission_uploads.count).to eq 1 - expect(DecisionReview::SubmitUpload).to have_enqueued_sidekiq_job(appeal_submission_uploads.first.id) - # SavedClaim should be created with request data - saved_claim = SavedClaim::NoticeOfDisagreement.find_by(guid: id) - expect(JSON.parse(saved_claim.form)).to eq(body) - end - end - - it 'adds to the PersonalInformationLog when an exception is thrown' do - VCR.use_cassette('decision_review/NOD-CREATE-RESPONSE-422') do - allow(Rails.logger).to receive(:error) - expect(Rails.logger).to receive(:error).with({ - message: 'Overall claim submission failure!', - user_uuid: user.uuid, - action: 'Overall claim submission', - form_id: '10182', - upstream_system: nil, - downstream_system: 'Lighthouse', - is_success: false, - http: { - status_code: 422, - body: anything - }, - version_number: 'v1' - }) - allow(StatsD).to receive(:increment) - expect(StatsD).to receive(:increment).with('decision_review.form_10182.overall_claim_submission.failure') - expect(personal_information_logs.count).to be 0 - subject - expect(personal_information_logs.count).to be 1 - pil = personal_information_logs.first - %w[ - first_name last_name birls_id icn edipi mhv_correlation_id - participant_id vet360_id ssn assurance_level birth_date - ].each { |key| expect(pil.data['user'][key]).to be_truthy } - %w[message backtrace key response_values original_status original_body] - .each { |key| expect(pil.data['error'][key]).to be_truthy } - expect(pil.data['additional_data']['request']['body']).not_to be_empty - end - end - end - - describe '#show' do - subject { get "/v0/notice_of_disagreements/#{uuid}" } - - let(:uuid) { '1234567a-89b0-123c-d456-789e01234f56' } - - it 'shows an HLR' do - VCR.use_cassette('decision_review/NOD-SHOW-RESPONSE-200') do - subject - expect(response).to be_successful - expect(JSON.parse(response.body)['data']['id']).to eq uuid - end - end - end -end From 70d037b4a90d5fdaeff3f35297b4124679e6d290 Mon Sep 17 00:00:00 2001 From: stevenjcumming <134282106+stevenjcumming@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:06:57 -0400 Subject: [PATCH 26/31] Reorganize VBA Documents & Veterans Request Specs (#18273) * reorganize vba_documents request specs * reorganize veteran request specs --- .../docs/v1/api_spec.rb} | 2 +- .../internal/v1/upload_complete_spec.rb} | 4 +-- .../spec/requests/metadata_spec.rb | 13 ++++++++ .../v1/healthcheck_spec.rb} | 9 +----- .../v1/uploads/reports_spec.rb} | 8 ++--- .../v1/uploads_spec.rb} | 20 ++++++------ .../v2/uploads/reports_spec.rb} | 6 ++-- .../v2/uploads/submit_spec.rb} | 31 ++++++++++--------- .../v2/uploads_spec.rb} | 22 ++++++------- .../veteran/spec/requests/v0/apidocs_spec.rb | 2 +- .../other_accredited_representatives_spec.rb | 2 +- .../find_rep_spec.rb} | 2 +- .../v0/vso_accredited_representatives_spec.rb | 2 +- 13 files changed, 65 insertions(+), 58 deletions(-) rename modules/vba_documents/spec/{request/v1/api_docs_request_spec.rb => requests/docs/v1/api_spec.rb} (77%) rename modules/vba_documents/spec/{request/v1/upload_complete_request_spec.rb => requests/internal/v1/upload_complete_spec.rb} (98%) create mode 100644 modules/vba_documents/spec/requests/metadata_spec.rb rename modules/vba_documents/spec/{request/metadata_request_spec.rb => requests/v1/healthcheck_spec.rb} (96%) rename modules/vba_documents/spec/{request/v1/reports_request_spec.rb => requests/v1/uploads/reports_spec.rb} (95%) rename modules/vba_documents/spec/{request/v1/uploads_request_spec.rb => requests/v1/uploads_spec.rb} (96%) rename modules/vba_documents/spec/{request/v2/reports_request_spec.rb => requests/v2/uploads/reports_spec.rb} (95%) rename modules/vba_documents/spec/{request/v2/uploads_request_submission_spec.rb => requests/v2/uploads/submit_spec.rb} (93%) rename modules/vba_documents/spec/{request/v2/uploads_request_spec.rb => requests/v2/uploads_spec.rb} (96%) rename modules/veteran/spec/requests/v0/{representatives_spec.rb => representatives/find_rep_spec.rb} (92%) diff --git a/modules/vba_documents/spec/request/v1/api_docs_request_spec.rb b/modules/vba_documents/spec/requests/docs/v1/api_spec.rb similarity index 77% rename from modules/vba_documents/spec/request/v1/api_docs_request_spec.rb rename to modules/vba_documents/spec/requests/docs/v1/api_spec.rb index 787366beac4..f09b1555e8a 100644 --- a/modules/vba_documents/spec/request/v1/api_docs_request_spec.rb +++ b/modules/vba_documents/spec/requests/docs/v1/api_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'VBA Document Uploads Documentation Endpoint', type: :request do +RSpec.describe 'VBADocument::Docs::V1::Api', type: :request do describe '#get /docs/v1/api' do it 'returns swagger JSON' do get '/services/vba_documents/docs/v1/api' diff --git a/modules/vba_documents/spec/request/v1/upload_complete_request_spec.rb b/modules/vba_documents/spec/requests/internal/v1/upload_complete_spec.rb similarity index 98% rename from modules/vba_documents/spec/request/v1/upload_complete_request_spec.rb rename to modules/vba_documents/spec/requests/internal/v1/upload_complete_spec.rb index f609d5c5894..08c2b4e66c0 100644 --- a/modules/vba_documents/spec/request/v1/upload_complete_request_spec.rb +++ b/modules/vba_documents/spec/requests/internal/v1/upload_complete_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'VBA Document SNS upload complete notification', type: :request do +RSpec.describe 'VBADocument::Internal::V1::UploadComplete', type: :request do context 'with a subscriptionconfirmation message type' do # rubocop:disable Layout/LineLength let(:headers) do @@ -214,7 +214,7 @@ # rubocop:enable Layout/LineLength - xit 'responds with a parameter missing error' do + it 'responds with a parameter missing error', skip: 'temporarily skip not working' do with_settings(Settings.vba_documents.sns, 'topic_arns' => ['arn:aws:sns:us-west-2:123456789012:MyTopic'], 'region' => 'us-gov-west-1') do diff --git a/modules/vba_documents/spec/requests/metadata_spec.rb b/modules/vba_documents/spec/requests/metadata_spec.rb new file mode 100644 index 00000000000..174fecdf82e --- /dev/null +++ b/modules/vba_documents/spec/requests/metadata_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'vba_documents/health_checker' + +RSpec.describe 'VBADocument::V1::Metadata', type: :request do + describe '#get /metadata' do + it 'returns metadata JSON' do + get '/services/vba_documents/metadata' + expect(response).to have_http_status(:ok) + end + end +end diff --git a/modules/vba_documents/spec/request/metadata_request_spec.rb b/modules/vba_documents/spec/requests/v1/healthcheck_spec.rb similarity index 96% rename from modules/vba_documents/spec/request/metadata_request_spec.rb rename to modules/vba_documents/spec/requests/v1/healthcheck_spec.rb index b2912501470..775039ca3b6 100644 --- a/modules/vba_documents/spec/request/metadata_request_spec.rb +++ b/modules/vba_documents/spec/requests/v1/healthcheck_spec.rb @@ -3,14 +3,7 @@ require 'rails_helper' require 'vba_documents/health_checker' -RSpec.describe 'VBA Documents Metadata Endpoint', type: :request do - describe '#get /metadata' do - it 'returns metadata JSON' do - get '/services/vba_documents/metadata' - expect(response).to have_http_status(:ok) - end - end - +RSpec.describe 'VBADocument::V1::Healthcheck', type: :request do describe '#healthcheck' do context 'v1' do it 'returns a successful health check' do diff --git a/modules/vba_documents/spec/request/v1/reports_request_spec.rb b/modules/vba_documents/spec/requests/v1/uploads/reports_spec.rb similarity index 95% rename from modules/vba_documents/spec/request/v1/reports_request_spec.rb rename to modules/vba_documents/spec/requests/v1/uploads/reports_spec.rb index 898f70c4655..7976721cff3 100644 --- a/modules/vba_documents/spec/request/v1/reports_request_spec.rb +++ b/modules/vba_documents/spec/requests/v1/uploads/reports_spec.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true require 'rails_helper' -require_relative '../../support/vba_document_fixtures' +require_relative '../../../support/vba_document_fixtures' require 'vba_documents/pdf_inspector' -require_relative '../../../app/serializers/vba_documents/upload_serializer' +require_relative '../../../../app/serializers/vba_documents/upload_serializer' -RSpec.describe 'VBA Document Uploads Report Endpoint', type: :request do +RSpec.describe 'VBADocument::V1::Uploads::Report', type: :request do describe '#create /v1/uploads/report' do let(:upload) { FactoryBot.create(:upload_submission) } let(:pdf_info) { FactoryBot.create(:upload_submission, :status_uploaded, consumer_name: 'test consumer') } @@ -36,7 +36,7 @@ expect(ids).to include(upload2_received.guid) end - it 'silentlies skip status not returned from central mail' do + it 'silentlies skip status not returned from central mail', skip: 'Repeated examples' do params = [upload_received.guid, upload2_received.guid] post '/services/vba_documents/v1/uploads/report', params: { ids: params } expect(response).to have_http_status(:ok) diff --git a/modules/vba_documents/spec/request/v1/uploads_request_spec.rb b/modules/vba_documents/spec/requests/v1/uploads_spec.rb similarity index 96% rename from modules/vba_documents/spec/request/v1/uploads_request_spec.rb rename to modules/vba_documents/spec/requests/v1/uploads_spec.rb index d5cb941c892..40cf37f0fef 100644 --- a/modules/vba_documents/spec/request/v1/uploads_request_spec.rb +++ b/modules/vba_documents/spec/requests/v1/uploads_spec.rb @@ -7,12 +7,12 @@ require 'vba_documents/multipart_parser' require 'vba_documents/object_store' -RSpec.describe 'VBA Document Uploads Endpoint', type: :request, retry: 3 do +RSpec.describe 'VBADocument::V1::Uploads', retry: 3, type: :request do include VBADocuments::Fixtures let(:test_caller) { { 'caller' => 'tester' } } - let(:client_stub) { instance_double('CentralMail::Service') } - let(:faraday_response) { instance_double('Faraday::Response') } + let(:client_stub) { instance_double(CentralMail::Service) } + let(:faraday_response) { instance_double(Faraday::Response) } let(:valid_metadata) { get_fixture('valid_metadata.json').read } let(:valid_doc) { get_fixture('valid_doc.pdf') } @@ -231,7 +231,7 @@ it "returns a 404 if feature (via setting) isn't enabled" do with_settings(Settings.vba_documents, enable_download_endpoint: false) do get "/services/vba_documents/v1/uploads/#{upload.guid}/download" - expect(response.status).to eq(404) + expect(response).to have_http_status(:not_found) end end @@ -249,14 +249,14 @@ allow(VBADocuments::MultipartParser).to receive(:parse) { valid_parts } get "/services/vba_documents/v1/uploads/#{upload.guid}/download" - expect(response.status).to eq(200) + expect(response).to have_http_status(:ok) expect(response.headers['Content-Type']).to eq('application/zip') end it '200S even with an invalid doc' do allow(VBADocuments::PayloadManager).to receive(:download_raw_file).and_return(invalid_doc) get "/services/vba_documents/v1/uploads/#{upload.guid}/download" - expect(response.status).to eq(200) + expect(response).to have_http_status(:ok) expect(response.headers['Content-Type']).to eq('application/zip') end @@ -274,7 +274,7 @@ allow(VBADocuments::MultipartParser).to receive(:parse) { valid_parts } get "/services/vba_documents/v1/uploads/#{upload.guid}/download" - expect(response.status).to eq(404) + expect(response).to have_http_status(:not_found) end end @@ -308,7 +308,7 @@ allow(request_validator).to receive(:validate).and_return(successful_validation_result) post request_path - expect(response.status).to eq(200) + expect(response).to have_http_status(:ok) expect(response.body).to eq(successful_validation_result.to_json) end @@ -317,14 +317,14 @@ allow(request_validator).to receive(:validate).and_return(failed_validation_result) post request_path - expect(response.status).to eq(422) + expect(response).to have_http_status(:unprocessable_entity) expect(response.body).to eq(failed_validation_result.to_json) end it "returns a 404 if feature (via setting) isn't enabled" do with_settings(Settings.vba_documents, enable_validate_document_endpoint: false) do post request_path - expect(response.status).to eq(404) + expect(response).to have_http_status(:not_found) end end end diff --git a/modules/vba_documents/spec/request/v2/reports_request_spec.rb b/modules/vba_documents/spec/requests/v2/uploads/reports_spec.rb similarity index 95% rename from modules/vba_documents/spec/request/v2/reports_request_spec.rb rename to modules/vba_documents/spec/requests/v2/uploads/reports_spec.rb index aca548fc49d..aff1aa376cb 100644 --- a/modules/vba_documents/spec/request/v2/reports_request_spec.rb +++ b/modules/vba_documents/spec/requests/v2/uploads/reports_spec.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true require 'rails_helper' -require_relative '../../support/vba_document_fixtures' +require_relative '../../../support/vba_document_fixtures' require 'vba_documents/pdf_inspector' -require_relative '../../../app/serializers/vba_documents/upload_serializer' +require_relative '../../../../app/serializers/vba_documents/upload_serializer' -RSpec.describe 'VBA Document Uploads Report Endpoint', type: :request do +RSpec.describe 'VBADocument::V2::Uploads::Report', type: :request do include VBADocuments::Fixtures load('./modules/vba_documents/config/routes.rb') diff --git a/modules/vba_documents/spec/request/v2/uploads_request_submission_spec.rb b/modules/vba_documents/spec/requests/v2/uploads/submit_spec.rb similarity index 93% rename from modules/vba_documents/spec/request/v2/uploads_request_submission_spec.rb rename to modules/vba_documents/spec/requests/v2/uploads/submit_spec.rb index d937191510f..127ec218ecd 100644 --- a/modules/vba_documents/spec/request/v2/uploads_request_submission_spec.rb +++ b/modules/vba_documents/spec/requests/v2/uploads/submit_spec.rb @@ -2,17 +2,18 @@ require 'rails_helper' require './lib/central_mail/utilities' -require_relative '../../support/vba_document_fixtures' +require_relative '../../../support/vba_document_fixtures' # rubocop:disable Style/OptionalBooleanParameter -RSpec.describe 'VBA Document Uploads Endpoint', type: :request, retry: 3 do +RSpec.describe 'VBADocument::V2::Uploads::Submit', retry: 3, type: :request do include VBADocuments::Fixtures load('./modules/vba_documents/config/routes.rb') # need a larger limit for sending raw data (base_64 for example) Rack::Utils.key_space_limit = 65_536 * 5 - SUBMIT_ENDPOINT = '/services/vba_documents/v2/uploads/submit' + + let(:submit_endpoint) { '/services/vba_documents/v2/uploads/submit' } def build_fixture(fixture, is_metadata = false, is_erb = false) fixture_path = if is_erb && is_metadata @@ -89,7 +90,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) end it 'returns a UUID with status of uploaded and populated pdf metadata with a valid post' do - post SUBMIT_ENDPOINT, + post submit_endpoint, params: {}.merge(valid_metadata).merge(valid_content).merge(valid_attachments) expect(response).to have_http_status(:ok) json = JSON.parse(response.body) @@ -104,7 +105,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) end it 'processes base64 requests' do - post SUBMIT_ENDPOINT, params: get_fixture('base_64').read + post submit_endpoint, params: get_fixture('base_64').read expect(response).to have_http_status(:ok) json = JSON.parse(response.body) @attributes = json['data']['attributes'] @@ -119,7 +120,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) let(:params) { {}.merge(valid_metadata).merge(valid_content).merge(invalid_attachment_oversized) } it 'returns a UUID with status of error' do - post(SUBMIT_ENDPOINT, params:) + post(submit_endpoint, params:) expect(response).to have_http_status(:bad_request) json = JSON.parse(response.body) @attributes = json['data']['attributes'] @@ -135,7 +136,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) %i[dashes_slashes_first_last valid_metadata_space_in_name].each do |allowed| it "allows #{allowed} in names" do - post SUBMIT_ENDPOINT, + post submit_endpoint, params: {}.merge(send(allowed)).merge(valid_content) expect(response).to have_http_status(:ok) end @@ -144,7 +145,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) %i[missing_first missing_last bad_with_digits_first bad_with_funky_characters_last name_too_long_metadata].each do |bad| it "returns an error if the name field #{bad} is missing or has bad characters" do - post SUBMIT_ENDPOINT, + post submit_endpoint, params: {}.merge(send(bad)).merge(valid_content) expect(response).to have_http_status(:bad_request) json = JSON.parse(response.body) @@ -156,7 +157,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) end it 'returns an error when a content is missing' do - post SUBMIT_ENDPOINT, + post submit_endpoint, params: {}.merge(valid_metadata).merge(invalid_content_missing).merge(valid_attachments) expect(response).to have_http_status(:bad_request) json = JSON.parse(response.body) @@ -167,7 +168,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) end it 'returns an error when an attachment is missing' do - post SUBMIT_ENDPOINT, + post submit_endpoint, params: {}.merge(valid_metadata).merge(valid_content).merge(invalid_attachment_missing) expect(response).to have_http_status(:bad_request) json = JSON.parse(response.body) @@ -186,7 +187,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) StringIO.new(metadata.to_json), 'application/json', false, original_filename: 'metadata.json' ) } - post SUBMIT_ENDPOINT, params: {}.merge(metadata_file).merge(valid_content).merge(valid_attachments) + post submit_endpoint, params: {}.merge(metadata_file).merge(valid_content).merge(valid_attachments) expect(response).to have_http_status(:ok) json = JSON.parse(response.body) @attributes = json['data']['attributes'] @@ -206,7 +207,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) StringIO.new(metadata.to_json), 'application/json', false, original_filename: 'metadata.json' ) } - post SUBMIT_ENDPOINT, params: {}.merge(metadata_file).merge(valid_content).merge(valid_attachments) + post submit_endpoint, params: {}.merge(metadata_file).merge(valid_content).merge(valid_attachments) expect(response).to have_http_status(:bad_request) json = JSON.parse(response.body) @attributes = json['data']['attributes'] @@ -220,7 +221,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) it "Returns a 400 error when #{key} is nil" do # set key to be nil in metadata metadata = { metadata: invalidate_metadata(key) } - post SUBMIT_ENDPOINT, params: {}.merge(metadata).merge(valid_content).merge(valid_attachments) + post submit_endpoint, params: {}.merge(metadata).merge(valid_content).merge(valid_attachments) expect(response).to have_http_status(:bad_request) json = JSON.parse(response.body) @attributes = json['data']['attributes'] @@ -232,7 +233,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) it "Returns a 400 error when #{key} is missing" do # remove the key from metadata metadata = { metadata: invalidate_metadata(key, '', true) } - post SUBMIT_ENDPOINT, params: {}.merge(metadata).merge(valid_content).merge(valid_attachments) + post submit_endpoint, params: {}.merge(metadata).merge(valid_content).merge(valid_attachments) expect(response).to have_http_status(:bad_request) json = JSON.parse(response.body) @attributes = json['data']['attributes'] @@ -245,7 +246,7 @@ def invalidate_metadata(key, value = nil, delete_key = false) it "Returns an error when #{key} is not a string" do # make fileNumber a non-string value metadata = { metadata: invalidate_metadata(key, 123_456_789) } - post SUBMIT_ENDPOINT, params: {}.merge(metadata).merge(valid_content).merge(valid_attachments) + post submit_endpoint, params: {}.merge(metadata).merge(valid_content).merge(valid_attachments) expect(response).to have_http_status(:bad_request) json = JSON.parse(response.body) @attributes = json['data']['attributes'] diff --git a/modules/vba_documents/spec/request/v2/uploads_request_spec.rb b/modules/vba_documents/spec/requests/v2/uploads_spec.rb similarity index 96% rename from modules/vba_documents/spec/request/v2/uploads_request_spec.rb rename to modules/vba_documents/spec/requests/v2/uploads_spec.rb index 6e3ee5883c0..4278ca31e7e 100644 --- a/modules/vba_documents/spec/request/v2/uploads_request_spec.rb +++ b/modules/vba_documents/spec/requests/v2/uploads_spec.rb @@ -6,14 +6,14 @@ require_relative '../../support/vba_document_fixtures' require 'vba_documents/object_store' -RSpec.describe 'VBA Document Uploads Endpoint', type: :request, retry: 3 do +RSpec.describe 'VBADocument::V2::Uploads', retry: 3, type: :request do include VBADocuments::Fixtures load('./modules/vba_documents/config/routes.rb') let(:test_caller) { { 'caller' => 'tester' } } - let(:client_stub) { instance_double('CentralMail::Service') } - let(:faraday_response) { instance_double('Faraday::Response') } + let(:client_stub) { instance_double(CentralMail::Service) } + let(:faraday_response) { instance_double(Faraday::Response) } let(:valid_metadata) { get_fixture('valid_metadata.json').read } let(:valid_doc) { get_fixture('valid_doc.pdf') } let(:dev_headers) do @@ -36,7 +36,7 @@ allow(s3_object).to receive(:presigned_url).and_return(+'https://fake.s3.url/foo/guid') end - xit 'returns a UUID and location' do + it 'returns a UUID and location', skip: 'Temporarily skip examples not working' do with_settings(Settings.vba_documents.location, prefix: 'https://fake.s3.url/foo/', replacement: 'https://api.vets.gov/proxy/') do @@ -73,7 +73,7 @@ observers = observers_json if multipart_fashion == :text post vba_documents.v2_uploads_path, params: { - 'observers': observers + observers: }, headers: dev_headers expect(response).to have_http_status(:accepted) @@ -98,7 +98,7 @@ post vba_documents.v2_uploads_path, params: { - 'observers': observers + observers: }, headers: dev_headers expect(response).to have_http_status(:unprocessable_entity) @@ -111,7 +111,7 @@ post vba_documents.v2_uploads_path, params: { - 'observers': observers + observers: }, headers: dev_headers expect(response).to have_http_status(:unprocessable_entity) @@ -296,7 +296,7 @@ it "raises if settings aren't set" do with_settings(Settings.vba_documents, enable_download_endpoint: false) do get vba_documents.v2_upload_download_path(upload.guid) - expect(response.status).to eq(404) + expect(response).to have_http_status(:not_found) end end @@ -314,14 +314,14 @@ allow(VBADocuments::MultipartParser).to receive(:parse) { valid_parts } get vba_documents.v2_upload_download_path(upload.guid) - expect(response.status).to eq(200) + expect(response).to have_http_status(:ok) expect(response.headers['Content-Type']).to eq('application/zip') end it '200S even with an invalid doc' do allow(VBADocuments::PayloadManager).to receive(:download_raw_file).and_return(invalid_doc) get vba_documents.v2_upload_download_path(upload.guid) - expect(response.status).to eq(200) + expect(response).to have_http_status(:ok) expect(response.headers['Content-Type']).to eq('application/zip') end @@ -339,7 +339,7 @@ allow(VBADocuments::MultipartParser).to receive(:parse) { valid_parts } get vba_documents.v2_upload_download_path(upload.guid) - expect(response.status).to eq(404) + expect(response).to have_http_status(:not_found) end end end diff --git a/modules/veteran/spec/requests/v0/apidocs_spec.rb b/modules/veteran/spec/requests/v0/apidocs_spec.rb index 1ef280578cb..8d31ec703b2 100644 --- a/modules/veteran/spec/requests/v0/apidocs_spec.rb +++ b/modules/veteran/spec/requests/v0/apidocs_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'V0::ApidocsController', type: :request do +RSpec.describe 'Veteran::V0::Apidocs', type: :request do let(:openapi_version) { %w[openapi 3.0.0] } describe 'GET `index`' do diff --git a/modules/veteran/spec/requests/v0/other_accredited_representatives_spec.rb b/modules/veteran/spec/requests/v0/other_accredited_representatives_spec.rb index 47407f07e96..8a87f28835f 100644 --- a/modules/veteran/spec/requests/v0/other_accredited_representatives_spec.rb +++ b/modules/veteran/spec/requests/v0/other_accredited_representatives_spec.rb @@ -4,7 +4,7 @@ require_relative 'base_accredited_representatives_shared_spec' require_relative 'other_accredited_representatives_shared_spec' -RSpec.describe 'OtherAccreditedRepresentativesController', type: :request do +RSpec.describe 'Veteran::V0::OtherAccreditedRepresentatives', type: :request do let(:path) { '/services/veteran/v0/other_accredited_representatives' } before do diff --git a/modules/veteran/spec/requests/v0/representatives_spec.rb b/modules/veteran/spec/requests/v0/representatives/find_rep_spec.rb similarity index 92% rename from modules/veteran/spec/requests/v0/representatives_spec.rb rename to modules/veteran/spec/requests/v0/representatives/find_rep_spec.rb index 070e48fd1d1..216cfd24e41 100644 --- a/modules/veteran/spec/requests/v0/representatives_spec.rb +++ b/modules/veteran/spec/requests/v0/representatives/find_rep_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'VSO representative spec', type: :request do +RSpec.describe 'Veteran::V0::Representatives::FindRep', type: :request do let!(:representative) { FactoryBot.create(:representative, first_name: 'Bob', last_name: 'Smith', poa_codes: ['1B']) } it 'finds a VSO rep' do diff --git a/modules/veteran/spec/requests/v0/vso_accredited_representatives_spec.rb b/modules/veteran/spec/requests/v0/vso_accredited_representatives_spec.rb index af36b5557e0..6a05da30fd6 100644 --- a/modules/veteran/spec/requests/v0/vso_accredited_representatives_spec.rb +++ b/modules/veteran/spec/requests/v0/vso_accredited_representatives_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' require_relative 'base_accredited_representatives_shared_spec' -RSpec.describe 'VSOAccreditedRepresentativesController', type: :request do +RSpec.describe 'Veteran::V0::VSOAccreditedRepresentatives', type: :request do include_examples 'base_accredited_representatives_controller_shared_examples', '/services/veteran/v0/vso_accredited_representatives', 'veteran_service_officer' From edbb359578282e9dff88a8b3f9fc67de9abcbdb8 Mon Sep 17 00:00:00 2001 From: stevenjcumming <134282106+stevenjcumming@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:07:11 -0400 Subject: [PATCH 27/31] Reorganize VAOS Request Specs (#18272) * reorganize vaos request specs * lintin * fix failing test * linting * rename a couple of files and example groups --- .../vaos/v1/appointment_spec.rb} | 2 +- .../vaos/v1/healthcare_service_spec.rb} | 0 .../vaos/v1/location_spec.rb} | 0 .../vaos/v1/organization_spec.rb} | 2 +- .../vaos/v1/patient_spec.rb} | 0 .../vaos/v1/slot_spec.rb} | 0 .../vaos/v2/apidocs_spec.rb} | 2 +- .../vaos/v2/appointments_spec.rb} | 84 ++++++++++--------- .../v2/community_care/eligibility_spec.rb} | 2 +- .../vaos/v2/eligibility_spec.rb} | 2 +- .../vaos/v2/facilities_spec.rb} | 2 +- .../vaos/v2/locations/clinics_spec.rb} | 2 +- .../vaos/v2/locations/slots_spec.rb} | 2 +- .../v2/scheduling/configurations_spec.rb} | 2 +- 14 files changed, 52 insertions(+), 50 deletions(-) rename modules/vaos/spec/{request/v1/appointments_request_spec.rb => requests/vaos/v1/appointment_spec.rb} (99%) rename modules/vaos/spec/{request/v1/healthcare_service_request_spec.rb => requests/vaos/v1/healthcare_service_spec.rb} (100%) rename modules/vaos/spec/{request/v1/locations_request_spec.rb => requests/vaos/v1/location_spec.rb} (100%) rename modules/vaos/spec/{request/v1/organization_request_spec.rb => requests/vaos/v1/organization_spec.rb} (98%) rename modules/vaos/spec/{request/v1/patient_request_spec.rb => requests/vaos/v1/patient_spec.rb} (100%) rename modules/vaos/spec/{request/v1/slot_request_spec.rb => requests/vaos/v1/slot_spec.rb} (100%) rename modules/vaos/spec/{request/v2/apidocs_request_spec.rb => requests/vaos/v2/apidocs_spec.rb} (82%) rename modules/vaos/spec/{request/v2/appointments_request_spec.rb => requests/vaos/v2/appointments_spec.rb} (95%) rename modules/vaos/spec/{request/v2/cc_eligibility_request_spec.rb => requests/vaos/v2/community_care/eligibility_spec.rb} (97%) rename modules/vaos/spec/{request/v2/patients_request_spec.rb => requests/vaos/v2/eligibility_spec.rb} (97%) rename modules/vaos/spec/{request/v2/facilities_request_spec.rb => requests/vaos/v2/facilities_spec.rb} (98%) rename modules/vaos/spec/{request/v2/clinics_request_spec.rb => requests/vaos/v2/locations/clinics_spec.rb} (98%) rename modules/vaos/spec/{request/v2/available_slots_request_spec.rb => requests/vaos/v2/locations/slots_spec.rb} (99%) rename modules/vaos/spec/{request/v2/scheduling_configurations_request_spec.rb => requests/vaos/v2/scheduling/configurations_spec.rb} (97%) diff --git a/modules/vaos/spec/request/v1/appointments_request_spec.rb b/modules/vaos/spec/requests/vaos/v1/appointment_spec.rb similarity index 99% rename from modules/vaos/spec/request/v1/appointments_request_spec.rb rename to modules/vaos/spec/requests/vaos/v1/appointment_spec.rb index 62d1b624fee..300b20a3eaa 100644 --- a/modules/vaos/spec/request/v1/appointments_request_spec.rb +++ b/modules/vaos/spec/requests/vaos/v1/appointment_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Appointment', type: :request do +RSpec.describe 'VAOS::V1::Appointment', type: :request do include SchemaMatchers before do diff --git a/modules/vaos/spec/request/v1/healthcare_service_request_spec.rb b/modules/vaos/spec/requests/vaos/v1/healthcare_service_spec.rb similarity index 100% rename from modules/vaos/spec/request/v1/healthcare_service_request_spec.rb rename to modules/vaos/spec/requests/vaos/v1/healthcare_service_spec.rb diff --git a/modules/vaos/spec/request/v1/locations_request_spec.rb b/modules/vaos/spec/requests/vaos/v1/location_spec.rb similarity index 100% rename from modules/vaos/spec/request/v1/locations_request_spec.rb rename to modules/vaos/spec/requests/vaos/v1/location_spec.rb diff --git a/modules/vaos/spec/request/v1/organization_request_spec.rb b/modules/vaos/spec/requests/vaos/v1/organization_spec.rb similarity index 98% rename from modules/vaos/spec/request/v1/organization_request_spec.rb rename to modules/vaos/spec/requests/vaos/v1/organization_spec.rb index 3f503e467ac..359926a3802 100644 --- a/modules/vaos/spec/request/v1/organization_request_spec.rb +++ b/modules/vaos/spec/requests/vaos/v1/organization_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Organization', type: :request do +RSpec.describe 'VAOS::V1::Organization', type: :request do include SchemaMatchers before do diff --git a/modules/vaos/spec/request/v1/patient_request_spec.rb b/modules/vaos/spec/requests/vaos/v1/patient_spec.rb similarity index 100% rename from modules/vaos/spec/request/v1/patient_request_spec.rb rename to modules/vaos/spec/requests/vaos/v1/patient_spec.rb diff --git a/modules/vaos/spec/request/v1/slot_request_spec.rb b/modules/vaos/spec/requests/vaos/v1/slot_spec.rb similarity index 100% rename from modules/vaos/spec/request/v1/slot_request_spec.rb rename to modules/vaos/spec/requests/vaos/v1/slot_spec.rb diff --git a/modules/vaos/spec/request/v2/apidocs_request_spec.rb b/modules/vaos/spec/requests/vaos/v2/apidocs_spec.rb similarity index 82% rename from modules/vaos/spec/request/v2/apidocs_request_spec.rb rename to modules/vaos/spec/requests/vaos/v2/apidocs_spec.rb index 1a1214548e6..7f75f3ab4c4 100644 --- a/modules/vaos/spec/request/v2/apidocs_request_spec.rb +++ b/modules/vaos/spec/requests/vaos/v2/apidocs_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'rails_helper' -RSpec.describe VAOS::V2::ApidocsController, type: :request do +RSpec.describe 'VAOS::V2::Apidocs', type: :request do describe 'GET /vaos/v2/apidocs' do it 'renders the apidocs as json' do get '/vaos/v2/apidocs' diff --git a/modules/vaos/spec/request/v2/appointments_request_spec.rb b/modules/vaos/spec/requests/vaos/v2/appointments_spec.rb similarity index 95% rename from modules/vaos/spec/request/v2/appointments_request_spec.rb rename to modules/vaos/spec/requests/vaos/v2/appointments_spec.rb index 296e5bc8044..10c31dc47b7 100644 --- a/modules/vaos/spec/request/v2/appointments_request_spec.rb +++ b/modules/vaos/spec/requests/vaos/v2/appointments_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe VAOS::V2::AppointmentsController, :skip_mvi, type: :request do +RSpec.describe 'VAOS::V2::Appointments', :skip_mvi, type: :request do include SchemaMatchers before do @@ -12,22 +12,24 @@ allow_any_instance_of(VAOS::UserService).to receive(:session).and_return('stubbed_token') end + let(:described_class) { VAOS::V2::AppointmentsController } + let(:mock_clinic) do { - 'service_name': 'service_name', - 'physical_location': 'physical_location' + service_name: 'service_name', + physical_location: 'physical_location' } end - let(:mock_clinic_without_physical_location) { { 'service_name': 'service_name' } } + let(:mock_clinic_without_physical_location) { { service_name: 'service_name' } } let(:mock_facility) do { - 'test': 'test', - 'id': '668', - 'name': 'COL OR 1', - 'timezone': { - 'time_zone_id': 'America/New_York' + test: 'test', + id: '668', + name: 'COL OR 1', + timezone: { + time_zone_id: 'America/New_York' } } end @@ -45,37 +47,37 @@ let(:mock_appt_location_openstruct) do OpenStruct.new({ - 'id': '983', - 'vistaSite': '983', - 'vastParent': '983', - 'type': 'va_facilities', - 'name': 'COL OR 1', - 'classification': 'VA Medical Center (VAMC)', - 'lat': 39.744507, - 'long': -104.830956, - 'website': 'https://www.denver.va.gov/locations/directions.asp', - 'phone': { - 'main': '307-778-7550', - 'fax': '307-778-7381', - 'pharmacy': '866-420-6337', - 'afterHours': '307-778-7550', - 'patientAdvocate': '307-778-7550 x7517', - 'mentalHealthClinic': '307-778-7349', - 'enrollmentCoordinator': '307-778-7550 x7579' + id: '983', + vistaSite: '983', + vastParent: '983', + type: 'va_facilities', + name: 'COL OR 1', + classification: 'VA Medical Center (VAMC)', + lat: 39.744507, + long: -104.830956, + website: 'https://www.denver.va.gov/locations/directions.asp', + phone: { + main: '307-778-7550', + fax: '307-778-7381', + pharmacy: '866-420-6337', + afterHours: '307-778-7550', + patientAdvocate: '307-778-7550 x7517', + mentalHealthClinic: '307-778-7349', + enrollmentCoordinator: '307-778-7550 x7579' }, - 'physicalAddress': { - 'type': 'physical', - 'line': ['2360 East Pershing Boulevard'], - 'city': 'Cheyenne', - 'state': 'WY', - 'postalCode': '82001-5356' + physicalAddress: { + type: 'physical', + line: ['2360 East Pershing Boulevard'], + city: 'Cheyenne', + state: 'WY', + postalCode: '82001-5356' }, - 'mobile': false, - 'healthService': %w[Audiology Cardiology DentalServices EmergencyCare Gastroenterology - Gynecology MentalHealthCare Nutrition Ophthalmology Optometry Orthopedics - Podiatry PrimaryCare SpecialtyCare UrgentCare Urology WomensHealth], - 'operatingStatus': { - 'code': 'NORMAL' + mobile: false, + healthService: %w[Audiology Cardiology DentalServices EmergencyCare Gastroenterology + Gynecology MentalHealthCare Nutrition Ophthalmology Optometry Orthopedics + Podiatry PrimaryCare SpecialtyCare UrgentCare Urology WomensHealth], + operatingStatus: { + code: 'NORMAL' } }) end @@ -632,7 +634,7 @@ def stub_clinics end describe 'GET appointment' do - context 'when the VAOS service returns a single appointment ' do + context 'when the VAOS service returns a single appointment' do before do Flipper.disable(:va_online_scheduling_use_vpg) end @@ -807,7 +809,7 @@ def stub_clinics Flipper.disable(:va_online_scheduling_enable_OH_cancellations) VCR.use_cassette('vaos/v2/appointments/cancel_appointment_400', match_requests_on: %i[method path query]) do put '/vaos/v2/appointments/42081', params: { status: 'cancelled' } - expect(response.status).to eq(400) + expect(response).to have_http_status(:bad_request) expect(JSON.parse(response.body)['errors'][0]['code']).to eq('VAOS_400') end end @@ -821,7 +823,7 @@ def stub_clinics it 'returns a 502 status code' do VCR.use_cassette('vaos/v2/appointments/cancel_appointment_500', match_requests_on: %i[method path query]) do put '/vaos/v2/appointments/35952', params: { status: 'cancelled' } - expect(response.status).to eq(502) + expect(response).to have_http_status(:bad_gateway) expect(JSON.parse(response.body)['errors'][0]['code']).to eq('VAOS_502') end end diff --git a/modules/vaos/spec/request/v2/cc_eligibility_request_spec.rb b/modules/vaos/spec/requests/vaos/v2/community_care/eligibility_spec.rb similarity index 97% rename from modules/vaos/spec/request/v2/cc_eligibility_request_spec.rb rename to modules/vaos/spec/requests/vaos/v2/community_care/eligibility_spec.rb index 505d3209ece..ca0a3b8a3e1 100644 --- a/modules/vaos/spec/request/v2/cc_eligibility_request_spec.rb +++ b/modules/vaos/spec/requests/vaos/v2/community_care/eligibility_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'rails_helper' -RSpec.describe 'vaos v2 community care eligibility', type: :request do +RSpec.describe 'VAOS::V2::CommunityCare::Eligibility', type: :request do include SchemaMatchers before do diff --git a/modules/vaos/spec/request/v2/patients_request_spec.rb b/modules/vaos/spec/requests/vaos/v2/eligibility_spec.rb similarity index 97% rename from modules/vaos/spec/request/v2/patients_request_spec.rb rename to modules/vaos/spec/requests/vaos/v2/eligibility_spec.rb index 20d13887637..79636b17f86 100644 --- a/modules/vaos/spec/request/v2/patients_request_spec.rb +++ b/modules/vaos/spec/requests/vaos/v2/eligibility_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'vaos patients', :skip_mvi, type: :request do +RSpec.describe 'VAOS::V2::Patients', :skip_mvi, type: :request do include SchemaMatchers before do diff --git a/modules/vaos/spec/request/v2/facilities_request_spec.rb b/modules/vaos/spec/requests/vaos/v2/facilities_spec.rb similarity index 98% rename from modules/vaos/spec/request/v2/facilities_request_spec.rb rename to modules/vaos/spec/requests/vaos/v2/facilities_spec.rb index 225ad713c15..dec9fb090e7 100644 --- a/modules/vaos/spec/request/v2/facilities_request_spec.rb +++ b/modules/vaos/spec/requests/vaos/v2/facilities_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'facilities', type: :request do +RSpec.describe 'VAOS::V2::Facilities', type: :request do include SchemaMatchers before do diff --git a/modules/vaos/spec/request/v2/clinics_request_spec.rb b/modules/vaos/spec/requests/vaos/v2/locations/clinics_spec.rb similarity index 98% rename from modules/vaos/spec/request/v2/clinics_request_spec.rb rename to modules/vaos/spec/requests/vaos/v2/locations/clinics_spec.rb index 0415d1cec7d..cead3af6b56 100644 --- a/modules/vaos/spec/request/v2/clinics_request_spec.rb +++ b/modules/vaos/spec/requests/vaos/v2/locations/clinics_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'clinics', type: :request do +RSpec.describe 'VAOS::V2::Locations::Clinics', type: :request do include SchemaMatchers before do diff --git a/modules/vaos/spec/request/v2/available_slots_request_spec.rb b/modules/vaos/spec/requests/vaos/v2/locations/slots_spec.rb similarity index 99% rename from modules/vaos/spec/request/v2/available_slots_request_spec.rb rename to modules/vaos/spec/requests/vaos/v2/locations/slots_spec.rb index b7e3f97863f..a55a1b9b98d 100644 --- a/modules/vaos/spec/request/v2/available_slots_request_spec.rb +++ b/modules/vaos/spec/requests/vaos/v2/locations/slots_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Available Slots Request', type: :request do +RSpec.describe 'VAOS::V2::Locations::Slots', type: :request do include SchemaMatchers before do diff --git a/modules/vaos/spec/request/v2/scheduling_configurations_request_spec.rb b/modules/vaos/spec/requests/vaos/v2/scheduling/configurations_spec.rb similarity index 97% rename from modules/vaos/spec/request/v2/scheduling_configurations_request_spec.rb rename to modules/vaos/spec/requests/vaos/v2/scheduling/configurations_spec.rb index f036a18d466..90b8136512a 100644 --- a/modules/vaos/spec/request/v2/scheduling_configurations_request_spec.rb +++ b/modules/vaos/spec/requests/vaos/v2/scheduling/configurations_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe VAOS::V2::SchedulingController, :skip_mvi, type: :request do +RSpec.describe 'VAOS::V2::Scheduling::Configurations', :skip_mvi, type: :request do include SchemaMatchers let(:inflection_header) { { 'X-Key-Inflection' => 'camel' } } From fff1b7e65bdef2ba5b03580a15f1928d267b3180 Mon Sep 17 00:00:00 2001 From: stevenjcumming <134282106+stevenjcumming@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:07:28 -0400 Subject: [PATCH 28/31] Reorganize TUD & TravelPay & VAForms Request Specs (#18257) * linting * reorganize tud request specs * reorganize travel_pay request specs * reorganize va_forms request specs * fix travel pay example group name * fix linting error --- .rubocop_todo.yml | 2 +- .../tud_accounts_spec.rb} | 6 +- .../tud_github_oauth_proxy_spec.rb | 6 +- .../travel_pay/claims_spec.rb} | 2 +- .../spec/requests/travel_pay/pings_spec.rb | 58 +++++++++++++++++++ ...adata_request_spec.rb => metadata_spec.rb} | 6 +- .../v0/apidocs_spec.rb} | 2 +- .../v0/forms_spec.rb} | 2 +- 8 files changed, 71 insertions(+), 13 deletions(-) rename modules/test_user_dashboard/spec/requests/{tud_accounts_request_spec.rb => test_user_dashboard/tud_accounts_spec.rb} (89%) rename modules/test_user_dashboard/spec/requests/{ => test_user_dashboard}/tud_github_oauth_proxy_spec.rb (83%) rename modules/travel_pay/spec/{controllers/claims_controller_spec.rb => requests/travel_pay/claims_spec.rb} (94%) create mode 100644 modules/travel_pay/spec/requests/travel_pay/pings_spec.rb rename modules/va_forms/spec/requests/{metadata_request_spec.rb => metadata_spec.rb} (92%) rename modules/va_forms/spec/requests/{v0/api_docs_request_spec.rb => va_forms/v0/apidocs_spec.rb} (80%) rename modules/va_forms/spec/requests/{v0/forms_request_spec.rb => va_forms/v0/forms_spec.rb} (98%) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 04eb8ce208f..83fd1803e94 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -673,7 +673,7 @@ RSpec/NoExpectationExample: - 'modules/check_in/spec/request/v2/sessions_request_spec.rb' - 'modules/claims_api/spec/requests/v1/disability_compensation_request_spec.rb' - 'modules/claims_api/spec/sidekiq/poa_vbms_updater_spec.rb' - - 'modules/va_forms/spec/requests/metadata_request_spec.rb' + - 'modules/va_forms/spec/requests/metadata_spec.rb' - 'spec/config/initializers/staccato_spec.rb' - 'spec/controllers/application_controller_spec.rb' - 'spec/controllers/v0/profile/ch33_bank_accounts_controller_spec.rb' diff --git a/modules/test_user_dashboard/spec/requests/tud_accounts_request_spec.rb b/modules/test_user_dashboard/spec/requests/test_user_dashboard/tud_accounts_spec.rb similarity index 89% rename from modules/test_user_dashboard/spec/requests/tud_accounts_request_spec.rb rename to modules/test_user_dashboard/spec/requests/test_user_dashboard/tud_accounts_spec.rb index 80643a5c8c5..c5d5b22aa2d 100644 --- a/modules/test_user_dashboard/spec/requests/tud_accounts_request_spec.rb +++ b/modules/test_user_dashboard/spec/requests/test_user_dashboard/tud_accounts_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Test User Dashboard', type: :request do +RSpec.describe 'TestUserDashboard::TudAccounts', type: :request do let(:rsa_private) { OpenSSL::PKey::RSA.new 2048 } let(:rsa_public) { rsa_private.public_key } let(:pub_key) { Base64.encode64(rsa_public.to_der) } @@ -14,7 +14,7 @@ it 'refuses the request' do get('/test_user_dashboard/tud_accounts') - expect(response.status).to eq 403 + expect(response).to have_http_status :forbidden expect(response.content_type).to eq 'text/html' end end @@ -32,7 +32,7 @@ it 'returns a 403' do get('/test_user_dashboard/tud_accounts', params: '', headers: { 'JWT' => 'invalid', 'PK' => pub_key }) - expect(response.status).to eq 403 + expect(response).to have_http_status :forbidden end end end diff --git a/modules/test_user_dashboard/spec/requests/tud_github_oauth_proxy_spec.rb b/modules/test_user_dashboard/spec/requests/test_user_dashboard/tud_github_oauth_proxy_spec.rb similarity index 83% rename from modules/test_user_dashboard/spec/requests/tud_github_oauth_proxy_spec.rb rename to modules/test_user_dashboard/spec/requests/test_user_dashboard/tud_github_oauth_proxy_spec.rb index 0f6c3c36af3..e4291cc8166 100644 --- a/modules/test_user_dashboard/spec/requests/tud_github_oauth_proxy_spec.rb +++ b/modules/test_user_dashboard/spec/requests/test_user_dashboard/tud_github_oauth_proxy_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe TestUserDashboard::TudGithubOAuthProxyController do +Rspec.describe 'TestUserDashboard::TudGithubOAuthProxy', type: :request do describe '#index' do context 'when the token is generated successfully' do before do @@ -12,7 +12,7 @@ it 'returns the access token as json' do get('/test_user_dashboard/tud_github_oauth_proxy?code=123') - expect(response.status).to be(200) + expect(response).to have_http_status(:ok) expect(response.content_type).to include('application/json') expect(response.body).to eql('{"access_token":"345"}') end @@ -25,7 +25,7 @@ expect_any_instance_of(SentryLogging).to receive(:log_exception_to_sentry) get('/test_user_dashboard/tud_github_oauth_proxy?code=123') - expect(response.status).to be(400) + expect(response).to have_http_status(:bad_request) expect(response.body).to eql(' ') end end diff --git a/modules/travel_pay/spec/controllers/claims_controller_spec.rb b/modules/travel_pay/spec/requests/travel_pay/claims_spec.rb similarity index 94% rename from modules/travel_pay/spec/controllers/claims_controller_spec.rb rename to modules/travel_pay/spec/requests/travel_pay/claims_spec.rb index 13f90cb5950..1b665428b75 100644 --- a/modules/travel_pay/spec/controllers/claims_controller_spec.rb +++ b/modules/travel_pay/spec/requests/travel_pay/claims_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe TravelPay::ClaimsController, type: :request do +RSpec.describe 'TravelPay::Claims', type: :request do let(:user) { build(:user) } before do diff --git a/modules/travel_pay/spec/requests/travel_pay/pings_spec.rb b/modules/travel_pay/spec/requests/travel_pay/pings_spec.rb new file mode 100644 index 00000000000..19447776c64 --- /dev/null +++ b/modules/travel_pay/spec/requests/travel_pay/pings_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'TravelPay::Pings', type: :request do + let(:user) { build(:user) } + + before do + sign_in(user) + Flipper.disable :travel_pay_power_switch + end + + describe '#ping' do + context 'the feature switch is enabled' do + before do + Flipper.enable :travel_pay_power_switch + end + + it 'requests a token and sends a ping to BTSSS' do + VCR.use_cassette('travel_pay/ping') do + get '/travel_pay/pings/ping' + expect(response.body).to include('Received ping from upstream server with status 200') + end + end + end + + context 'the feature switch is disabled' do + it 'raises the proper error' do + get '/travel_pay/pings/ping' + expect(response).to have_http_status(:forbidden) + expect(response.body).to include('You do not have access to travel pay') + end + end + end + + describe '#authorized_ping' do + context 'the feature switch is enabled' do + before do + Flipper.enable :travel_pay_power_switch + end + + it 'requests a token and sends a ping to BTSSS' do + VCR.use_cassette('travel_pay/auth_ping', match_requests_on: %i[method path]) do + get '/travel_pay/pings/authorized_ping', headers: { 'Authorization' => 'Bearer vagov_token' } + expect(response.body).to include('Received authorized ping from upstream server with status 200') + end + end + end + + context 'the feature switch is disabled' do + it 'raises the proper error' do + get '/travel_pay/pings/authorized_ping', headers: { 'Authorization' => 'Bearer vagov_token' } + expect(response).to have_http_status(:forbidden) + expect(response.body).to include('You do not have access to travel pay') + end + end + end +end diff --git a/modules/va_forms/spec/requests/metadata_request_spec.rb b/modules/va_forms/spec/requests/metadata_spec.rb similarity index 92% rename from modules/va_forms/spec/requests/metadata_request_spec.rb rename to modules/va_forms/spec/requests/metadata_spec.rb index db188c26add..ec4e9715c0a 100644 --- a/modules/va_forms/spec/requests/metadata_request_spec.rb +++ b/modules/va_forms/spec/requests/metadata_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' require 'va_forms/health_checker' -RSpec.describe 'VA Forms Metadata Endpoint', type: :request do +RSpec.describe 'VAForms::Metadata', type: :request do describe '#get /metadata' do it 'returns metadata JSON' do get '/services/va_forms/metadata' @@ -83,11 +83,11 @@ def unhealthy_checks(path) context 'v0' do path = '/services/va_forms/v0/upstream_healthcheck' - it 'returns correct response and status when healthy' do + it 'returns correct response and status when healthy', skip: 'No expectation in this example' do healthy_checks(path) end - it 'returns correct status when cms is not healthy' do + it 'returns correct status when cms is not healthy', skip: 'No expectation in this example' do unhealthy_checks(path) end end diff --git a/modules/va_forms/spec/requests/v0/api_docs_request_spec.rb b/modules/va_forms/spec/requests/va_forms/v0/apidocs_spec.rb similarity index 80% rename from modules/va_forms/spec/requests/v0/api_docs_request_spec.rb rename to modules/va_forms/spec/requests/va_forms/v0/apidocs_spec.rb index c57632e9359..c3317a89523 100644 --- a/modules/va_forms/spec/requests/v0/api_docs_request_spec.rb +++ b/modules/va_forms/spec/requests/va_forms/v0/apidocs_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Forms Documentation Endpoint', type: :request do +RSpec.describe 'VAForms::V0::Apidocs', type: :request do describe '#get /docs/v1/api' do it 'returns Open API Spec v3 JSON' do get '/services/va_forms/docs/v0/api' diff --git a/modules/va_forms/spec/requests/v0/forms_request_spec.rb b/modules/va_forms/spec/requests/va_forms/v0/forms_spec.rb similarity index 98% rename from modules/va_forms/spec/requests/v0/forms_request_spec.rb rename to modules/va_forms/spec/requests/va_forms/v0/forms_spec.rb index a1632473a61..4019f264fae 100644 --- a/modules/va_forms/spec/requests/v0/forms_request_spec.rb +++ b/modules/va_forms/spec/requests/va_forms/v0/forms_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'VA Forms', type: :request do +RSpec.describe 'VAForms::V0::Forms', type: :request do include SchemaMatchers let!(:form) do From 36354b4fb973c5895ecdbc146a9381621a9cd2a5 Mon Sep 17 00:00:00 2001 From: stevenjcumming <134282106+stevenjcumming@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:07:58 -0400 Subject: [PATCH 29/31] Reorganize Vye & Veteran Confirmation Request Specs (#18274) * reorganize veteran_confirmation request specs * reorganize vye request specs --- .../requests/{api_docs_request_spec.rb => docs/v0/api_spec.rb} | 2 +- modules/vye/spec/requests/vye/v1/address/create_spec.rb | 2 +- modules/vye/spec/requests/vye/v1/bank_info/create_spec.rb | 2 +- .../spec/requests/vye/v1/{show_spec.rb => user_info_spec.rb} | 2 +- modules/vye/spec/requests/vye/v1/verify/create_spec.rb | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename modules/veteran_confirmation/spec/requests/{api_docs_request_spec.rb => docs/v0/api_spec.rb} (77%) rename modules/vye/spec/requests/vye/v1/{show_spec.rb => user_info_spec.rb} (97%) diff --git a/modules/veteran_confirmation/spec/requests/api_docs_request_spec.rb b/modules/veteran_confirmation/spec/requests/docs/v0/api_spec.rb similarity index 77% rename from modules/veteran_confirmation/spec/requests/api_docs_request_spec.rb rename to modules/veteran_confirmation/spec/requests/docs/v0/api_spec.rb index 929862a5247..f4a8f9d3df9 100644 --- a/modules/veteran_confirmation/spec/requests/api_docs_request_spec.rb +++ b/modules/veteran_confirmation/spec/requests/docs/v0/api_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Veteran Confirmation Documentation Endpoints', type: :request do +RSpec.describe 'VeteranConfirmation::Doc::V0::Api', type: :request do describe '#get /docs/v0/status' do it 'returns Open API Spec v3 JSON' do get '/services/veteran_confirmation/docs/v0/api' diff --git a/modules/vye/spec/requests/vye/v1/address/create_spec.rb b/modules/vye/spec/requests/vye/v1/address/create_spec.rb index d80d9acb093..7d338859592 100644 --- a/modules/vye/spec/requests/vye/v1/address/create_spec.rb +++ b/modules/vye/spec/requests/vye/v1/address/create_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' require Vye::Engine.root / 'spec/rails_helper' -RSpec.describe Vye::V1::AddressChangesController, type: :request do +RSpec.describe 'Vye::V1::Address#create', type: :request do let!(:current_user) { create(:user, :accountable) } let(:headers) { { 'Content-Type' => 'application/json', 'X-Key-Inflection' => 'camel' } } diff --git a/modules/vye/spec/requests/vye/v1/bank_info/create_spec.rb b/modules/vye/spec/requests/vye/v1/bank_info/create_spec.rb index 3e68c7c9e35..de65ac9c731 100644 --- a/modules/vye/spec/requests/vye/v1/bank_info/create_spec.rb +++ b/modules/vye/spec/requests/vye/v1/bank_info/create_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' require Vye::Engine.root / 'spec/rails_helper' -RSpec.describe Vye::V1::DirectDepositChangesController, type: :request do +RSpec.describe 'Vye::V1::DirectDeposit#create', type: :request do let!(:current_user) { create(:user, :accountable) } let(:headers) { { 'Content-Type' => 'application/json', 'X-Key-Inflection' => 'camel' } } diff --git a/modules/vye/spec/requests/vye/v1/show_spec.rb b/modules/vye/spec/requests/vye/v1/user_info_spec.rb similarity index 97% rename from modules/vye/spec/requests/vye/v1/show_spec.rb rename to modules/vye/spec/requests/vye/v1/user_info_spec.rb index b2256f06675..7f3a01e70cc 100644 --- a/modules/vye/spec/requests/vye/v1/show_spec.rb +++ b/modules/vye/spec/requests/vye/v1/user_info_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' require Vye::Engine.root / 'spec/rails_helper' -RSpec.describe Vye::V1::UserInfosController, type: :request do +RSpec.describe 'Vye::V1 UserInfo', type: :request do describe 'GET /vye/v1' do describe 'when there is a logged in current_user' do let!(:current_user) { create(:user, :accountable) } diff --git a/modules/vye/spec/requests/vye/v1/verify/create_spec.rb b/modules/vye/spec/requests/vye/v1/verify/create_spec.rb index 9d91f93d5f5..848f85bdda5 100644 --- a/modules/vye/spec/requests/vye/v1/verify/create_spec.rb +++ b/modules/vye/spec/requests/vye/v1/verify/create_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' require Vye::Engine.root / 'spec/rails_helper' -RSpec.describe Vye::V1::VerificationsController, type: :request do +RSpec.describe 'Vye::V1::Verify#create', type: :request do let!(:current_user) { create(:user, :accountable) } before do From 5e3fa8abd2b29a9e2fcef62ef7cf3a41be1ee71e Mon Sep 17 00:00:00 2001 From: stevenjcumming <134282106+stevenjcumming@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:08:25 -0400 Subject: [PATCH 30/31] Reorganize Rep Man & SimpleFormsApi Request Specs (#18256) * reorganize rep-man request specs * reorganize rep-man request specs * reorganize simpleformsapi request specs --- .../v0/accredited_entities_for_appoint_spec.rb | 2 +- .../v0/accredited_individuals_spec.rb} | 2 +- .../v0/flag_accredited_representatives_spec.rb | 2 +- .../v0/pdf_generator_2122_spec.rb | 2 +- .../v0/pdf_generator_2122a_spec.rb | 2 +- .../v0/power_of_attorney_request_spec.rb | 2 +- .../{ => simple_forms_api}/v1/scanned_form_uploads_spec.rb | 2 +- .../v1/simple_forms_spec.rb} | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) rename modules/representation_management/spec/requests/{ => representation_management}/v0/accredited_entities_for_appoint_spec.rb (98%) rename modules/representation_management/spec/requests/{v0/accredited_individuals_request_spec.rb => representation_management/v0/accredited_individuals_spec.rb} (99%) rename modules/representation_management/spec/requests/{ => representation_management}/v0/flag_accredited_representatives_spec.rb (98%) rename modules/representation_management/spec/requests/{ => representation_management}/v0/pdf_generator_2122_spec.rb (97%) rename modules/representation_management/spec/requests/{ => representation_management}/v0/pdf_generator_2122a_spec.rb (98%) rename modules/representation_management/spec/requests/{ => representation_management}/v0/power_of_attorney_request_spec.rb (97%) rename modules/simple_forms_api/spec/requests/{ => simple_forms_api}/v1/scanned_form_uploads_spec.rb (96%) rename modules/simple_forms_api/spec/requests/{v1/uploads_spec.rb => simple_forms_api/v1/simple_forms_spec.rb} (99%) diff --git a/modules/representation_management/spec/requests/v0/accredited_entities_for_appoint_spec.rb b/modules/representation_management/spec/requests/representation_management/v0/accredited_entities_for_appoint_spec.rb similarity index 98% rename from modules/representation_management/spec/requests/v0/accredited_entities_for_appoint_spec.rb rename to modules/representation_management/spec/requests/representation_management/v0/accredited_entities_for_appoint_spec.rb index 6794c42db31..71ef106d4ec 100644 --- a/modules/representation_management/spec/requests/v0/accredited_entities_for_appoint_spec.rb +++ b/modules/representation_management/spec/requests/representation_management/v0/accredited_entities_for_appoint_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'RepresentationManagement::V0::AccreditedEntitiesForAppointController', type: :request do +RSpec.describe 'RepresentationManagement::V0::AccreditedEntitiesForAppoint', type: :request do let(:path) { '/representation_management/v0/accredited_entities_for_appoint' } let!(:bob_law) { create(:accredited_individual, :with_location, full_name: 'Bob Law') } let!(:bob_smith) { create(:accredited_individual, :with_location, full_name: 'Bob Smith') } diff --git a/modules/representation_management/spec/requests/v0/accredited_individuals_request_spec.rb b/modules/representation_management/spec/requests/representation_management/v0/accredited_individuals_spec.rb similarity index 99% rename from modules/representation_management/spec/requests/v0/accredited_individuals_request_spec.rb rename to modules/representation_management/spec/requests/representation_management/v0/accredited_individuals_spec.rb index 2de3b599af6..4542d0f6b71 100644 --- a/modules/representation_management/spec/requests/v0/accredited_individuals_request_spec.rb +++ b/modules/representation_management/spec/requests/representation_management/v0/accredited_individuals_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'RepresentationManagement::V0::AccreditedIndividualsController', type: :request do +RSpec.describe 'RepresentationManagement::V0::AccreditedIndividuals', type: :request do let(:path) { '/representation_management/v0/accredited_individuals' } let(:type) { 'representative' } let(:distance) { 50 } diff --git a/modules/representation_management/spec/requests/v0/flag_accredited_representatives_spec.rb b/modules/representation_management/spec/requests/representation_management/v0/flag_accredited_representatives_spec.rb similarity index 98% rename from modules/representation_management/spec/requests/v0/flag_accredited_representatives_spec.rb rename to modules/representation_management/spec/requests/representation_management/v0/flag_accredited_representatives_spec.rb index 2c5c7623e35..73c7f0dd51e 100644 --- a/modules/representation_management/spec/requests/v0/flag_accredited_representatives_spec.rb +++ b/modules/representation_management/spec/requests/representation_management/v0/flag_accredited_representatives_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'FlagAccreditedRepresentativesController', type: :request do +RSpec.describe 'RepresentationManagement::V0::FlagAccreditedRepresentatives', type: :request do describe 'POST #create' do let(:base_path) { '/representation_management/v0/flag_accredited_representatives' } diff --git a/modules/representation_management/spec/requests/v0/pdf_generator_2122_spec.rb b/modules/representation_management/spec/requests/representation_management/v0/pdf_generator_2122_spec.rb similarity index 97% rename from modules/representation_management/spec/requests/v0/pdf_generator_2122_spec.rb rename to modules/representation_management/spec/requests/representation_management/v0/pdf_generator_2122_spec.rb index e1707ce2ddb..fec940857fd 100644 --- a/modules/representation_management/spec/requests/v0/pdf_generator_2122_spec.rb +++ b/modules/representation_management/spec/requests/representation_management/v0/pdf_generator_2122_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'PdfGenerator2122Controller', type: :request do +RSpec.describe 'RepresentationManagement::V0::PdfGenerator2122', type: :request do describe 'POST #create' do let(:base_path) { '/representation_management/v0/pdf_generator2122' } let(:params) do diff --git a/modules/representation_management/spec/requests/v0/pdf_generator_2122a_spec.rb b/modules/representation_management/spec/requests/representation_management/v0/pdf_generator_2122a_spec.rb similarity index 98% rename from modules/representation_management/spec/requests/v0/pdf_generator_2122a_spec.rb rename to modules/representation_management/spec/requests/representation_management/v0/pdf_generator_2122a_spec.rb index 5c8d6c6029a..5f83ed28897 100644 --- a/modules/representation_management/spec/requests/v0/pdf_generator_2122a_spec.rb +++ b/modules/representation_management/spec/requests/representation_management/v0/pdf_generator_2122a_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'PdfGenerator2122aController', type: :request do +RSpec.describe 'RepresentationManagement::V0::PdfGenerator2122a', type: :request do describe 'POST #create' do let(:base_path) { '/representation_management/v0/pdf_generator2122a' } let(:params) do diff --git a/modules/representation_management/spec/requests/v0/power_of_attorney_request_spec.rb b/modules/representation_management/spec/requests/representation_management/v0/power_of_attorney_request_spec.rb similarity index 97% rename from modules/representation_management/spec/requests/v0/power_of_attorney_request_spec.rb rename to modules/representation_management/spec/requests/representation_management/v0/power_of_attorney_request_spec.rb index 80dd5490738..60778319a9c 100644 --- a/modules/representation_management/spec/requests/v0/power_of_attorney_request_spec.rb +++ b/modules/representation_management/spec/requests/representation_management/v0/power_of_attorney_request_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'RepresentationManagement::V0::PowerOfAttorneyController', type: :request do +RSpec.describe 'RepresentationManagement::V0::PowerOfAttorney', type: :request do let(:index_path) { '/representation_management/v0/power_of_attorney' } let(:user) { create(:user, :loa3) } diff --git a/modules/simple_forms_api/spec/requests/v1/scanned_form_uploads_spec.rb b/modules/simple_forms_api/spec/requests/simple_forms_api/v1/scanned_form_uploads_spec.rb similarity index 96% rename from modules/simple_forms_api/spec/requests/v1/scanned_form_uploads_spec.rb rename to modules/simple_forms_api/spec/requests/simple_forms_api/v1/scanned_form_uploads_spec.rb index 21484de89be..2ef22cd25f2 100644 --- a/modules/simple_forms_api/spec/requests/v1/scanned_form_uploads_spec.rb +++ b/modules/simple_forms_api/spec/requests/simple_forms_api/v1/scanned_form_uploads_spec.rb @@ -4,7 +4,7 @@ require 'simple_forms_api_submission/metadata_validator' require 'common/file_helpers' -RSpec.describe 'Scanned forms uploader', type: :request do +RSpec.describe 'SimpleFormsApi::V1::ScannedFormsUploader', type: :request do before do sign_in end diff --git a/modules/simple_forms_api/spec/requests/v1/uploads_spec.rb b/modules/simple_forms_api/spec/requests/simple_forms_api/v1/simple_forms_spec.rb similarity index 99% rename from modules/simple_forms_api/spec/requests/v1/uploads_spec.rb rename to modules/simple_forms_api/spec/requests/simple_forms_api/v1/simple_forms_spec.rb index f98f72e2382..c96890dbdf4 100644 --- a/modules/simple_forms_api/spec/requests/v1/uploads_spec.rb +++ b/modules/simple_forms_api/spec/requests/simple_forms_api/v1/simple_forms_spec.rb @@ -4,7 +4,7 @@ require 'simple_forms_api_submission/metadata_validator' require 'common/file_helpers' -RSpec.describe 'Forms uploader', type: :request do +RSpec.describe 'SimpleFormsApi::V1::SimpleForms', type: :request do before do Flipper.disable(:simple_forms_lighthouse_benefits_intake_service) end From 1fa334355c889d520351ce82708d19342e08fe32 Mon Sep 17 00:00:00 2001 From: Austin Covrig Date: Wed, 4 Sep 2024 16:37:26 -0400 Subject: [PATCH 31/31] API 38954 Enable EBenefitsBnftClaimStatusWebService (#18015) * Enable EBenefitsBnftClaimStatusWebService --- .../claims_api/lib/bgs_service/local_bgs.rb | 1 + .../lib/claims_api/find_definition_spec.rb | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/modules/claims_api/lib/bgs_service/local_bgs.rb b/modules/claims_api/lib/bgs_service/local_bgs.rb index 9210ad66035..e6661be037d 100644 --- a/modules/claims_api/lib/bgs_service/local_bgs.rb +++ b/modules/claims_api/lib/bgs_service/local_bgs.rb @@ -16,6 +16,7 @@ module ClaimsApi class LocalBGS CACHED_SERVICES = %w[ ClaimantServiceBean/ClaimantWebService + EBenefitsBnftClaimStatusWebServiceBean/EBenefitsBnftClaimStatusWebService IntentToFileWebServiceBean/IntentToFileWebService OrgWebServiceBean/OrgWebService PersonWebServiceBean/PersonWebService diff --git a/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb b/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb index 2d4e6929a1f..a9b7d0a16fb 100644 --- a/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb +++ b/modules/claims_api/spec/lib/claims_api/find_definition_spec.rb @@ -32,6 +32,17 @@ end context 'EBenefitsBnftClaimStatusWebServiceBean' do + let(:endpoint) { 'EBenefitsBnftClaimStatusWebServiceBean/EBenefitsBnftClaimStatusWebService' } + let(:action) { 'findBenefitClaimsStatusByPtcpntId' } + let(:key) { 'BenefitClaimsDTO' } + + it 'response with the correct attributes' do + result = subject.for_action(endpoint, action) + parsed_result = JSON.parse(result.to_json) + expect(parsed_result['service']['bean']['path']).to eq 'EBenefitsBnftClaimStatusWebServiceBean' + expect(parsed_result['service']['path']).to eq 'EBenefitsBnftClaimStatusWebService' + expect(parsed_result['service']['bean']['namespaces']['target']).to eq 'http://claimstatus.services.ebenefits.vba.va.gov/' + end end context 'IntentToFileWebServiceBean' do @@ -240,6 +251,15 @@ end context 'EBenefitsBnftClaimStatusWebServiceBean' do + let(:endpoint) { 'EBenefitsBnftClaimStatusWebServiceBean/EBenefitsBnftClaimStatusWebService' } + + it 'response with the correct namespace' do + result = subject.for_service(endpoint) + parsed_result = JSON.parse(result.to_json) + expect(parsed_result['bean']['path']).to eq 'EBenefitsBnftClaimStatusWebServiceBean' + expect(parsed_result['path']).to eq 'EBenefitsBnftClaimStatusWebService' + expect(parsed_result['bean']['namespaces']['target']).to eq 'http://claimstatus.services.ebenefits.vba.va.gov/' + end end context 'IntentToFileWebServiceBean' do