From 96e2381e20b9591ada0ba75cb6106986cf7749f0 Mon Sep 17 00:00:00 2001 From: Ryan Johnson <72466113+rjohnson2011@users.noreply.github.com> Date: Wed, 28 Feb 2024 10:39:13 -0500 Subject: [PATCH] K8s feb 28 (#15715) * Resolve bundle-audit error (#15704) * Change rack-cors version to fix bundle-audit error * Add ignore flag to bundle audit * Restore rack cors version 2.0.1 * Update bundle-audit * Fix Gemfile.lock (#15700) * remove x86_64-darwin-22 using bundle lock --remove-platform command * add ruby using bundle lock --add-platform command * Dbex user identifiers status check (#14858) * Include Form526 user identifier presence mapping in user profile Includes the mapping of required Form526 user identifier data generated by the Users::Form526UserIdentifiersStatusService in the user profile returned from the main user endpoint. The front end will use this information to display to the user any identifiers we don't have in our system, so they can pass that information on to the Contact Center. Adds a feature flag, form_526_required_identifiers_in_user_object, and gates the presence of this data in the profile. * Update User LOA JSON Schema validations for 526 identifiers Updates four JSON schema validation files to relfect the addition of the form526_required_identifier_presence key to the users profile metadata * Add user arg to feature flags Forgot to pass the user arg to this feature flag. We want to allow this level of control so we could release this change progressively if we wanted to * Satisfy outstanding Rubocop warning to use anonymous positional arguments forwarding * Fix Flipper disable in profile test The user argument doesn't seem to work properly when enabling and disabling Flippers in specs. Confident this is working properly in the actual codebase though. * Address style suggestion in metadata conditional Prefer unless statement and early return to if statment in this case --------- Co-authored-by: Eric Boehs * Adds count of records written to log message (#15705) * Use LOA2 instead of LOA3 for datebox timestamp logic (#15655) * revert(vaos): removed clinic stop code logging (#15693) va.gov-team#71272 * Filter Unwanted Errors from Retrying (Dependents Forms) (#15545) * Add filters from exception cause * Use sidekiq skip mechanism * Use common method to submit backup * Move filter handling to method * Params for filter method * Lint issues * Fix icn as instance var * Missed 686c param * Move salvage form to top of rescue block * Same for other job * Remove code checks * updated cve file in build workflow --------- Co-authored-by: Holden Hinkle Co-authored-by: Nathan Burgess Co-authored-by: Eric Boehs Co-authored-by: gia-lexa <103389320+gia-lexa@users.noreply.github.com> Co-authored-by: Eric Tillberg Co-authored-by: AJ Magdub Co-authored-by: Tyler Fink Co-authored-by: RachalCassity --- .github/workflows/build.yml | 2 +- ...orm_526_user_identifiers_status_service.rb | 27 ++++++ app/services/users/profile.rb | 9 +- app/sidekiq/bgs/job.rb | 8 ++ app/sidekiq/bgs/submit_form674_job.rb | 65 +++++++++----- app/sidekiq/bgs/submit_form686c_job.rb | 71 ++++++++++----- .../create_daily_spool_files.rb | 2 +- config/features.yml | 3 + .../services/simple_forms_api/pdf_stamper.rb | 2 +- .../controllers/vaos/v2/clinics_controller.rb | 19 ---- .../services/vaos/v2/appointments_service.rb | 1 - .../spec/request/v2/clinics_request_spec.rb | 2 - ...26_user_identifiers_status_service_spec.rb | 89 +++++++++++++++++++ spec/services/users/profile_spec.rb | 36 ++++++++ spec/sidekiq/bgs/submit_form674_job_spec.rb | 19 ++++ spec/sidekiq/bgs/submit_form686c_job_spec.rb | 14 +++ spec/support/schemas/user_loa1.json | 13 ++- spec/support/schemas/user_loa3.json | 13 ++- spec/support/schemas_camelized/user_loa1.json | 13 ++- spec/support/schemas_camelized/user_loa3.json | 13 ++- 20 files changed, 346 insertions(+), 75 deletions(-) create mode 100644 app/services/users/form_526_user_identifiers_status_service.rb create mode 100644 spec/services/users/form526_user_identifiers_status_service_spec.rb diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c12b2831c8b..bee4336d23c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,7 +30,7 @@ jobs: bundler-cache: true - name: Run bundle-audit (checks gems for CVE issues) - run: bundle exec bundle-audit check --update --ignore CVE-2023-26141 CVE-2023-49090 + run: bundle exec bundle-audit check --update --ignore CVE-2024-27456 - name: Run Rubocop run: bundle exec rubocop --parallel --format github diff --git a/app/services/users/form_526_user_identifiers_status_service.rb b/app/services/users/form_526_user_identifiers_status_service.rb new file mode 100644 index 00000000000..27c69b77166 --- /dev/null +++ b/app/services/users/form_526_user_identifiers_status_service.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +# For a given user, checks for the presence of certain identifiers required by Form526 +# Returns a mapping of the identifier name to a boolean indicating whether we have that information for a user or not +module Users + class Form526UserIdentifiersStatusService + FORM526_REQUIRED_IDENTIFIERS = %w[participant_id birls_id ssn birth_date edipi].freeze + + def self.call(*) + new(*).call + end + + def initialize(user) + @user = user + end + + def call + identifer_mapping + end + + private + + def identifer_mapping + FORM526_REQUIRED_IDENTIFIERS.index_with { |identifier| @user[identifier].present? } + end + end +end diff --git a/app/services/users/profile.rb b/app/services/users/profile.rb index 914ab86e827..f2dded83b7e 100644 --- a/app/services/users/profile.rb +++ b/app/services/users/profile.rb @@ -96,11 +96,18 @@ def claims military_history: Vet360Policy.new(user).military_access?, payment_history: BGSPolicy.new(user).access?(log_stats: false), personal_information: MPIPolicy.new(user).queryable?, - rating_info: LighthousePolicy.new(user).rating_info_access? + rating_info: LighthousePolicy.new(user).rating_info_access?, + **form_526_required_identifiers } end end + def form_526_required_identifiers + return {} unless Flipper.enabled?(:form_526_required_identifiers_in_user_object, user) + + { form526_required_identifier_presence: Users::Form526UserIdentifiersStatusService.call(user) } + end + def vet360_contact_information person = user.vet360_contact_info return {} if person.blank? diff --git a/app/sidekiq/bgs/job.rb b/app/sidekiq/bgs/job.rb index f50160ebea1..b892c7e3729 100644 --- a/app/sidekiq/bgs/job.rb +++ b/app/sidekiq/bgs/job.rb @@ -5,6 +5,14 @@ module BGS class Job include BGS::Utilities::Helpers + FILTERED_ERRORS = [ + 'insertBenefitClaim: Invalid zipcode.', + 'Maximum number of EPs reached for this bnftClaimTypeCd', + 'This update is being elevated for additional review due to an Incident Flash associated with this Beneficiary', + 'ORA-20099: Error - File Number and Social Security number are different', + 'ORA-00001: unique constraint', + 'The length of the EXTERNAL_UID or EXTERNAL_KEY exceeds the maximum' + ].freeze def in_progress_form_copy(in_progress_form) return nil if in_progress_form.blank? diff --git a/app/sidekiq/bgs/submit_form674_job.rb b/app/sidekiq/bgs/submit_form674_job.rb index eb0253802a0..1a10dee76fc 100644 --- a/app/sidekiq/bgs/submit_form674_job.rb +++ b/app/sidekiq/bgs/submit_form674_job.rb @@ -9,7 +9,7 @@ class Invalid674Claim < StandardError; end include Sidekiq::Job include SentryLogging - attr_reader :claim, :user, :in_progress_copy, :user_uuid, :saved_claim_id, :vet_info + attr_reader :claim, :user, :in_progress_copy, :user_uuid, :saved_claim_id, :vet_info, :icn sidekiq_options retry: 14 @@ -18,42 +18,52 @@ class Invalid674Claim < StandardError; end vet_info = JSON.parse(KmsEncrypted::Box.new.decrypt(encrypted_vet_info)) Rails.logger.error('BGS::SubmitForm674Job failed, retries exhausted...', { user_uuid:, saved_claim_id:, icn:, error: }) - if Flipper.enabled?(:dependents_central_submission) - user ||= BGS::SubmitForm674Job.generate_user_struct(encrypted_user_struct_hash, vet_info) - CentralMail::SubmitCentralForm686cJob.perform_async(saved_claim_id, - KmsEncrypted::Box.new.encrypt(vet_info.to_json), - KmsEncrypted::Box.new.encrypt(user.to_h.to_json)) - else - DependentsApplicationFailureMailer.build(user).deliver_now if user&.email.present? # rubocop:disable Style/IfInsideElse # Temporary for flipper - end + + BGS::SubmitForm674Job.send_backup_submission(encrypted_user_struct_hash, vet_info, saved_claim_id) end def perform(user_uuid, icn, saved_claim_id, encrypted_vet_info, encrypted_user_struct_hash = nil) - @vet_info = JSON.parse(KmsEncrypted::Box.new.decrypt(encrypted_vet_info)) Rails.logger.info('BGS::SubmitForm674Job running!', { user_uuid:, saved_claim_id:, icn: }) - - @user = BGS::SubmitForm674Job.generate_user_struct(encrypted_user_struct_hash, @vet_info) - @user_uuid = user_uuid - @saved_claim_id = saved_claim_id + instance_params(encrypted_vet_info, icn, encrypted_user_struct_hash, user_uuid, saved_claim_id) in_progress_form = InProgressForm.find_by(form_id: FORM_ID, user_uuid:) @in_progress_copy = in_progress_form_copy(in_progress_form) - claim_data = normalize_names_and_addresses!(valid_claim_data) - - BGS::Form674.new(user, claim).submit(claim_data) + submit_form send_confirmation_email in_progress_form&.destroy Rails.logger.info('BGS::SubmitForm674Job succeeded!', { user_uuid:, saved_claim_id:, icn: }) rescue => e + salvage_save_in_progress_form(FORM_ID, user_uuid, @in_progress_copy) if @in_progress_copy.present? + handle_filtered_errors!(e:, encrypted_user_struct_hash:, encrypted_vet_info:) + Rails.logger.warn('BGS::SubmitForm674Job received error, retrying...', - { user_uuid:, saved_claim_id:, icn:, error: e.message }) + { user_uuid:, saved_claim_id:, icn:, error: e.message, nested_error: e.cause&.message }) log_message_to_sentry(e, :warning, {}, { team: 'vfs-ebenefits' }) - salvage_save_in_progress_form(FORM_ID, user_uuid, @in_progress_copy) if @in_progress_copy.present? raise end + def handle_filtered_errors!(e:, encrypted_user_struct_hash:, encrypted_vet_info:) + filter = FILTERED_ERRORS.any? { |filtered| e.message.include?(filtered) || e.cause&.message&.include?(filtered) } + return unless filter + + Rails.logger.warn('BGS::SubmitForm674Job received error, skipping retries...', + { user_uuid:, saved_claim_id:, icn:, error: e.message, nested_error: e.cause&.message }) + + vet_info = JSON.parse(KmsEncrypted::Box.new.decrypt(encrypted_vet_info)) + self.class.send_backup_submission(encrypted_user_struct_hash, vet_info, saved_claim_id) + raise Sidekiq::JobRetry::Skip + end + + def instance_params(encrypted_vet_info, icn, encrypted_user_struct_hash, user_uuid, saved_claim_id) + @vet_info = JSON.parse(KmsEncrypted::Box.new.decrypt(encrypted_vet_info)) + @user = BGS::SubmitForm674Job.generate_user_struct(encrypted_user_struct_hash, @vet_info) + @icn = icn + @user_uuid = user_uuid + @saved_claim_id = saved_claim_id + end + def self.generate_user_struct(encrypted_user_struct, vet_info) if encrypted_user_struct.present? return OpenStruct.new(JSON.parse(KmsEncrypted::Box.new.decrypt(encrypted_user_struct))) @@ -75,16 +85,29 @@ def self.generate_user_struct(encrypted_user_struct, vet_info) ) end + def self.send_backup_submission(encrypted_user_struct_hash, vet_info, saved_claim_id) + if Flipper.enabled?(:dependents_central_submission) + user = generate_user_struct(encrypted_user_struct_hash, vet_info) + CentralMail::SubmitCentralForm686cJob.perform_async(saved_claim_id, + KmsEncrypted::Box.new.encrypt(vet_info.to_json), + KmsEncrypted::Box.new.encrypt(user.to_h.to_json)) + else + DependentsApplicationFailureMailer.build(user).deliver_now if user&.email.present? # rubocop:disable Style/IfInsideElse # Temporary for flipper + end + end + private - def valid_claim_data + def submit_form @claim = SavedClaim::DependencyClaim.find(saved_claim_id) claim.add_veteran_info(vet_info) raise Invalid674Claim unless claim.valid?(:run_686_form_jobs) - claim.formatted_674_data(vet_info) + claim_data = normalize_names_and_addresses!(claim.formatted_674_data(vet_info)) + + BGS::Form674.new(user, claim).submit(claim_data) end def send_confirmation_email diff --git a/app/sidekiq/bgs/submit_form686c_job.rb b/app/sidekiq/bgs/submit_form686c_job.rb index 195876385bd..84d58d13e61 100644 --- a/app/sidekiq/bgs/submit_form686c_job.rb +++ b/app/sidekiq/bgs/submit_form686c_job.rb @@ -9,7 +9,7 @@ class Invalid686cClaim < StandardError; end include Sidekiq::Job include SentryLogging - attr_reader :claim, :user, :in_progress_copy, :user_uuid, :saved_claim_id, :vet_info + attr_reader :claim, :user, :in_progress_copy, :user_uuid, :saved_claim_id, :vet_info, :icn sidekiq_options retry: 14 @@ -18,45 +18,52 @@ class Invalid686cClaim < StandardError; end vet_info = JSON.parse(KmsEncrypted::Box.new.decrypt(encrypted_vet_info)) Rails.logger.error('BGS::SubmitForm686cJob failed, retries exhausted!', { user_uuid:, saved_claim_id:, icn:, error: }) - if Flipper.enabled?(:dependents_central_submission) - user ||= BGS::SubmitForm686cJob.generate_user_struct(vet_info) - CentralMail::SubmitCentralForm686cJob.perform_async(saved_claim_id, - KmsEncrypted::Box.new.encrypt(vet_info.to_json), - KmsEncrypted::Box.new.encrypt(user.to_h.to_json)) - else - DependentsApplicationFailureMailer.build(user).deliver_now if user&.email.present? # rubocop:disable Style/IfInsideElse - end + + BGS::SubmitForm686cJob.send_backup_submission(vet_info, saved_claim_id) end def perform(user_uuid, icn, saved_claim_id, encrypted_vet_info) - @vet_info = JSON.parse(KmsEncrypted::Box.new.decrypt(encrypted_vet_info)) Rails.logger.info('BGS::SubmitForm686cJob running!', { user_uuid:, saved_claim_id:, icn: }) - - @user = BGS::SubmitForm686cJob.generate_user_struct(@vet_info) - @user_uuid = user_uuid - @saved_claim_id = saved_claim_id + instance_params(encrypted_vet_info, icn, user_uuid, saved_claim_id) in_progress_form = InProgressForm.find_by(form_id: FORM_ID, user_uuid:) @in_progress_copy = in_progress_form_copy(in_progress_form) - claim_data = normalize_names_and_addresses!(valid_claim_data) - - BGS::Form686c.new(user, claim).submit(claim_data) - - # If Form 686c job succeeds, then enqueue 674 job. - BGS::SubmitForm674Job.perform_async(user_uuid, icn, saved_claim_id, encrypted_vet_info, KmsEncrypted::Box.new.encrypt(user.to_h.to_json)) if claim.submittable_674? # rubocop:disable Layout/LineLength + submit_forms(encrypted_vet_info) send_confirmation_email in_progress_form&.destroy Rails.logger.info('BGS::SubmitForm686cJob succeeded!', { user_uuid:, saved_claim_id:, icn: }) rescue => e + salvage_save_in_progress_form(FORM_ID, user_uuid, @in_progress_copy) if @in_progress_copy.present? + handle_filtered_errors!(e:, encrypted_vet_info:) + Rails.logger.warn('BGS::SubmitForm686cJob received error, retrying...', - { user_uuid:, saved_claim_id:, icn:, error: e.message }) + { user_uuid:, saved_claim_id:, icn:, error: e.message, nested_error: e.cause&.message }) log_message_to_sentry(e, :warning, {}, { team: 'vfs-ebenefits' }) - salvage_save_in_progress_form(FORM_ID, user_uuid, @in_progress_copy) if @in_progress_copy.present? raise end + def handle_filtered_errors!(e:, encrypted_vet_info:) + filter = FILTERED_ERRORS.any? { |filtered| e.message.include?(filtered) || e.cause&.message&.include?(filtered) } + return unless filter + + Rails.logger.warn('BGS::SubmitForm686cJob received error, skipping retries...', + { user_uuid:, saved_claim_id:, icn:, error: e.message, nested_error: e.cause&.message }) + + vet_info = JSON.parse(KmsEncrypted::Box.new.decrypt(encrypted_vet_info)) + self.class.send_backup_submission(vet_info, saved_claim_id) + raise Sidekiq::JobRetry::Skip + end + + def instance_params(encrypted_vet_info, icn, user_uuid, saved_claim_id) + @vet_info = JSON.parse(KmsEncrypted::Box.new.decrypt(encrypted_vet_info)) + @user = BGS::SubmitForm686cJob.generate_user_struct(@vet_info) + @icn = icn + @user_uuid = user_uuid + @saved_claim_id = saved_claim_id + end + def self.generate_user_struct(vet_info) info = vet_info['veteran_information'] full_name = info['full_name'] @@ -74,16 +81,32 @@ def self.generate_user_struct(vet_info) ) end + def self.send_backup_submission(vet_info, saved_claim_id) + if Flipper.enabled?(:dependents_central_submission) + user = generate_user_struct(vet_info) + CentralMail::SubmitCentralForm686cJob.perform_async(saved_claim_id, + KmsEncrypted::Box.new.encrypt(vet_info.to_json), + KmsEncrypted::Box.new.encrypt(user.to_h.to_json)) + else + DependentsApplicationFailureMailer.build(user).deliver_now if user&.email.present? # rubocop:disable Style/IfInsideElse + end + end + private - def valid_claim_data + def submit_forms(encrypted_vet_info) @claim = SavedClaim::DependencyClaim.find(saved_claim_id) claim.add_veteran_info(vet_info) raise Invalid686cClaim unless claim.valid?(:run_686_form_jobs) - claim.formatted_686_data(vet_info) + claim_data = normalize_names_and_addresses!(claim.formatted_686_data(vet_info)) + + BGS::Form686c.new(user, claim).submit(claim_data) + + # If Form 686c job succeeds, then enqueue 674 job. + BGS::SubmitForm674Job.perform_async(user_uuid, icn, saved_claim_id, encrypted_vet_info, KmsEncrypted::Box.new.encrypt(user.to_h.to_json)) if claim.submittable_674? # rubocop:disable Layout/LineLength end def send_confirmation_email diff --git a/app/sidekiq/education_form/create_daily_spool_files.rb b/app/sidekiq/education_form/create_daily_spool_files.rb index 8e3379e3aec..5803f654d8f 100644 --- a/app/sidekiq/education_form/create_daily_spool_files.rb +++ b/app/sidekiq/education_form/create_daily_spool_files.rb @@ -109,7 +109,7 @@ def write_files(writer, structured_data:) ## Testing to see if writer is the cause for retry attempt failures ## If we get to this message, it's not the writer object - log_info("Successfully wrote to filename: #{filename} for region: #{region}") + log_info("Successfully wrote #{records.count} applications to filename: #{filename} for region: #{region}") # send copy of staging spool files to testers # This mailer is intended to only work for development, staging and NOT production diff --git a/config/features.yml b/config/features.yml index d542bf83ea3..0c9918ca428 100644 --- a/config/features.yml +++ b/config/features.yml @@ -507,6 +507,9 @@ features: actor_type: user description: Enables form 21-4142 email submission confirmation (VaNotify) enable_in_development: true + form_526_required_identifiers_in_user_object: + actor_type: user + description: includes a mapping of booleans in the profile section of a serialized user indicating which ids are nil for the user form5490_confirmation_email: actor_type: user description: Enables form 5490 email submission confirmation (VaNotify) diff --git a/modules/simple_forms_api/app/services/simple_forms_api/pdf_stamper.rb b/modules/simple_forms_api/app/services/simple_forms_api/pdf_stamper.rb index b69f5d5169c..ba7616133eb 100644 --- a/modules/simple_forms_api/app/services/simple_forms_api/pdf_stamper.rb +++ b/modules/simple_forms_api/app/services/simple_forms_api/pdf_stamper.rb @@ -19,7 +19,7 @@ def self.stamp_pdf(stamped_template_path, form, current_loa) auth_text = case current_loa when 3 'Signee signed with an identity-verified account.' - when 1 + when 2 'Signee signed in but hasn’t verified their identity.' else 'Signee not signed in.' diff --git a/modules/vaos/app/controllers/vaos/v2/clinics_controller.rb b/modules/vaos/app/controllers/vaos/v2/clinics_controller.rb index 51fb16c50c4..bfc3bc1ca9a 100644 --- a/modules/vaos/app/controllers/vaos/v2/clinics_controller.rb +++ b/modules/vaos/app/controllers/vaos/v2/clinics_controller.rb @@ -11,7 +11,6 @@ def index clinical_service: params[:clinical_service], page_size: params[:page_size], page_number: params[:page_number]) - log_clinic_info(response) render json: VAOS::V2::ClinicsSerializer.new(response) end @@ -71,24 +70,6 @@ def unable_to_lookup_clinic?(appt) appt.nil? || appt.location_id.nil? || appt.clinic.nil? end - def log_clinic_info(clinic_data) - clinic_data.each do |clinic| - clinic_info = get_clinic_info(clinic) - Rails.logger.info('VAOS Clinic info: ', clinic_info.to_json) unless clinic_info.values.all?(&:nil?) - end - end - - def get_clinic_info(clinic) - { - stationId: clinic.station_id, - serviceName: clinic.service_name, - primaryStopCode: clinic.primary_stop_code, - primaryStopCodeName: clinic.primary_stop_code_name, - secondaryStopCode: clinic.secondary_stop_code, - secondaryStopCodeName: clinic.secondary_stop_code_name - } - end - def systems_service VAOS::V2::SystemsService.new(current_user) end diff --git a/modules/vaos/app/services/vaos/v2/appointments_service.rb b/modules/vaos/app/services/vaos/v2/appointments_service.rb index 8c72f3b32da..75a28e407cf 100644 --- a/modules/vaos/app/services/vaos/v2/appointments_service.rb +++ b/modules/vaos/app/services/vaos/v2/appointments_service.rb @@ -12,7 +12,6 @@ class AppointmentsService < VAOS::SessionService DIRECT_SCHEDULE_ERROR_KEY = 'DirectScheduleError' VAOS_SERVICE_DATA_KEY = 'VAOSServiceTypesAndCategory' - VAOS_TELEHEALTH_DATA_KEY = 'VAOSTelehealthData' FACILITY_ERROR_MSG = 'Error fetching facility details' AVS_ERROR_MESSAGE = 'Error retrieving AVS link' AVS_APPT_TEST_ID = '192308' diff --git a/modules/vaos/spec/request/v2/clinics_request_spec.rb b/modules/vaos/spec/request/v2/clinics_request_spec.rb index ab9a282d24e..030e6b8cc5c 100644 --- a/modules/vaos/spec/request/v2/clinics_request_spec.rb +++ b/modules/vaos/spec/request/v2/clinics_request_spec.rb @@ -20,9 +20,7 @@ context 'on successful query for clinics given service type' do it 'returns a list of clinics' do VCR.use_cassette('vaos/v2/systems/get_facility_clinics_200', match_requests_on: %i[method path query]) do - allow(Rails.logger).to receive(:info).at_least(:once) get '/vaos/v2/locations/983/clinics?clinical_service=audiology', headers: inflection_header - expect(Rails.logger).to have_received(:info).with('VAOS Clinic info: ', anything).at_least(:once) expect(response).to have_http_status(:ok) expect(response.body).to match_camelized_schema('vaos/v2/clinics', { strict: false }) x = JSON.parse(response.body) diff --git a/spec/services/users/form526_user_identifiers_status_service_spec.rb b/spec/services/users/form526_user_identifiers_status_service_spec.rb new file mode 100644 index 00000000000..71a8f998540 --- /dev/null +++ b/spec/services/users/form526_user_identifiers_status_service_spec.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Users::Form526UserIdentifiersStatusService do + describe '#call' do + let(:user) { build(:user) } + + describe 'participant_id validation' do + context 'when participant_id is missing' do + it "returns a hash with 'participant_id' marked false" do + allow(user).to receive(:participant_id).and_return(nil) + expect(Users::Form526UserIdentifiersStatusService.call(user)['participant_id']).to eq(false) + end + end + + context 'when participant_id is present' do + it "returns a hash with 'participant_id' marked true" do + allow(user).to receive(:participant_id).and_return('8675309') + expect(Users::Form526UserIdentifiersStatusService.call(user)['participant_id']).to eq(true) + end + end + end + + describe 'birls_id validation' do + context 'when birls_id is missing' do + it "returns a hash with 'birls_id' marked false" do + allow(user).to receive(:birls_id).and_return(nil) + expect(Users::Form526UserIdentifiersStatusService.call(user)['birls_id']).to eq(false) + end + end + + context 'when birls_id is present' do + it 'returns a hash with birls_id marked true' do + allow(user).to receive(:birls_id).and_return('8675309') + expect(Users::Form526UserIdentifiersStatusService.call(user)['birls_id']).to eq(true) + end + end + end + + describe 'ssn validation' do + context 'when ssn is missing' do + it "returns a hash with 'ssn' marked false" do + allow(user).to receive(:ssn).and_return(nil) + expect(Users::Form526UserIdentifiersStatusService.call(user)['ssn']).to eq(false) + end + end + + context 'when ssn is present' do + it 'returns a hash with ssn marked true' do + allow(user).to receive(:ssn).and_return('8675309') + expect(Users::Form526UserIdentifiersStatusService.call(user)['ssn']).to eq(true) + end + end + end + + describe 'birth_date validation' do + context 'when birth_date is missing' do + it "returns a hash with 'birth_date' marked false" do + allow(user).to receive(:birth_date).and_return(nil) + expect(Users::Form526UserIdentifiersStatusService.call(user)['birth_date']).to eq(false) + end + end + + context 'when birth_date is present' do + it 'returns a hash with birth_date marked true' do + allow(user).to receive(:birth_date).and_return('1985-10-26') + expect(Users::Form526UserIdentifiersStatusService.call(user)['birth_date']).to eq(true) + end + end + end + + describe 'edipi validation' do + context 'when edipi is missing' do + it "returns a hash with 'edipi' marked false" do + allow(user).to receive(:edipi).and_return(nil) + expect(Users::Form526UserIdentifiersStatusService.call(user)['edipi']).to eq(false) + end + end + + context 'when edipi is present' do + it 'returns a hash with edipi marked true' do + allow(user).to receive(:edipi).and_return('8675309') + expect(Users::Form526UserIdentifiersStatusService.call(user)['edipi']).to eq(true) + end + end + end + end +end diff --git a/spec/services/users/profile_spec.rb b/spec/services/users/profile_spec.rb index b5973787778..f16981240a9 100644 --- a/spec/services/users/profile_spec.rb +++ b/spec/services/users/profile_spec.rb @@ -164,6 +164,42 @@ end end + describe 'form 526 required identifiers' do + context 'when the user has the form_526_required_identifiers_in_user_object feature flag on' do + before do + Flipper.enable(:form_526_required_identifiers_in_user_object) + end + + context 'when a user is missing an identifier required by the 526 form' do + it 'has a value of false in the [:claims][:form526_required_identifier_presence] hash' do + allow(user).to receive(:participant_id).and_return(nil) + + identifiers = profile[:claims][:form526_required_identifier_presence] + expect(identifiers['participant_id']).to eq(false) + end + end + + context 'when a user is not missing an identifier required by the 526 form' do + it 'has a value of true in the [:claims][:form526_required_identifier_presence] hash' do + allow(user).to receive(:participant_id).and_return('8675309') + + identifiers = profile[:claims][:form526_required_identifier_presence] + expect(identifiers['participant_id']).to eq(true) + end + end + end + + context 'when the user has the form_526_required_identifiers_in_user_object feature flag off' do + before do + Flipper.disable(:form_526_required_identifiers_in_user_object) + end + + it 'does not include the identifiers in the claims section of the user profile' do + expect(profile[:claims][:form526_required_identifier_presence]).to eq(nil) + end + end + end + it 'includes email' do expect(profile[:email]).to eq(user.email) end diff --git a/spec/sidekiq/bgs/submit_form674_job_spec.rb b/spec/sidekiq/bgs/submit_form674_job_spec.rb index 288a8b5a7d7..8f7d5356363 100644 --- a/spec/sidekiq/bgs/submit_form674_job_spec.rb +++ b/spec/sidekiq/bgs/submit_form674_job_spec.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'rails_helper' +require 'sidekiq/job_retry' RSpec.describe BGS::SubmitForm674Job, type: :job do let(:user) { FactoryBot.create(:evss_user, :loa3) } @@ -101,5 +102,23 @@ subject.perform(user.uuid, user.icn, dependency_claim.id, encrypted_vet_info, encrypted_user_struct) end.to raise_error(BGS::SubmitForm674Job::Invalid674Claim) end + + it 'filters based on error cause' do + expect(OpenStruct).to receive(:new) + .with(hash_including('icn' => vet_info['veteran_information']['icn'])) + .and_return(user_struct) + expect(BGS::Form674).to receive(:new).with(user_struct, dependency_claim) { client_stub } + expect(client_stub).to receive(:submit) { raise_nested_err } + + expect do + subject.perform(user.uuid, user.icn, dependency_claim.id, encrypted_vet_info, encrypted_user_struct) + end.to raise_error(Sidekiq::JobRetry::Skip) + end end end + +def raise_nested_err + raise BGS::SubmitForm674Job::Invalid674Claim, 'A very specific error occurred: insertBenefitClaim: Invalid zipcode.' +rescue + raise BGS::SubmitForm674Job::Invalid674Claim, 'A Generic Error Occurred' +end diff --git a/spec/sidekiq/bgs/submit_form686c_job_spec.rb b/spec/sidekiq/bgs/submit_form686c_job_spec.rb index c7a6dcbc5c2..099d9160895 100644 --- a/spec/sidekiq/bgs/submit_form686c_job_spec.rb +++ b/spec/sidekiq/bgs/submit_form686c_job_spec.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'rails_helper' +require 'sidekiq/job_retry' RSpec.describe BGS::SubmitForm686cJob, type: :job do let(:job) { subject.perform(user.uuid, user.icn, dependency_claim.id, encrypted_vet_info) } @@ -106,5 +107,18 @@ expect { job }.to raise_error(BGS::SubmitForm686cJob::Invalid686cClaim) end + + it 'filters based on error cause' do + expect(BGS::Form686c).to receive(:new).with(user_struct, dependency_claim).and_return(client_stub) + expect(client_stub).to receive(:submit) { raise_nested_err } + + expect { job }.to raise_error(Sidekiq::JobRetry::Skip) + end end end + +def raise_nested_err + raise BGS::SubmitForm686cJob::Invalid686cClaim, 'A very specific error occurred: insertBenefitClaim: Invalid zipcode.' +rescue + raise BGS::SubmitForm686cJob::Invalid686cClaim, 'A Generic Error Occurred' +end diff --git a/spec/support/schemas/user_loa1.json b/spec/support/schemas/user_loa1.json index 00467bdc4fc..8b071eac829 100644 --- a/spec/support/schemas/user_loa1.json +++ b/spec/support/schemas/user_loa1.json @@ -99,7 +99,18 @@ "personal_information": { "type": "boolean" }, "rating_info": { "type": "boolean" }, "appeals": { "type": "boolean" }, - "medical_copays": { "type": "boolean" } + "medical_copays": { "type": "boolean" }, + "form526_required_identifier_presence": { + "type": "object", + "properties": { + "participant_id": { "type": "boolean" }, + "birls_id": { "type": "boolean" }, + "ssn": { "type": "boolean" }, + "birth_date": { "type": "boolean" }, + "edipi": { "type": "boolean" } + }, + "required": ["participant_id", "birls_id", "ssn", "birth_date", "edipi"] + } } } } diff --git a/spec/support/schemas/user_loa3.json b/spec/support/schemas/user_loa3.json index 595cf6b8d8a..f54854613e3 100644 --- a/spec/support/schemas/user_loa3.json +++ b/spec/support/schemas/user_loa3.json @@ -100,7 +100,18 @@ "personal_information": { "type": "boolean" }, "rating_info": { "type": "boolean" }, "appeals": { "type": "boolean" }, - "medical_copays": { "type": "boolean" } + "medical_copays": { "type": "boolean" }, + "form526_required_identifier_presence": { + "type": "object", + "properties": { + "participant_id": { "type": "boolean" }, + "birls_id": { "type": "boolean" }, + "ssn": { "type": "boolean" }, + "birth_date": { "type": "boolean" }, + "edipi": { "type": "boolean" } + }, + "required": ["participant_id", "birls_id", "ssn", "birth_date", "edipi"] + } } } } diff --git a/spec/support/schemas_camelized/user_loa1.json b/spec/support/schemas_camelized/user_loa1.json index 1c3f72357b9..dc3368b6955 100644 --- a/spec/support/schemas_camelized/user_loa1.json +++ b/spec/support/schemas_camelized/user_loa1.json @@ -194,7 +194,18 @@ "personalInformation": { "type": "boolean" }, "ratingInfo": { "type": "boolean" }, "appeals": { "type": "boolean" }, - "medicalCopays": { "type": "boolean" } + "medicalCopays": { "type": "boolean" }, + "form526RequiredIdentifierPresence": { + "type": "object", + "properties": { + "participantId": { "type": "boolean" }, + "birlsId": { "type": "boolean" }, + "ssn": { "type": "boolean" }, + "birthDate": { "type": "boolean" }, + "edipi": { "type": "boolean" } + }, + "required": ["participantId", "birlsId", "ssn", "birthDate", "edipi"] + } } } } diff --git a/spec/support/schemas_camelized/user_loa3.json b/spec/support/schemas_camelized/user_loa3.json index 9daf36e7d43..6f4b7a78d76 100644 --- a/spec/support/schemas_camelized/user_loa3.json +++ b/spec/support/schemas_camelized/user_loa3.json @@ -191,7 +191,18 @@ "personalInformation": { "type": "boolean" }, "ratingInfo": { "type": "boolean" }, "appeals": { "type": "boolean" }, - "medicalCopays": { "type": "boolean" } + "medicalCopays": { "type": "boolean" }, + "form526RequiredIdentifierPresence": { + "type": "object", + "properties": { + "participantId": { "type": "boolean" }, + "birlsId": { "type": "boolean" }, + "ssn": { "type": "boolean" }, + "birthDate": { "type": "boolean" }, + "edipi": { "type": "boolean" } + }, + "required": ["participantId", "birlsId", "ssn", "birthDate", "edipi"] + } } } }