diff --git a/lib/unified_health_data/service.rb b/lib/unified_health_data/service.rb index 074655a60df..76192cee5c1 100644 --- a/lib/unified_health_data/service.rb +++ b/lib/unified_health_data/service.rb @@ -287,8 +287,16 @@ def get_immunizations # Use of this is behind va_online_scheduling_uhd_avs_metadata flipper def get_all_avs_metadata(start_date:, end_date:) # rubocop:disable Metrics/MethodLength validate_icn! + start_d = (start_date || default_start_date).to_s + end_d = (end_date || default_end_date).to_s + + if start_d > end_d + Rails.logger.error("UHD: start_d not before end_d | start_d: #{start_d}, end_d: #{end_d}") + return [[], []] + end + with_monitoring do - response = uhd_client.get_all_avs(patient_id: @user.icn, start_date:, end_date:) + response = uhd_client.get_all_avs(patient_id: @user.icn, start_date: start_d, end_date: end_d) # SCDF returns a bundle: DocumentReference, Encounter, and other types. body = response.body if body.nil? || !body.is_a?(Hash) || body['entry'].blank? diff --git a/modules/vaos/app/services/vaos/v2/appointments_service.rb b/modules/vaos/app/services/vaos/v2/appointments_service.rb index 1c096804875..e7fd7cb47cb 100644 --- a/modules/vaos/app/services/vaos/v2/appointments_service.rb +++ b/modules/vaos/app/services/vaos/v2/appointments_service.rb @@ -267,9 +267,10 @@ def get_appointment(appointment_id, include = {}, tp_client = 'vagov') # We always fetch facility and clinic information when getting a single appointment include[:facilities] = true include[:clinics] = true + start_dt = appointment[:start]&.to_datetime + should_fetch_avs = include[:avs] && start_dt&.past? - avs_metadata = fetch_all_avs_metadata(appointment[:start]&.to_datetime, [appointment], - include_avs: include[:avs]) + avs_metadata = fetch_all_avs_metadata(start_dt, [appointment], include_avs: should_fetch_avs) prepare_appointment(appointment, include, avs_metadata) check_appointments_migration_override([appointment]) @@ -498,22 +499,30 @@ def extract_facility_identifiers(appointments) # Returns a hash indexed by appointment id (without any prefix like CERNER) # # @return [Hash{String => Array}] - def fetch_all_avs_metadata(start_date, appointments = [], include_avs: false) + def fetch_all_avs_metadata(start_date, appointments = [], include_avs: false) # rubocop:disable Metrics/MethodLength return {} unless include_avs return {} unless Flipper.enabled?(:va_online_scheduling_uhd_avs_metadata, user) && Flipper.enabled?(APPOINTMENTS_FETCH_OH_AVS, user) && appointments.any? { |appt| VAOS::AppointmentsHelper.cerner?(appt) } return {} if user.icn.nil? || !start_date.respond_to?(:to_date) - start_date_str = start_date.to_date.to_s - end_date_str = Time.zone.today.to_s - doc_refs, encounters = unified_health_data_service.get_all_avs_metadata(start_date: start_date_str, - end_date: end_date_str) + start_date = start_date.to_date + end_date = Time.zone.today + + return {} if start_date > end_date + + doc_refs, encounters = unified_health_data_service.get_all_avs_metadata(start_date:, end_date:) clinical_notes_adapter.build_avs_metadata_by_appointment(encounters, doc_refs) rescue => e err_stack = e.backtrace.reject { |line| line.include?('gems') }.compact.join("\n ") - Rails.logger.error("VAOS: Error retrieving AVS metadata for user #{user.user_account_uuid}:" \ - "#{e.class}, #{e.message} \n #{err_stack}") + original_status = e.respond_to?(:original_status) ? e.original_status : nil + Rails.logger.error( + "VAOS: Error retrieving AVS metadata for user #{user.user_account_uuid}:" \ + "#{e.class}, #{e.message}" \ + " | start_date: #{start_date}, end_date: #{end_date}" \ + " | upstream_status: #{original_status}" \ + " \n #{err_stack}" + ) {} end diff --git a/modules/vaos/spec/requests/vaos/v2/appointments_spec.rb b/modules/vaos/spec/requests/vaos/v2/appointments_spec.rb index f43c6b2231f..2d8e453763e 100644 --- a/modules/vaos/spec/requests/vaos/v2/appointments_spec.rb +++ b/modules/vaos/spec/requests/vaos/v2/appointments_spec.rb @@ -893,6 +893,24 @@ def stub_clinics end end + it 'does not fetch avs when OH appointment is in the future even if avs is requested' do + Timecop.freeze(DateTime.parse('2023-09-01T12:00:00Z')) do + VCR.use_cassette('vaos/v2/appointments/get_appointment_200_with_facility_200_with_avs_cerner', + match_requests_on: %i[method path query]) do + allow(Rails.logger).to receive(:info).at_least(:once) + expect_any_instance_of(VAOS::V2::AppointmentsService).to receive(:fetch_all_avs_metadata) + .with(anything, anything, include_avs: false).and_call_original + + get '/vaos/v2/appointments/70060?_include=avs', headers: inflection_header + expect(response).to have_http_status(:ok) + data = JSON.parse(response.body)['data'] + + expect(data['id']).to eq('70060') + expect(data['attributes']['avsPdf']).to be_nil + end + end + end + it 'has access and returns appointment with OH avs' do avs_show_metadata = { '523938333130383130' => [ diff --git a/spec/lib/unified_health_data/service_spec.rb b/spec/lib/unified_health_data/service_spec.rb index 53042b2f31f..1af6a049f68 100644 --- a/spec/lib/unified_health_data/service_spec.rb +++ b/spec/lib/unified_health_data/service_spec.rb @@ -1895,6 +1895,27 @@ returned_types = all_returned.map { |entry| entry['resourceType'] }.uniq expect(returned_types).to contain_exactly('DocumentReference', 'Encounter') end + + it 'returns empty arrays when start_date is after end_date' do + expect_any_instance_of(UnifiedHealthData::Client).not_to receive(:get_all_avs) + result = service.get_all_avs_metadata(start_date: '2025-12-31', end_date: '2025-01-01') + expect(result).to eq([[], []]) + end + + it 'does not short-circuit when start_date equals end_date' do + result = service.get_all_avs_metadata(start_date: '2025-06-15', end_date: '2025-06-15') + doc_refs, encounters = result + expect(doc_refs.size).to eq(2) + expect(encounters.size).to eq(2) + end + + it 'accepts Date objects for start_date and end_date' do + result = service.get_all_avs_metadata(start_date: Date.new(2025, 1, 1), end_date: Date.new(2025, 12, 31)) + + doc_refs, encounters = result + expect(doc_refs.size).to eq(2) + expect(encounters.size).to eq(2) + end end describe '#get_avs_binary_data' do