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

Add new endpoint to vaos and mobile module for VPG appointment slots #16036

Merged
merged 9 commits into from
Apr 2, 2024
25 changes: 25 additions & 0 deletions modules/mobile/app/controllers/mobile/v0/clinics_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,37 @@ def slots

response = systems_service.get_available_slots(location_id: facility_id,
clinic_id:,
clinical_service: nil,
start_dt: start_date,
end_dt: end_date)

render json: Mobile::V0::ClinicSlotsSerializer.new(response)
end

def facility_slots
if params[:clinic_id] || params[:clinical_service]
start_date = params[:start_date] || now.iso8601
end_date = params[:end_date] || two_months_from_now.iso8601

response = systems_service.get_available_slots(location_id: facility_id,
clinic_id: params[:clinic_id],
clinical_service: params[:clinical_service],
start_dt: start_date,
end_dt: end_date)

render json: Mobile::V0::ClinicSlotsSerializer.new(response)
else
render status: :bad_request, json: {
errors: [
{
status: 400,
detail: 'clinic_id or clinical_service is required.'
}
]
}
end
end

private

def systems_service
Expand Down
1 change: 1 addition & 0 deletions modules/mobile/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
get '/appointments/facility/eligibility', to: 'facility_eligibility#index'
get '/appointments/facilities/:facility_id/clinics', to: 'clinics#index'
get '/appointments/facilities/:facility_id/clinics/:clinic_id/slots', to: 'clinics#slots'
get '/appointments/facilities/:facility_id/slots', to: 'clinics#facility_slots'
get '/appointments/preferences', to: 'appointment_preferences#show'
put '/appointments/preferences', to: 'appointment_preferences#update'
post '/appointments/check-in', to: 'check_in#create'
Expand Down
67 changes: 67 additions & 0 deletions modules/mobile/docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,73 @@ paths:
security:
- Bearer: []
summary: /v0/appointments/facilities/{facility_id}/clinics/{clinic_id}/slots
/v0/appointments/facilities/{facility_id}/slots:
get:
description: Accepts date range for a va facility and returns available slots for a a direct schedule appointment.
parameters:
- description: The start date for the range of appointments slots in ISO 8601 UTC
format. If not provided the start date will be considered now.
example: 2020-10-29T07:00:00Z
in: query
name: startDate
schema:
format: date-time
type: string
- description: The end date for the range of appointments slots in ISO 8601 UTC format.
If not provided the end date will be 2 months from today's date
example: 2021-11-29T08:00:00Z
in: query
name: endDate
schema:
format: date-time
type: string
- description: The facility division ID
in: path
required: true
name: location_id
schema:
type: string
- description: The clinic IEN. Required if clinical_service not provided.
in: query
required: false
name: clinic_id
schema:
type: string
- description: The clinical service (type of care) to find appointment slots for. Required if clinic_id not provided.
in: query
required: false
name: clinical_service
schema:
type: string
- $ref: '#/components/parameters/InflectionHeader'
responses:
'200':
content:
application/json:
schema:
$ref: ./schemas/ClinicSlots.yml
description: OK
'401':
$ref: '#/components/responses/401'
'403':
$ref: '#/components/responses/403'
'404':
$ref: '#/components/responses/404'
'408':
$ref: '#/components/responses/408'
'422':
$ref: '#/components/responses/422'
'500':
$ref: '#/components/responses/500'
'502':
$ref: '#/components/responses/502'
'503':
$ref: '#/components/responses/503'
'504':
$ref: '#/components/responses/504'
security:
- Bearer: [ ]
summary: /v0/appointments/facilities/{facility_id}/clinics/{clinic_id}/slots
/v0/appointments/preferences:
get:
description: Returns VAOS appointment contact preferences
Expand Down
189 changes: 176 additions & 13 deletions modules/mobile/spec/request/clinics_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
allow_any_instance_of(VAOS::UserService).to receive(:session).and_return('stubbed_token')
end

describe 'PUT /mobile/v0/appointments/facilities/:facility_id/clinics', :aggregate_failures do
describe 'GET /mobile/v0/appointments/facilities/:facility_id/clinics', :aggregate_failures do
context 'when both facility id and service type is found' do
let(:facility_id) { '983' }
let(:params) { { service_type: 'audiology' } }
Expand Down Expand Up @@ -60,19 +60,158 @@
end
end

