Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding merge functionality for eps to regular appointments #19754

Open
wants to merge 48 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
a7c7ab2
adding merge functionality for eps to regular appointments
lee-delarm6 Dec 5, 2024
7b9caa6
rubocop fixes
lee-delarm6 Dec 5, 2024
f9d0a36
revert controller, move logic to service
lee-delarm6 Dec 12, 2024
0577b6e
update test
lee-delarm6 Dec 12, 2024
6401a1f
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Dec 12, 2024
a749327
moved controller logic to service
lee-delarm6 Dec 12, 2024
36cbafd
dropping and fixing a few items
lee-delarm6 Dec 12, 2024
170d535
removing unused function
lee-delarm6 Dec 12, 2024
8a362ce
update to master
lee-delarm6 Dec 12, 2024
c565abd
fixes
lee-delarm6 Dec 12, 2024
26804f8
more fixes
lee-delarm6 Dec 12, 2024
7631136
last fix
lee-delarm6 Dec 12, 2024
fbde9be
maybe last fix
lee-delarm6 Dec 12, 2024
3c9df3b
Updated fix?
lee-delarm6 Dec 12, 2024
5822040
Fixed linting issues
lee-delarm6 Dec 19, 2024
91d4dbc
Changing naming, removing empty line
lee-delarm6 Dec 19, 2024
a755e2d
Lint fixes again
lee-delarm6 Dec 19, 2024
0b84443
Remove line
lee-delarm6 Dec 19, 2024
e7b6f30
eps serializer
lee-delarm6 Dec 20, 2024
76b38cb
rubocop fix
lee-delarm6 Dec 20, 2024
10a0b0f
Unfixed test
lee-delarm6 Dec 30, 2024
37add43
Fix tests and code
lee-delarm6 Dec 30, 2024
699e013
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 7, 2025
fabfda6
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 9, 2025
7445cac
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 10, 2025
beeb062
Fix data issues with appointments
lee-delarm6 Jan 15, 2025
a785508
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 15, 2025
22bd92c
Rubocop fixes
lee-delarm6 Jan 15, 2025
0c3691e
Add start time stamp for uniqueness
lee-delarm6 Jan 16, 2025
1e6bf3e
VCR update, spec updates, block updates
lee-delarm6 Jan 21, 2025
2a333fd
Rubocop fixes
lee-delarm6 Jan 21, 2025
80347b3
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 21, 2025
eb8d591
Updated line too long offenses
lee-delarm6 Jan 21, 2025
0694ff9
Merge branch '96412_merge_eps_appointments' of https://github.com/dep…
lee-delarm6 Jan 21, 2025
b8f3ebc
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 22, 2025
3fadd7d
Not needed anymore
lee-delarm6 Jan 23, 2025
deea80d
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 23, 2025
77cd91c
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 23, 2025
e3fc186
Moved status to serialize step
lee-delarm6 Jan 27, 2025
246ed56
Update modules/vaos/app/serializers/vaos/v2/eps_appointment.rb
lee-delarm6 Jan 28, 2025
5f05d5b
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 29, 2025
6fea526
rubocop fix
lee-delarm6 Jan 29, 2025
0b4093c
Merge branch '96412_merge_eps_appointments' of https://github.com/dep…
lee-delarm6 Jan 29, 2025
5e9be5f
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 29, 2025
303da0c
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 29, 2025
f817cac
Fixed testing and rubocop errors
lee-delarm6 Jan 29, 2025
6348a6b
Moving file locations
lee-delarm6 Jan 30, 2025
5581d55
Merge branch 'master' into 96412_merge_eps_appointments
lee-delarm6 Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions modules/vaos/app/serializers/vaos/v2/eps_appointment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# frozen_string_literal: true

module VAOS
module V2
class EpsAppointment
randomsync marked this conversation as resolved.
Show resolved Hide resolved
def initialize(params = {})
appointment_details = params[:appointment_details]
referral_details = params[:referral]

