diff --git a/modules/accredited_representative_portal/app/controllers/accredited_representative_portal/v0/power_of_attorney_requests_controller.rb b/modules/accredited_representative_portal/app/controllers/accredited_representative_portal/v0/power_of_attorney_requests_controller.rb index 867b3db8d32..2f0dc0a512a 100644 --- a/modules/accredited_representative_portal/app/controllers/accredited_representative_portal/v0/power_of_attorney_requests_controller.rb +++ b/modules/accredited_representative_portal/app/controllers/accredited_representative_portal/v0/power_of_attorney_requests_controller.rb @@ -3,53 +3,16 @@ module AccreditedRepresentativePortal module V0 class PowerOfAttorneyRequestsController < ApplicationController - POA_REQUEST_ITEM_MOCK_DATA = { - status: 'Pending', - declinedReason: nil, - powerOfAttorneyCode: '091', - submittedAt: '2024-04-30T11:03:17Z', - acceptedOrDeclinedAt: nil, - isAddressChangingAuthorized: false, - isTreatmentDisclosureAuthorized: true, - veteran: { - firstName: 'Jon', - middleName: nil, - lastName: 'Smith', - participantId: '6666666666666' - }, - representative: { - email: 'j2@example.com', - firstName: 'Jane', - lastName: 'Doe' - }, - claimant: { - firstName: 'Sam', - lastName: 'Smith', - participantId: '777777777777777', - relationshipToVeteran: 'Child' - }, - claimantAddress: { - city: 'Hartford', - state: 'CT', - zip: '06107', - country: 'GU', - militaryPostOffice: nil, - militaryPostalCode: nil - } - }.freeze - - POA_REQUEST_LIST_MOCK_DATA = [ - POA_REQUEST_ITEM_MOCK_DATA, - POA_REQUEST_ITEM_MOCK_DATA, - POA_REQUEST_ITEM_MOCK_DATA - ].freeze - def index - render json: POA_REQUEST_LIST_MOCK_DATA + poa_requests = PowerOfAttorneyRequest.includes(resolution: :resolving).limit(100) + render json: PowerOfAttorneyRequestSerializer.new(poa_requests).serializable_hash, status: :ok end def show - render json: POA_REQUEST_ITEM_MOCK_DATA + poa_request = PowerOfAttorneyRequest.includes(resolution: :resolving).find(params[:id]) + render json: PowerOfAttorneyRequestSerializer.new(poa_request).serializable_hash, status: :ok + rescue ActiveRecord::RecordNotFound + render json: { error: 'Record not found' }, status: :not_found end end end diff --git a/modules/accredited_representative_portal/app/serializers/accredited_representative_portal/power_of_attorney_request_resolution_serializer.rb b/modules/accredited_representative_portal/app/serializers/accredited_representative_portal/power_of_attorney_request_resolution_serializer.rb new file mode 100644 index 00000000000..99ce0602977 --- /dev/null +++ b/modules/accredited_representative_portal/app/serializers/accredited_representative_portal/power_of_attorney_request_resolution_serializer.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module AccreditedRepresentativePortal + class PowerOfAttorneyRequestResolutionSerializer + include JSONAPI::Serializer + + attribute :id + + attribute :type do |object| + object.resolving_type.demodulize.underscore.split('_').last + end + + attribute :decision_type, if: proc { |obj| obj.resolving.respond_to?(:type) } do |object| + object.resolving.type + end + + attribute :reason + + attribute :creator_id, if: proc { |obj| obj.resolving.respond_to?(:creator_id) } do |object| + object.resolving.creator_id + end + + attribute :created_at do |object| + object.created_at.iso8601 + end + end +end diff --git a/modules/accredited_representative_portal/app/serializers/accredited_representative_portal/power_of_attorney_request_serializer.rb b/modules/accredited_representative_portal/app/serializers/accredited_representative_portal/power_of_attorney_request_serializer.rb new file mode 100644 index 00000000000..4114143b6b1 --- /dev/null +++ b/modules/accredited_representative_portal/app/serializers/accredited_representative_portal/power_of_attorney_request_serializer.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module AccreditedRepresentativePortal + class PowerOfAttorneyRequestSerializer + include JSONAPI::Serializer + + attributes :id, :claimant_id + + attribute :created_at do |object| + object.created_at.iso8601 + end + + attribute :resolution do |object| + next nil if object.resolution.blank? + + AccreditedRepresentativePortal::PowerOfAttorneyRequestResolutionSerializer.new( + object.resolution + ).serializable_hash[:data][:attributes] + end + end +end diff --git a/modules/accredited_representative_portal/spec/factories/power_of_attorney_decision.rb b/modules/accredited_representative_portal/spec/factories/power_of_attorney_decision.rb index fd6f2e65d66..96066eafe0c 100644 --- a/modules/accredited_representative_portal/spec/factories/power_of_attorney_decision.rb +++ b/modules/accredited_representative_portal/spec/factories/power_of_attorney_decision.rb @@ -6,5 +6,13 @@ id { Faker::Internet.uuid } association :creator, factory: :user_account type { 'Approval' } + + trait :declination do + type { 'Declination' } + end + + trait :approval do + type { 'Approval' } + end end end diff --git a/modules/accredited_representative_portal/spec/factories/power_of_attorney_request.rb b/modules/accredited_representative_portal/spec/factories/power_of_attorney_request.rb index 0aa23eea4f6..5d04780c575 100644 --- a/modules/accredited_representative_portal/spec/factories/power_of_attorney_request.rb +++ b/modules/accredited_representative_portal/spec/factories/power_of_attorney_request.rb @@ -5,5 +5,9 @@ association :claimant, factory: :user_account id { Faker::Internet.uuid } created_at { Time.current } + + trait :with_resolution do + resolution { create(:power_of_attorney_request_resolution, :with_decision) } + end end end diff --git a/modules/accredited_representative_portal/spec/factories/power_of_attorney_request_resolution.rb b/modules/accredited_representative_portal/spec/factories/power_of_attorney_request_resolution.rb index 20798bf1d54..1b7ca929b5a 100644 --- a/modules/accredited_representative_portal/spec/factories/power_of_attorney_request_resolution.rb +++ b/modules/accredited_representative_portal/spec/factories/power_of_attorney_request_resolution.rb @@ -3,12 +3,16 @@ FactoryBot.define do factory :power_of_attorney_request_resolution, class: 'AccreditedRepresentativePortal::PowerOfAttorneyRequestResolution' do - association :power_of_attorney_request, factory: :power_of_attorney_request - resolving_id { SecureRandom.uuid } - reason_ciphertext { 'Encrypted Reason' } + association :power_of_attorney_request + resolving_type { 'AccreditedRepresentativePortal::PowerOfAttorneyRequestExpiration' } + reason { 'Test reason for resolution' } created_at { Time.current } encrypted_kms_key { SecureRandom.hex(16) } + after(:build) do |resolution| + resolution.id ||= SecureRandom.random_number(1000) + end + trait :with_expiration do resolving_type { 'AccreditedRepresentativePortal::PowerOfAttorneyRequestExpiration' } resolving { create(:power_of_attorney_request_expiration) } @@ -16,7 +20,13 @@ trait :with_decision do resolving_type { 'AccreditedRepresentativePortal::PowerOfAttorneyRequestDecision' } - resolving { create(:power_of_attorney_request_decision) } + resolving { create(:power_of_attorney_request_decision, creator: create(:user_account)) } + end + + trait :with_declination do + resolving_type { 'AccreditedRepresentativePortal::PowerOfAttorneyRequestDecision' } + reason { "Didn't authorize treatment record disclosure" } + resolving { create(:power_of_attorney_request_decision, creator: create(:user_account)) } end trait :with_invalid_type do diff --git a/modules/accredited_representative_portal/spec/requests/accredited_representative_portal/v0/power_of_attorney_requests_spec.rb b/modules/accredited_representative_portal/spec/requests/accredited_representative_portal/v0/power_of_attorney_requests_spec.rb index c1349f2db60..b9f4f6f2b58 100644 --- a/modules/accredited_representative_portal/spec/requests/accredited_representative_portal/v0/power_of_attorney_requests_spec.rb +++ b/modules/accredited_representative_portal/spec/requests/accredited_representative_portal/v0/power_of_attorney_requests_spec.rb @@ -4,28 +4,8 @@ RSpec.describe AccreditedRepresentativePortal::V0::PowerOfAttorneyRequestsController, type: :request do let(:test_user) { create(:representative_user) } - let(:poa_request_details_id) { '123' } - let(:poa_request_details_mock_data) do - { - 'status' => 'Pending', - 'declinedReason' => nil, - 'powerOfAttorneyCode' => '091', - 'submittedAt' => '2024-04-30T11:03:17Z', - 'acceptedOrDeclinedAt' => nil, - 'isAddressChangingAuthorized' => false, - 'isTreatmentDisclosureAuthorized' => true, - 'veteran' => { 'firstName' => 'Jon', 'middleName' => nil, 'lastName' => 'Smith', - 'participantId' => '6666666666666' }, - 'representative' => { 'email' => 'j2@example.com', 'firstName' => 'Jane', 'lastName' => 'Doe' }, - 'claimant' => { 'firstName' => 'Sam', 'lastName' => 'Smith', 'participantId' => '777777777777777', - 'relationshipToVeteran' => 'Child' }, - 'claimantAddress' => { 'city' => 'Hartford', 'state' => 'CT', 'zip' => '06107', 'country' => 'GU', - 'militaryPostOffice' => nil, 'militaryPostalCode' => nil } - } - end - let(:poa_request_list_mock_data) do - [poa_request_details_mock_data, poa_request_details_mock_data, poa_request_details_mock_data] - end + let(:poa_request) { create(:power_of_attorney_request) } + let(:poa_requests) { create_list(:power_of_attorney_request, 3) } before do Flipper.enable(:accredited_representative_portal_pilot) @@ -33,18 +13,34 @@ end describe 'GET /accredited_representative_portal/v0/power_of_attorney_requests' do - it 'returns the list of a power of attorney request' do + it 'returns the list of power of attorney requests' do + poa_requests + get('/accredited_representative_portal/v0/power_of_attorney_requests') + expect(response).to have_http_status(:ok) - expect(JSON.parse(response.body)).to eq(poa_request_list_mock_data) + parsed_response = JSON.parse(response.body) + + expected_response = AccreditedRepresentativePortal::PowerOfAttorneyRequestSerializer + .new(poa_requests) + .serializable_hash + + expect(parsed_response.to_json).to eq(expected_response.to_json) end end describe 'GET /accredited_representative_portal/v0/power_of_attorney_requests/:id' do - it 'returns the details of a power of attorney request' do - get("/accredited_representative_portal/v0/power_of_attorney_requests/#{poa_request_details_id}") + it 'returns the details of a specific power of attorney request' do + get("/accredited_representative_portal/v0/power_of_attorney_requests/#{poa_request.id}") + expect(response).to have_http_status(:ok) - expect(JSON.parse(response.body)).to include(poa_request_details_mock_data) + parsed_response = JSON.parse(response.body) + + expected_response = AccreditedRepresentativePortal::PowerOfAttorneyRequestSerializer + .new(poa_request) + .serializable_hash + + expect(parsed_response.to_json).to eq(expected_response.to_json) end end end diff --git a/modules/accredited_representative_portal/spec/serializers/accredited_representative_portal/power_of_attorney_request_resolution_serializer_spec.rb b/modules/accredited_representative_portal/spec/serializers/accredited_representative_portal/power_of_attorney_request_resolution_serializer_spec.rb new file mode 100644 index 00000000000..3df2538fd8b --- /dev/null +++ b/modules/accredited_representative_portal/spec/serializers/accredited_representative_portal/power_of_attorney_request_resolution_serializer_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require_relative '../../rails_helper' + +RSpec.describe AccreditedRepresentativePortal::PowerOfAttorneyRequestResolutionSerializer, type: :serializer do + describe 'serialization' do + subject { described_class.new(resolution).serializable_hash[:data][:attributes] } + + let(:user) { create(:user_account) } + let(:resolution) do + create(:power_of_attorney_request_resolution, resolving: resolving, reason: 'Did not authorize') + end + + context 'when resolving is a Decision' do + let(:resolving) { create(:power_of_attorney_request_decision, type: 'declination', creator: user) } + + it 'serializes resolution with decision-specific fields' do + expect(subject).to eq( + id: resolution.id, + created_at: resolution.created_at.iso8601, + reason: 'Did not authorize', + type: 'decision', + decision_type: 'declination', + creator_id: user.id + ) + end + end + + context 'when resolving is an Expiration' do + let(:resolving) { create(:power_of_attorney_request_expiration) } + + it 'serializes resolution with expiration-specific fields' do + expect(subject).to eq( + id: resolution.id, + created_at: resolution.created_at.iso8601, + reason: 'Did not authorize', + type: 'expiration' + ) + end + end + end +end diff --git a/modules/accredited_representative_portal/spec/serializers/accredited_representative_portal/power_of_attorney_request_serializer_spec.rb b/modules/accredited_representative_portal/spec/serializers/accredited_representative_portal/power_of_attorney_request_serializer_spec.rb new file mode 100644 index 00000000000..b923cf977bd --- /dev/null +++ b/modules/accredited_representative_portal/spec/serializers/accredited_representative_portal/power_of_attorney_request_serializer_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require_relative '../../rails_helper' + +RSpec.describe AccreditedRepresentativePortal::PowerOfAttorneyRequestSerializer, type: :serializer do + describe 'serialization' do + subject { described_class.new(poa_request).serializable_hash[:data][:attributes] } + + let(:claimant) { create(:user_account) } + let(:poa_request) { create(:power_of_attorney_request, claimant: claimant, resolution: resolution) } + + context 'when resolution exists' do + let(:resolution) do + create(:power_of_attorney_request_resolution, + resolving: create(:power_of_attorney_request_decision, type: 'declination')) + end + + it 'serializes POA request with resolution' do + expect(subject).to eq( + id: poa_request.id, + claimant_id: poa_request.claimant_id, + created_at: poa_request.created_at.iso8601, + resolution: { + id: resolution.id, + created_at: resolution.created_at.iso8601, + reason: resolution.reason, + type: 'decision', + decision_type: 'declination', + creator_id: resolution.resolving.creator_id + } + ) + end + end + + context 'when resolution is absent' do + let(:resolution) { nil } + + it 'serializes POA request without resolution' do + expect(subject).to eq( + id: poa_request.id, + claimant_id: poa_request.claimant_id, + created_at: poa_request.created_at.iso8601, + resolution: nil + ) + end + end + end +end