describe 'PUT /mobile/v0/appointments/facilities/{facililty_id}/clinics/{clinic_id}/slots', :aggregate_failures do
describe 'GET /mobile/v0/appointments/facilities/{facililty_id}/slots', :aggregate_failures do
context 'when both facility id and clinic id is found' do
before do
Flipper.enable(:va_online_scheduling_use_vpg)
Flipper.enable(:va_online_scheduling_enable_OH_slots_search)
end

let(:facility_id) { '983' }
let(:clinic_id) { '1081' }
let(:params) { { start_date: '2021-10-26T00:00:00Z', end_date: '2021-12-30T23:59:59Z' } }
let(:params) do
{
start_date: '2021-10-26T00:00:00Z',
end_date: '2021-12-30T23:59:59Z',
clinic_id: '1081'
}
end

it 'returns 200' do
VCR.use_cassette('mobile/appointments/get_available_slots_200', match_requests_on: %i[method uri]) do
get "/mobile/v0/appointments/facilities/#{facility_id}/clinics/#{clinic_id}/slots", params:,
headers: sis_headers
VCR.use_cassette('mobile/appointments/get_available_slots_vpg_200', match_requests_on: %i[method uri]) do
get "/mobile/v0/appointments/facilities/#{facility_id}/slots", params:,
headers: sis_headers
expect(response).to have_http_status(:ok)
expect(response.body).to match_json_schema('clinic_slot')
end
end
end

context 'when clinic_id and clinical_service are not given' do
let(:facility_id) { '983' }

it 'returns 400 error' do
get "/mobile/v0/appointments/facilities/#{facility_id}/slots", params: {},
headers: sis_headers

expect(response).to have_http_status(:bad_request)
expect(JSON.parse(response.body)['errors'][0]['detail'])
.to eq('clinic_id or clinical_service is required.')
end
end

context 'when start and end date are not given' do
let(:facility_id) { '983' }
let(:current_time) { '2021-10-25T01:00:00Z' }
let(:params) do
{
clinic_id: '1081'
}
end

before do
Timecop.freeze(Time.zone.parse(current_time))
Flipper.disable(:va_online_scheduling_use_vpg)
Flipper.disable(:va_online_scheduling_enable_OH_slots_search)
end

after do
Timecop.return
end

it 'defaults time from now to 2 months from now' do
VCR.use_cassette('mobile/appointments/get_available_slots_200_no_start_end_date',
match_requests_on: %i[method uri]) do
get "/mobile/v0/appointments/facilities/#{facility_id}/slots",
params:,
headers: sis_headers

expect(response).to have_http_status(:ok)
expect(response.body).to match_json_schema('clinic_slot')

parsed_response = response.parsed_body['data']
min_start_date = parsed_response.map { |x| x.dig('attributes', 'startDate') }.min
max_end_date = parsed_response.map { |x| x.dig('attributes', 'endDate') }.max
expect(min_start_date).to be > current_time
expect(max_end_date).to be < '2021-12-25T23:59:59Z'
end
end
end

context 'with a upstream service 500 response' do
let(:facility_id) { '983' }
let(:clinic_id) { '1081' }
let(:params) { { start_date: '2021-10-01T00:00:00Z', end_date: '2021-12-31T23:59:59Z' } }

context 'using VAOS' do
before do
Flipper.disable(:va_online_scheduling_use_vpg)
Flipper.disable(:va_online_scheduling_enable_OH_slots_search)
end

it 'returns a 502 error' do
VCR.use_cassette('mobile/appointments/get_available_slots_500', match_requests_on: %i[method uri]) do
get "/mobile/v0/appointments/facilities/#{facility_id}/clinics/#{clinic_id}/slots", params:,
headers: sis_headers
expect(response).to have_http_status(:bad_gateway)
expect(response.body).to match_json_schema('errors')
end
end
end

context 'using VPG' do
before do
Flipper.enable(:va_online_scheduling_use_vpg)
Flipper.enable(:va_online_scheduling_enable_OH_slots_search)
end

it 'returns a 502 error' do
VCR.use_cassette('mobile/appointments/get_available_slots_vpg_500', match_requests_on: %i[method uri]) do
get "/mobile/v0/appointments/facilities/#{facility_id}/clinics/#{clinic_id}/slots", params:,
headers: sis_headers
expect(response).to have_http_status(:bad_gateway)
expect(response.body).to match_json_schema('errors')
end
end
end
end
end