@id = params[:id]&.to_s
@status = appointment_details[:status]
@patient_icn = params[:patient_id]
@created = appointment_details[:last_retrieved]
@location_id = params[:network_id]
@clinic = params[:provider_service_id]
@start = params.dig(:appointment_details, :start)
@contact = params[:contact]
@referral_id = referral_details[:referral_number]
@referral = { referral_number: referral_details[:referral_number]&.to_s }
end

def serializable_hash
{
id: @id,
status: determine_status(@status),
patient_icn: @patient_icn,
created: @created,
location_id: @location_id,
clinic: @clinic,
start: @start,
contact: @contact,
referral_id: @referral_id,
referral: @referral
}.compact
end

private

def determine_status(status)
status == 'booked' ? 'booked' : 'proposed'
end
end
end
end
32 changes: 32 additions & 0 deletions modules/vaos/app/services/vaos/v2/appointments_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ def get_appointments(start_date, end_date, statuses = nil, pagination_params = {
cnp_count += 1 if cnp?(appt)
end

appointments = merge_appointments(eps_appointments, appointments) if include[:eps]

if Flipper.enabled?(:appointments_consolidation, user)
filterer = AppointmentsPresentationFilter.new
appointments = appointments.keep_if { |appt| filterer.user_facing?(appt) }
Expand Down Expand Up @@ -221,6 +223,17 @@ def get_facility_timezone_memoized(facility_location_id)
facility_info[:timezone]&.[](:time_zone_id)
end

def merge_appointments(eps_appointments, appointments)
normalized_new = eps_appointments.map(&:serializable_hash)
existing_referral_ids = appointments.to_set { |a| a.dig(:referral, :referral_number) }
date_and_time_for_referral_list = appointments.pluck(:start)
merged_data = appointments + normalized_new.reject do |a|
existing_referral_ids.include?(a.dig(:referral,
:referral_number)) && date_and_time_for_referral_list.include?(a[:start])
end
merged_data.sort_by { |appt| appt[:start] || '' }
end

memoize :get_facility_timezone_memoized

private
Expand Down Expand Up @@ -251,6 +264,7 @@ def parse_possible_token_related_errors(e)
{ message:, status:, icn: sanitized_icn, context: }
end
end

# rubocop:enable Metrics/MethodLength

# Modifies the appointment, extracting individual fields from the appointment. This currently includes:
Expand Down Expand Up @@ -930,6 +944,24 @@ def validate_response_schema(response, contract_name)

SchemaContract::ValidationInitiator.call(user:, response:, contract_name:)
end

def eps_appointments_service
@eps_appointments_service ||=
Eps::AppointmentService.new(user)
end

def eps_appointments
@eps_appointments ||= begin
appointments = eps_appointments_service.get_appointments
appointments = [] if appointments.blank? || appointments.all?(&:empty?)
appointments.reject! { |appt| appt.dig(:appointment_details, :start).nil? }
appointments.map { |appt| VAOS::V2::EpsAppointment.new(appt) }
end
end

def eps_serializer
@eps_serializer ||= VAOS::V2::EpsAppointment.new
end
end
end
end
63 changes: 63 additions & 0 deletions modules/vaos/spec/serializers/v2/eps_appointment_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# frozen_string_literal: true

# spec/serializers/vaos/v2/eps_appointment_spec.rb
require 'rails_helper'

describe VAOS::V2::EpsAppointment do
subject { described_class.new(params) }

let(:params) do
{
id: 1,
appointment_details: { status: 'booked', last_retrieved: '2023-10-01T00:00:00Z', start: '2023-10-10T10:00:00Z' },
referral: { referral_number: '12345' },
patient_id: '1234567890V123456',
network_id: 'network_1',
provider_service_id: 'clinic_1',
contact: 'contact_info'
}
end

describe '#initialize' do
it 'initializes with correct attributes' do
expect(subject.instance_variable_get(:@id)).to eq('1')
expect(subject.instance_variable_get(:@status)).to eq('booked')
expect(subject.instance_variable_get(:@patient_icn)).to eq('1234567890V123456')
expect(subject.instance_variable_get(:@created)).to eq('2023-10-01T00:00:00Z')
expect(subject.instance_variable_get(:@location_id)).to eq('network_1')
expect(subject.instance_variable_get(:@clinic)).to eq('clinic_1')
expect(subject.instance_variable_get(:@start)).to eq('2023-10-10T10:00:00Z')
expect(subject.instance_variable_get(:@contact)).to eq('contact_info')
expect(subject.instance_variable_get(:@referral_id)).to eq('12345')
expect(subject.instance_variable_get(:@referral)).to eq({ referral_number: '12345' })
end
end

describe '#serializable_hash' do
it 'returns a hash with the correct attributes' do
expected_hash = {
id: '1',
status: 'booked',
patient_icn: '1234567890V123456',
created: '2023-10-01T00:00:00Z',
location_id: 'network_1',
clinic: 'clinic_1',
start: '2023-10-10T10:00:00Z',
contact: 'contact_info',
referral_id: '12345',
referral: { referral_number: '12345' }
}
expect(subject.serializable_hash).to eq(expected_hash)
end
end

describe '#determine_status' do
it 'returns "booked" when status is "booked"' do
expect(subject.send(:determine_status, 'booked')).to eq('booked')
end

it 'returns "proposed" when status is not "booked"' do
expect(subject.send(:determine_status, 'proposed')).to eq('proposed')
end
end
end
151 changes: 151 additions & 0 deletions modules/vaos/spec/services/v2/appointment_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,95 @@

let(:provider_name) { 'TEST PROVIDER NAME' }

let(:eps_appointments) do
[
{
id: '123',
state: 'submitted',
patient_id: '456',
referral: {
referral_number: 'ref123'
},
provider_service_id: 'DBKQ-H0a',
network_id: 'random-sandbox-network-id',
slot_ids: [
'5vuTac8v-practitioner-8-role-1|' \
'9783e46c-efe2-462c-84a1-7af5f5f6613a|' \
'2024-12-01T10:00:00Z|30m0s|1733338893365|ov'
],
appointment_details: {
status: 'booked',
start: nil,
is_latest: false,
last_retrieved: '2024-12-01T10:00:00Z'
}
},
{
id: '124',
state: 'proposed',
patient_id: '457',
referral: {
referral_number: 'ref124'
},
provider_service_id: 'DBKQ-H0a',
network_id: 'random-sandbox-network-id',
slot_ids: [
'5vuTac8v-practitioner-8-role-1|' \
'9783e46c-efe2-462c-84a1-7af5f5f6613a|' \
'2024-12-01T10:00:00Z|30m0s|1733338893365|ov'
],
appointment_details: {
status: 'booked',
start: '2024-12-02T10:00:00Z',
is_latest: false,
last_retrieved: '2024-12-02T10:00:00Z'
}
},
{
id: '125',
state: 'submitted',
patient_id: '458',
referral: {
referral_number: 'ref125'
},
provider_service_id: 'DBKQ-H0a',
network_id: 'random-sandbox-network-id',
slot_ids: [
'5vuTac8v-practitioner-8-role-1|' \
'9783e46c-efe2-462c-84a1-7af5f5f6613a|' \
'2024-12-01T10:00:00Z|30m0s|1733338893365|ov'
],
appointment_details: {
status: 'booked',
start: '2024-12-03T10:00:00Z',
is_latest: false,
last_retrieved: '2024-12-03T10:00:00Z'
}
},
{
id: 'thedupe',
state: 'submitted',
patient_id: 'fake-patient-id',
referral: {
referral_number: '1234567890'
},
provider_service_id: 'DBKQ-H0a',
network_id: 'random-sandbox-network-id',
slot_ids: [
'5vuTac8v-practitioner-8-role-1|' \
'9783e46c-efe2-462c-84a1-7af5f5f6613a|' \
'2024-12-01T10:00:00Z|30m0s|1733338893365|ov'
],
appointment_details: {
status: 'booked',
start: '2024-11-18T13:30:00Z',
is_latest: false,
last_retrieved: '2025-01-12T22:35:45Z'
}
}
]
end

mock_facility = {
test: 'test',
timezone: {
Expand Down Expand Up @@ -1070,6 +1159,68 @@
end
end

describe '#get_appointments merge' do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please add more tests for scenarios like no matching referral number, nil start date, empty eps_appointments or appointment data?

context 'when include eps is true' do
it 'merges eps appointments with vaos appointments' do
VCR.use_cassette('vaos/eps/get_appointments_200_with_merge',
match_requests_on: %i[method path query], allow_playback_repeats: true, tag: :force_utf8) do
allow_any_instance_of(Eps::AppointmentService).to receive(:get_appointments).and_return(eps_appointments)
Comment on lines +1165 to +1167
Copy link
Member

@randomsync randomsync Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curious why we're mixing use of VCR with a mock

result = subject.get_appointments(start_date, end_date, nil, {}, { eps: true })
expect(result[:data].map { |appt| appt[:referral][:referral_number] }).to include('ref124', 'ref125')
expect(result[:data].map { |appt| appt[:id].to_s }).to include('101', '102', '186')
end
end

it 'merges eps appointments with vaos appointments and removes eps appointment with duplicate referralNumbers ' \
'but not the vaos appointment' do
VCR.use_cassette('vaos/eps/get_appointments_200_with_merge',
match_requests_on: %i[method path query], allow_playback_repeats: true, tag: :force_utf8) do
allow_any_instance_of(Eps::AppointmentService).to receive(:get_appointments).and_return(eps_appointments)
result = subject.get_appointments(start_date, end_date, nil, {}, { eps: true })
expect(result[:data].map { |appt| appt[:id].to_s }).not_to include('thedupe')
end
end

it 'handles no matching referral number' do
VCR.use_cassette('vaos/eps/get_appointments_200_with_merge',
match_requests_on: %i[method path query], allow_playback_repeats: true, tag: :force_utf8) do
allow_any_instance_of(Eps::AppointmentService).to receive(:get_appointments).and_return(eps_appointments)
result = subject.get_appointments(start_date, end_date, nil, {}, { eps: true })
expect(result[:data].map { |appt| appt[:referral][:referral_number] }).not_to include('nonexistent_referral')
end
end

it 'handles nil start date in eps appointments' do
VCR.use_cassette('vaos/eps/get_appointments_200_with_merge',
match_requests_on: %i[method path query], allow_playback_repeats: true, tag: :force_utf8) do
allow_any_instance_of(Eps::AppointmentService).to receive(:get_appointments).and_return(eps_appointments)
result = subject.get_appointments(start_date, end_date, nil, {}, { eps: true })
expect(result[:data].map { |appt| appt[:id].to_s }).not_to include('123')
end
end

it 'handles empty eps_appointments' do
VCR.use_cassette('vaos/eps/get_appointments_200_with_merge',
match_requests_on: %i[method path query], allow_playback_repeats: true, tag: :force_utf8) do
allow_any_instance_of(Eps::AppointmentService).to receive(:get_appointments).and_return([])
result = subject.get_appointments(start_date, end_date, nil, {}, { eps: true })
expect(result[:data].map do |appt|
appt[:referral][:referral_number]
end).to include('0987654321', '1234567890', '1122334455', '6677889900', '1234567890')
end
end

it 'handles empty appointment data' do
VCR.use_cassette('vaos/eps/get_appointments_empty_data',
match_requests_on: %i[method path query], allow_playback_repeats: true, tag: :force_utf8) do
allow_any_instance_of(Eps::AppointmentService).to receive(:get_appointments).and_return([{}])
result = subject.get_appointments(start_date, end_date, nil, {}, { eps: true })
expect(result[:data].map { |appt| appt[:referral][:referral_number] }).to be_empty
end
end
end
end

describe '#convert_appointment_time' do
let(:manila_appt) do
{
Expand Down
Loading
Loading