Skip to content

Commit

Permalink
[API-35332] View POA Requests - Filtering (#19306)
Browse files Browse the repository at this point in the history
* add page size and index

* update docs

* add pageSize validation

* wrap response in an array

* add filter validation

* add filters

* add tests

* add docs

* restore gemfile
  • Loading branch information
tycol7 authored Nov 12, 2024
1 parent b28d8a8 commit 4912bed
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def index
poa_codes = form_attributes['poaCodes']
page_size = form_attributes['pageSize']
page_index = form_attributes['pageIndex']
filter = form_attributes['filter'] || {}

unless poa_codes.is_a?(Array) && poa_codes.size.positive?
raise ::Common::Exceptions::ParameterMissing.new('poaCodes',
Expand All @@ -26,10 +27,12 @@ def index
detail: 'pageSize is required when pageIndex is present')
end

service = ManageRepresentativeService.new(external_uid: 'power_of_attorney_request_uid',
external_key: 'power_of_attorney_request_key')
validate_filter!(filter)

service = ClaimsApi::ManageRepresentativeService.new(external_uid: 'power_of_attorney_request_uid',
external_key: 'power_of_attorney_request_key')

res = service.read_poa_request(poa_codes:, page_size:, page_index:)
res = service.read_poa_request(poa_codes:, page_size:, page_index:, filter:)

poa_list = res['poaRequestRespondReturnVOList']

Expand Down Expand Up @@ -130,6 +133,40 @@ def build_bgs_attributes(form_attributes)
bgs_form_attributes
end

def validate_filter!(filter)
return nil if filter.blank?

valid_filters = %w[status state city country]

invalid_filters = filter.keys - valid_filters

if invalid_filters.any?
raise ::Common::Exceptions::UnprocessableEntity.new(
detail: "Invalid filter(s): #{invalid_filters.join(', ')}"
)
end

validate_statuses!(filter['status'])
end

def validate_statuses!(statuses)
return nil if statuses.blank?

unless statuses.is_a?(Array)
raise ::Common::Exceptions::UnprocessableEntity.new(
detail: 'filter status must be an array'
)
end

valid_statuses = ManageRepresentativeService::ALL_STATUSES

if statuses.any? { |status| valid_statuses.exclude?(status.upcase) }
raise ::Common::Exceptions::UnprocessableEntity.new(
detail: "Status(es) must be one of: #{valid_statuses.join(', ')}"
)
end
end

def normalize(item)
item.to_s.strip.downcase
end
Expand Down
38 changes: 37 additions & 1 deletion modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,32 @@
},
"pageIndex": {
"type": "string"
},
"filter": {
"type": "object",
"additionalProperties": false,
"properties": {
"status": {
"type": "array",
"items": {
"type": "string",
"enum": [
"NEW",
"ACCEPTED",
"DECLINED"
]
}
},
"state": {
"type": "string"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
}
}
}
}
}
Expand All @@ -721,7 +747,17 @@
"083"
],
"pageSize": "3",
"pageIndex": "1"
"pageIndex": "1",
"filter": {
"status": [
"NEW",
"ACCEPTED",
"DECLINED"
],
"state": "OR",
"city": "Portland",
"country": "USA"
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,32 @@
},
"pageIndex": {
"type": "string"
},
"filter": {
"type": "object",
"additionalProperties": false,
"properties": {
"status": {
"type": "array",
"items": {
"type": "string",
"enum": [
"NEW",
"ACCEPTED",
"DECLINED"
]
}
},
"state": {
"type": "string"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,48 @@

module ClaimsApi
class ManageRepresentativeService < ClaimsApi::LocalBGS
ALL_STATUSES = %w[NEW ACCEPTED DECLINED].freeze

def bean_name
'VDC/ManageRepresentativeService'
end

def read_poa_request(poa_codes: [], page_size: nil, page_index: nil) # rubocop:disable Metrics/MethodLength
def read_poa_request(poa_codes: [], page_size: nil, page_index: nil, filter: {}) # rubocop:disable Metrics/MethodLength
# Workaround to allow multiple roots in the Nokogiri XML builder
# https://stackoverflow.com/a/4907450
doc = Nokogiri::XML::DocumentFragment.parse ''

status_list = filter['status'].presence || ALL_STATUSES
state = filter['state']
city = filter['city']
country = filter['country']

Nokogiri::XML::Builder.with(doc) do |xml|
xml.send('data:POACodeList') do
poa_codes.each do |poa_code|
xml.POACode poa_code
end
end
xml.send('data:SecondaryStatusList') do
%w[New Pending Accepted Declined].each do |status|
status_list.each do |status|
xml.SecondaryStatus status
end
end
if state
xml.send('data:StateList') do
xml.State state
end
end
if city
xml.send('data:CityList') do
xml.City city
end
end
if country
xml.send('data:CountryList') do
xml.Country country
end
end
if page_size || page_index
xml.send('data:POARequestParameter') do
xml.pageSize page_size if page_size
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,87 @@
end
end
end

context 'when pageIndex is present but pageSize is not' do
before do
allow(subject).to receive(:form_attributes).and_return({ 'poaCodes' => %w[002 003 083], 'pageIndex' => '2' })
end

it 'raises a ParameterMissing error' do
expect do
subject.index
end.to raise_error(Common::Exceptions::ParameterMissing)
end
end

context 'when valid filters are present' do
let(:filter) do
{ 'status' => %w[New Accepted Declined], 'state' => 'CA', 'city' => 'Cambria', 'country' => 'USA' }
end
let(:poa_codes) { %w[002 003 083] }
let(:mock_bgs_response) do
{
'poaRequestRespondReturnVOList' => [
{ 'some_filtered_key' => 'some_filtered_value' }
]
}
end

before do
service_double = instance_double(ClaimsApi::ManageRepresentativeService)
allow(ClaimsApi::ManageRepresentativeService).to receive(:new).with(any_args)
.and_return(service_double)
allow(service_double).to receive(:read_poa_request).with(any_args)
.and_return(mock_bgs_response)
end

it 'returns a successful response' do
mock_ccg(scopes) do |auth_header|
index_request_with(poa_codes:, filter:, auth_header:)

expect(response).to have_http_status(:ok)
end
end
end

context 'when an invalid filter is present' do
let(:filter) { { 'invalid' => 'invalid' } }
let(:poa_codes) { %w[002 003 083] }

it 'raises an UnprocessableEntity error' do
mock_ccg(scopes) do |auth_header|
index_request_with(poa_codes:, filter:, auth_header:)

expect(response).to have_http_status(:unprocessable_entity)
end
end
end

context 'when the status filter is not a list' do
let(:filter) { { 'status' => 'New' } }
let(:poa_codes) { %w[002 003 083] }

it 'raises an UnprocessableEntity error' do
mock_ccg(scopes) do |auth_header|
index_request_with(poa_codes:, filter:, auth_header:)

expect(response).to have_http_status(:unprocessable_entity)
end
end
end

context 'when a filter status is invalid' do
let(:filter) { { 'status' => %w[New Accepted Declined SomeInvalidStatus] } }
let(:poa_codes) { %w[002 003 083] }

it 'raises an UnprocessableEntity error' do
mock_ccg(scopes) do |auth_header|
index_request_with(poa_codes:, filter:, auth_header:)

expect(response).to have_http_status(:unprocessable_entity)
end
end
end
end

describe '#decide' do
Expand Down Expand Up @@ -254,9 +335,9 @@
end
end

def index_request_with(poa_codes:, auth_header:)
def index_request_with(poa_codes:, auth_header:, filter: {})
post v2_veterans_power_of_attorney_requests_path,
params: { data: { attributes: { poaCodes: poa_codes } } }.to_json,
params: { data: { attributes: { poaCodes: poa_codes, filter: } } }.to_json,
headers: auth_header
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@
'attributes' => {
'poaCodes' => %w[002 003 083],
'pageSize' => '3',
'pageIndex' => '1'
'pageIndex' => '1',
'filter' => {
'status' => %w[NEW ACCEPTED DECLINED],
'state' => 'OR',
'city' => 'Portland',
'country' => 'USA'
}
}
}
}
Expand Down

0 comments on commit 4912bed

Please sign in to comment.