From 3197afd9afbcf1db0438bb67515e47c83a494794 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Apr 2024 08:29:26 -0400 Subject: [PATCH 1/5] Bump parallel_tests from 4.6.1 to 4.7.0 (#16473) Bumps [parallel_tests](https://github.com/grosser/parallel_tests) from 4.6.1 to 4.7.0. - [Changelog](https://github.com/grosser/parallel_tests/blob/master/CHANGELOG.md) - [Commits](https://github.com/grosser/parallel_tests/compare/v4.6.1...v4.7.0) --- updated-dependencies: - dependency-name: parallel_tests 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 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index fb14fa4d562..c93cfb9372a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -692,7 +692,7 @@ GEM os (1.1.4) ox (2.14.18) parallel (1.24.0) - parallel_tests (4.6.1) + parallel_tests (4.7.0) parallel parser (3.3.0.5) ast (~> 2.4.1) From 709e36e30fe0068a371caa3c8a60d087a723b237 Mon Sep 17 00:00:00 2001 From: Kevin Suarez Date: Wed, 24 Apr 2024 09:52:16 -0400 Subject: [PATCH 2/5] 80453 pt2 rehydrate 5655 controller (#16459) * 80453 create a method to upsert IPFs based on 5655 metadata * move user verification logic out of UserVerification model at reviewer's request * 80453 add rehydration controller methods * linter or leave 'er am I right? --- .../v0/financial_status_reports_controller.rb | 22 ++++++++++++ modules/debts_api/config/routes.rb | 3 ++ .../debts_api/v0/fsr_rehydration_service.rb | 19 ++++++++++ ...inancial_status_reports_controller_spec.rb | 35 +++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 modules/debts_api/lib/debts_api/v0/fsr_rehydration_service.rb diff --git a/modules/debts_api/app/controllers/debts_api/v0/financial_status_reports_controller.rb b/modules/debts_api/app/controllers/debts_api/v0/financial_status_reports_controller.rb index 76ec33c8869..1cff11148e6 100644 --- a/modules/debts_api/app/controllers/debts_api/v0/financial_status_reports_controller.rb +++ b/modules/debts_api/app/controllers/debts_api/v0/financial_status_reports_controller.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'debts_api/v0/financial_status_report_service' +require 'debts_api/v0/fsr_rehydration_service' module DebtsApi module V0 @@ -23,6 +24,27 @@ def download_pdf ) end + def submissions + submissions = DebtsApi::V0::Form5655Submission.where(user_uuid: current_user.uuid) + render json: { 'submissions' => submissions.map { |sub| { 'id' => sub.id } } } + end + + def rehydrate + submission_id = params[:submission_id] + + DebtsApi::V0::FsrRehydrationService.attempt_rehydration(user_uuid: current_user.uuid, submission_id:) + + render json: { result: 'FSR rehydrated' } + rescue ActiveRecord::RecordNotFound + render json: { error: "Form5655Submission record #{submission_id} not found." }, status: :not_found + rescue DebtsApi::V0::FsrRehydrationService::UserDoesNotOwnsubmission + render json: { error: "User #{current_user.uuid} does not own submission #{submission_id}" }, + status: :unauthorized + rescue DebtsApi::V0::FsrRehydrationService::NoInProgressFormDataStored + render json: { error: "Form5655Submission record #{submission_id} missing InProgressForm data", + status: :not_found } + end + private def render_not_found diff --git a/modules/debts_api/config/routes.rb b/modules/debts_api/config/routes.rb index 6b3ab5c1b7a..5fbb494ba96 100644 --- a/modules/debts_api/config/routes.rb +++ b/modules/debts_api/config/routes.rb @@ -5,9 +5,12 @@ resources :financial_status_reports, only: %i[create] do collection do get :download_pdf + get :submissions end end + get 'financial_status_reports/rehydrate_submission/:submission_id', to: 'financial_status_reports#rehydrate' + post 'calculate_total_assets', to: 'financial_status_reports_calculations#total_assets' post 'calculate_monthly_expenses', to: 'financial_status_reports_calculations#monthly_expenses' post 'calculate_all_expenses', to: 'financial_status_reports_calculations#all_expenses' diff --git a/modules/debts_api/lib/debts_api/v0/fsr_rehydration_service.rb b/modules/debts_api/lib/debts_api/v0/fsr_rehydration_service.rb new file mode 100644 index 00000000000..c66130b30b5 --- /dev/null +++ b/modules/debts_api/lib/debts_api/v0/fsr_rehydration_service.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module DebtsApi + class V0::FsrRehydrationService + include SentryLogging + + class UserDoesNotOwnsubmission < StandardError; end + class NoInProgressFormDataStored < StandardError; end + + def self.attempt_rehydration(user_uuid:, submission_id:) + submission = DebtsApi::V0::Form5655Submission.find(submission_id) + + raise NoInProgressFormDataStored unless submission.ipf_data + raise UserDoesNotOwnsubmission unless submission.user_uuid == user_uuid + + submission.upsert_in_progress_form + end + end +end diff --git a/modules/debts_api/spec/request/debts_api/v0/financial_status_reports_controller_spec.rb b/modules/debts_api/spec/request/debts_api/v0/financial_status_reports_controller_spec.rb index 63be330783b..35f7955f963 100644 --- a/modules/debts_api/spec/request/debts_api/v0/financial_status_reports_controller_spec.rb +++ b/modules/debts_api/spec/request/debts_api/v0/financial_status_reports_controller_spec.rb @@ -59,4 +59,39 @@ def mock_pdf_fill expect(response.body).to eq(content) end end + + describe '#rehydrate' do + context 'on a nonexistent submission' do + it 'renders a 404' do + get '/debts_api/v0/financial_status_reports/rehydrate_submission/1' + expect(response).to have_http_status(:not_found) + end + end + + context 'on a submission you don\'t own' do + let(:form5655_submission) { create(:debts_api_form5655_submission) } + + it 'renders a 404' do + form5655_submission + form5655_submission.update!(user_uuid: 'nottherightguy', ipf_data: '{"its":"me"}') + get "/debts_api/v0/financial_status_reports/rehydrate_submission/#{form5655_submission.id}" + expect(response.code).to eq('401') + body = "{\"error\":\"User #{user.uuid} does not own submission #{form5655_submission.id}\"}" + expect(response.body).to eq(body) + end + end + + context 'on a submission you do own' do + let(:form5655_submission) do + create(:debts_api_form5655_submission, user_uuid: 'b2fab2b56af045e1a9e2394347af91ef') + end + + it 'rehydrates In Progress Form' do + form5655_submission + form5655_submission.update!(user_uuid: user.uuid, ipf_data: '{"its":"me"}') + get "/debts_api/v0/financial_status_reports/rehydrate_submission/#{form5655_submission.id}" + expect(response.code).to eq('200') + end + end + end end From a267cc85a78a10618d62a9ed4fa6d0d3c367ac04 Mon Sep 17 00:00:00 2001 From: Richard Davis Date: Wed, 24 Apr 2024 10:05:48 -0400 Subject: [PATCH 3/5] Adds mhv_landing_page_enable_va_gov_health_tools_links feature toggle (#16398) --- config/features.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/features.yml b/config/features.yml index 49463e5e0e6..79b167cdef5 100644 --- a/config/features.yml +++ b/config/features.yml @@ -730,6 +730,9 @@ features: actor_type: user description: Enables/disables refill-related content for Medications on VA.gov enable_in_development: true + mhv_landing_page_enable_va_gov_health_tools_links: + actor_type: user + description: Enables VA.gov Health Tools links (Appts, SM, Rx, Records) on MHV-on-VA.gov Landing Page mhv_to_logingov_account_transition: actor_type: cookie_id description: Enables/disables MHV to Login.gov account transfer experience (Identity) From da4c68f073ce4de80f2f980a2eea3f0bef57c9ec Mon Sep 17 00:00:00 2001 From: Corey Ferris Date: Wed, 24 Apr 2024 11:05:05 -0400 Subject: [PATCH 4/5] manila timezone info logging (#16468) * manila timezone info logging --- .../services/vaos/v2/appointments_service.rb | 22 +++++++ .../services/v2/appointment_service_spec.rb | 62 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/modules/vaos/app/services/vaos/v2/appointments_service.rb b/modules/vaos/app/services/vaos/v2/appointments_service.rb index 6a3eacbb338..d9bd6d153b3 100644 --- a/modules/vaos/app/services/vaos/v2/appointments_service.rb +++ b/modules/vaos/app/services/vaos/v2/appointments_service.rb @@ -15,6 +15,7 @@ class AppointmentsService < VAOS::SessionService FACILITY_ERROR_MSG = 'Error fetching facility details' AVS_ERROR_MESSAGE = 'Error retrieving AVS link' AVS_APPT_TEST_ID = '192308' + MANILA_PHILIPPINES_FACILITY_ID = '358' AVS_FLIPPER = :va_online_scheduling_after_visit_summary ORACLE_HEALTH_CANCELLATIONS = :va_online_scheduling_enable_OH_cancellations @@ -411,15 +412,36 @@ def convert_appointment_time(appt) if !appt[:start].nil? facility_timezone = get_facility_timezone_memoized(appt[:location_id]) appt[:local_start_time] = convert_utc_to_local_time(appt[:start], facility_timezone) + + if appt[:location_id] == MANILA_PHILIPPINES_FACILITY_ID + log_timezone_info(appt[:location_id], facility_timezone, appt[:start], appt[:local_start_time]) + end + elsif !appt.dig(:requested_periods, 0, :start).nil? appt[:requested_periods].each do |period| facility_timezone = get_facility_timezone_memoized(appt[:location_id]) period[:local_start_time] = convert_utc_to_local_time(period[:start], facility_timezone) + + if appt[:location_id] == MANILA_PHILIPPINES_FACILITY_ID + log_timezone_info(appt[:location_id], facility_timezone, period[:start], period[:local_start_time]) + end end end appt end + def log_timezone_info(appt_location_id, facility_timezone, appt_start_time_utc, appt_start_time_local) + Rails.logger.info( + "Timezone info for Manila Philippines location_id #{appt_location_id}", + { + location_id: appt_location_id, + facility_timezone:, + appt_start_time_utc:, + appt_start_time_local: + }.to_json + ) + end + # Returns a local [DateTime] object converted from UTC using the facility's timezone offset. # We'd like to perform this change only on the appointment responses to offer a consistently # formatted local time to our consumers while not changing how we pass DateTimes to upstream services. diff --git a/modules/vaos/spec/services/v2/appointment_service_spec.rb b/modules/vaos/spec/services/v2/appointment_service_spec.rb index 5ff40013f14..88c2486408c 100644 --- a/modules/vaos/spec/services/v2/appointment_service_spec.rb +++ b/modules/vaos/spec/services/v2/appointment_service_spec.rb @@ -623,6 +623,68 @@ end end + describe '#convert_appointment_time' do + let(:manila_appt) do + { + id: '12345', + location_id: '358', + start: '2024-12-20T00:00:00Z' + } + end + + let(:manila_appt_req) do + { + id: '12345', + location_id: '358', + requested_periods: [{ start: '2024-12-20T00:00:00Z', end: '2024-12-20T11:59:59.999Z' }] + } + end + + context 'when appt location id is 358' do + it 'logs the appt location id, timezone info, utc/local times of appt' do + allow_any_instance_of(VAOS::V2::AppointmentsService) + .to receive(:get_facility_timezone_memoized) + .and_return('Asia/Manila') + allow(Rails.logger).to receive(:info) + + subject.send(:convert_appointment_time, manila_appt) + expect(Rails.logger).to have_received(:info).with('Timezone info for Manila Philippines location_id 358', + { + location_id: '358', + facility_timezone: 'Asia/Manila', + appt_start_time_utc: '2024-12-20T00:00:00Z', + appt_start_time_local: subject.send( + :convert_utc_to_local_time, + manila_appt[:start], + 'Asia/Manila' + ) + }.to_json) + end + + it 'logs the appt location id, timezone info, utc/local times of appt request' do + allow_any_instance_of(VAOS::V2::AppointmentsService) + .to receive(:get_facility_timezone_memoized) + .and_return('Asia/Manila') + allow(Rails.logger).to receive(:info) + + subject.send(:convert_appointment_time, manila_appt_req) + expect(Rails.logger).to have_received(:info).with('Timezone info for Manila Philippines location_id 358', + { + location_id: '358', + facility_timezone: 'Asia/Manila', + appt_start_time_utc: '2024-12-20T00:00:00Z', + appt_start_time_local: subject.send( + :convert_utc_to_local_time, manila_appt_req.dig( + :requested_periods, + 0, + :start + ), 'Asia/Manila' + ) + }.to_json) + end + end + end + describe '#convert_utc_to_local_time' do let(:start_datetime) { '2021-09-02T14:00:00Z'.to_datetime } From 994c71fbc252d294f2818c8149676e29f435ee44 Mon Sep 17 00:00:00 2001 From: Sam Stuckey Date: Wed, 24 Apr 2024 11:19:07 -0400 Subject: [PATCH 5/5] [DBX-80624] add 526 states for remediation audit (#16455) * [DBX-80624] add 526 states for remediation audit * typos --- app/models/form526_submission.rb | 31 ++++++++++++++++++++++++-- spec/models/form526_submission_spec.rb | 4 ++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/app/models/form526_submission.rb b/app/models/form526_submission.rb index a16f90192a8..86f24ed8151 100644 --- a/app/models/form526_submission.rb +++ b/app/models/form526_submission.rb @@ -18,7 +18,8 @@ class Form526Submission < ApplicationRecord state :unprocessed, initial: true state :delivered_to_primary, :failed_primary_delivery, :rejected_by_primary, :delivered_to_backup, :failed_backup_delivery, :rejected_by_backup, - :in_remediation, :finalized_as_successful, :unprocessable + :in_remediation, :finalized_as_successful, :unprocessable, + :processed_in_batch_remediation, :ignorable_duplicate # - a submission has been delivered to our happy path # - requires polling to finalize @@ -62,7 +63,6 @@ class Form526Submission < ApplicationRecord transitions to: :in_remediation end - # TODO: add this transition when we add 526 completion polling # - The only state that means we no longer own completion of this submission # - There is nothing more to do. E.G. # - VBMS has accepted and returned the applicable status to us via @@ -78,6 +78,33 @@ class Form526Submission < ApplicationRecord event :mark_as_unprocessable do transitions to: :unprocessable end + + # A special state to indicate this was part of our remediation 'batching' + # process in 2023. These were handled manually and are distinct from `in_remediation` + # in that they were not tracked at the time of remediation, but rather later in + # the 2024 526 State audit. + # + # This state is useful to us at the time of creation, but may be something + # to flatten to a simple `finalized_as_successful` in the future. + event :process_in_batch_remediation do + transitions to: :processed_in_batch_remediation + end + + # A special state to indicate this was part of our remediation 'batching' + # process in 2023. These submissions may have been processed or not, but + # we don't care because they have an earlier, successful duplicate. + # + # Duplicates are identified by comparing form_json, using this script: + # https://github.com/department-of-veterans-affairs/va.gov-team-sensitive/blob/master/teams/benefits/scripts/526/submission_deduper.rb + # The result of this script can be evaluated by a qualified stakeholder to make + # a judgement call on whether or not a submission is a 'perfect' duplicate. + # + # IF a submission is found to be an exact duplicate of another + # AND its duplicate was previously submitted / remediated successfully + # THEN we can ignore it as a duplicate + event :ignore_as_duplicate do + transitions to: :ignorable_duplicate + end end wrap_with_logging(:start_evss_submission_job, diff --git a/spec/models/form526_submission_spec.rb b/spec/models/form526_submission_spec.rb index 5084dd9724f..ee207a30ffe 100644 --- a/spec/models/form526_submission_spec.rb +++ b/spec/models/form526_submission_spec.rb @@ -103,6 +103,10 @@ .to(:unprocessable).on_event(:mark_as_unprocessable) expect(submission).to transition_from(:unprocessed) .to(:in_remediation).on_event(:begin_remediation) + expect(submission).to transition_from(:unprocessed) + .to(:processed_in_batch_remediation).on_event(:process_in_batch_remediation) + expect(submission).to transition_from(:unprocessed) + .to(:ignorable_duplicate).on_event(:ignore_as_duplicate) end end