describe 'GET /mobile/v0/appointments/facilities/{facililty_id}/clinics/{clinic_id}/slots', :aggregate_failures do
context 'when both facility id and clinic id is found' do
let(:facility_id) { '983' }
let(:clinic_id) { '1081' }
let(:params) { { start_date: '2021-10-26T00:00:00Z', end_date: '2021-12-30T23:59:59Z' } }

context 'using VAOS' do
before do
Flipper.disable(:va_online_scheduling_use_vpg)
Flipper.disable(:va_online_scheduling_enable_OH_slots_search)
end

it 'returns 200' do
VCR.use_cassette('mobile/appointments/get_available_slots_200', match_requests_on: %i[method uri]) do
get "/mobile/v0/appointments/facilities/#{facility_id}/clinics/#{clinic_id}/slots", params:,
headers: sis_headers

expect(response).to have_http_status(:ok)
expect(response.body).to match_json_schema('clinic_slot')
end
end
end

context 'using VPG' do
before do
Flipper.enable(:va_online_scheduling_use_vpg)
Flipper.enable(:va_online_scheduling_enable_OH_slots_search)
end

it 'returns 200' do
VCR.use_cassette('mobile/appointments/get_available_slots_vpg_200', match_requests_on: %i[method uri]) do
get "/mobile/v0/appointments/facilities/#{facility_id}/clinics/#{clinic_id}/slots", params:,
headers: sis_headers
expect(response).to have_http_status(:ok)
expect(response.body).to match_json_schema('clinic_slot')
end
end
end
end
Expand All @@ -84,6 +223,8 @@

before do
Timecop.freeze(Time.zone.parse(current_time))
Flipper.disable(:va_online_scheduling_use_vpg)
Flipper.disable(:va_online_scheduling_enable_OH_slots_search)
end

after do
Expand Down Expand Up @@ -112,13 +253,35 @@
let(:clinic_id) { '1081' }
let(:params) { { start_date: '2021-10-01T00:00:00Z', end_date: '2021-12-31T23:59:59Z' } }

it 'returns a 502 error' do
VCR.use_cassette('mobile/appointments/get_available_slots_500', match_requests_on: %i[method uri]) do
get "/mobile/v0/appointments/facilities/#{facility_id}/clinics/#{clinic_id}/slots", params:,
headers: sis_headers
context 'using VAOS' do
before do
Flipper.disable(:va_online_scheduling_use_vpg)
Flipper.disable(:va_online_scheduling_enable_OH_slots_search)
end

it 'returns a 502 error' do
VCR.use_cassette('mobile/appointments/get_available_slots_500', match_requests_on: %i[method uri]) do
get "/mobile/v0/appointments/facilities/#{facility_id}/clinics/#{clinic_id}/slots", params:,
headers: sis_headers
expect(response).to have_http_status(:bad_gateway)
expect(response.body).to match_json_schema('errors')
end
end
end

context 'using VPG' do
before do
Flipper.enable(:va_online_scheduling_use_vpg)
Flipper.enable(:va_online_scheduling_enable_OH_slots_search)
end

expect(response).to have_http_status(:bad_gateway)
expect(response.body).to match_json_schema('errors')
it 'returns a 502 error' do
VCR.use_cassette('mobile/appointments/get_available_slots_vpg_500', match_requests_on: %i[method uri]) do
get "/mobile/v0/appointments/facilities/#{facility_id}/clinics/#{clinic_id}/slots", params:,
headers: sis_headers
expect(response).to have_http_status(:bad_gateway)
expect(response.body).to match_json_schema('errors')
end
end
end
end
Expand Down
22 changes: 22 additions & 0 deletions modules/vaos/app/controllers/vaos/v2/slots_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,33 @@ class SlotsController < VAOS::BaseController
def index
response = systems_service.get_available_slots(location_id:,
clinic_id:,
clinical_service: nil,
start_dt:,
end_dt:)
render json: VAOS::V2::SlotsSerializer.new(response)
end

def facility_slots
if !params[:clinic_id] && !params[:clinical_service]
render status: :bad_request, json: {
errors: [
{
status: 400,
detail: 'clinic_id or clinical_service is required.'
}
]
}

else
response = systems_service.get_available_slots(location_id:,
clinic_id: params[:clinic_id],
clinical_service: params[:clinical_service],
start_dt:,
end_dt:)
render json: VAOS::V2::SlotsSerializer.new(response)
end
end

private

def systems_service
Expand Down
Loading
Loading