From c7eebf807e118597207e2b27de9f24472e461c98 Mon Sep 17 00:00:00 2001 From: OJ Bucao Date: Thu, 19 Dec 2024 11:59:58 -0800 Subject: [PATCH] (feat): Add serializers for PowerOfAttorneyRequest and Resolution with specs - Implement `PowerOfAttorneyRequestSerializer` to handle serialization of power of attorney requests, including nested resolution data. - Implement `PowerOfAttorneyRequestResolutionSerializer` to serialize resolution details, accommodating various resolution subtypes. - Add comprehensive specs for both serializers to ensure accurate and dynamic handling of attributes. - Adjust model factories accordingly --- .../power_of_attorney_requests_controller.rb | 12 +- ..._attorney_request_resolution_serializer.rb | 27 +++++ .../power_of_attorney_request_serializer.rb | 14 +-- .../factories/power_of_attorney_decision.rb | 8 ++ .../factories/power_of_attorney_request.rb | 4 + ...wer_of_attorney_request_resolution_spec.rb | 12 -- .../v0/power_of_attorney_requests_spec.rb | 19 +-- ...rney_request_resolution_serializer_spec.rb | 42 +++++++ ...wer_of_attorney_request_serializer_spec.rb | 109 +++++++----------- 9 files changed, 133 insertions(+), 114 deletions(-) create mode 100644 modules/accredited_representative_portal/app/serializers/accredited_representative_portal/power_of_attorney_request_resolution_serializer.rb create mode 100644 modules/accredited_representative_portal/spec/serializers/accredited_representative_portal/power_of_attorney_request_resolution_serializer_spec.rb 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 98f59734be0..f8387180711 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 @@ -4,20 +4,16 @@ module AccreditedRepresentativePortal module V0 class PowerOfAttorneyRequestsController < ApplicationController def index - requests = PowerOfAttorneyRequest.includes(:resolution) - render json: PowerOfAttorneyRequestSerializer.new(requests).serializable_hash, status: :ok + poa_requests = PowerOfAttorneyRequest.includes(:resolution) + render json: PowerOfAttorneyRequestSerializer.new(poa_requests).serializable_hash, status: :ok end def show - request = PowerOfAttorneyRequest.includes(:resolution).find(params[:id]) - render json: PowerOfAttorneyRequestSerializer.new(request).serializable_hash, status: :ok + poa_request = PowerOfAttorneyRequest.includes(:resolution).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 - - private - - def authenticate; end 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 index 89961c9989e..4114143b6b1 100644 --- 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 @@ -7,19 +7,15 @@ class PowerOfAttorneyRequestSerializer attributes :id, :claimant_id attribute :created_at do |object| - object.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ') + object.created_at.iso8601 end attribute :resolution do |object| - next nil unless object.resolution + next nil if object.resolution.blank? - { - id: object.resolution.id, - type: object.resolution.resolving_type&.demodulize&.underscore, - created_at: object.resolution.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), - reason: object.resolution&.reason, - creator_id: object.resolution.resolving.try(:creator_id) - }.compact + 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/models/accredited_representative_portal/power_of_attorney_request_resolution_spec.rb b/modules/accredited_representative_portal/spec/models/accredited_representative_portal/power_of_attorney_request_resolution_spec.rb index 9e554815756..e7a006aac77 100644 --- a/modules/accredited_representative_portal/spec/models/accredited_representative_portal/power_of_attorney_request_resolution_spec.rb +++ b/modules/accredited_representative_portal/spec/models/accredited_representative_portal/power_of_attorney_request_resolution_spec.rb @@ -55,18 +55,6 @@ end end -<<<<<<< HEAD -======= - it 'does not allow invalid resolving_type values' do - resolution = build(:power_of_attorney_request_resolution, :with_invalid_type) - resolution.resolving_type = 'AccreditedRepresentativePortal::InvalidType' - - expect(resolution).not_to be_valid - expect(resolution.errors[:resolving_type]).to include('is not included in the list') - end - end - ->>>>>>> 3815598394 ((fix) Apply requested PR changes; all specs passing) describe 'heterogeneous list behavior' do it 'conveniently returns heterogeneous lists' do travel_to Time.zone.parse('2024-11-25T09:46:24Z') 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 d58082927c0..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 @@ -25,7 +25,7 @@ .new(poa_requests) .serializable_hash - expect(deep_stringify(parsed_response)).to eq(deep_stringify(expected_response)) + expect(parsed_response.to_json).to eq(expected_response.to_json) end end @@ -40,22 +40,7 @@ .new(poa_request) .serializable_hash - expect(deep_stringify(parsed_response)).to eq(deep_stringify(expected_response)) - end - end - - def deep_stringify(value) - case value - when Hash - value.each_with_object({}) do |(k, v), result| - result[k.to_s] = deep_stringify(v) # Stringify keys and recursively process values - end - when Array - value.map { |v| deep_stringify(v) } # Recursively process arrays - when Symbol - value.to_s # Convert symbols to strings - else - value # Leave other primitives (e.g., strings, numbers, nil) as is + 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 index 14011bf6ec6..b923cf977bd 100644 --- 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 @@ -1,75 +1,48 @@ # frozen_string_literal: true -# spec/serializers/power_of_attorney_request_serializer_spec.rb -require 'rails_helper' - -RSpec.describe AccreditedRepresentativePortal::PowerOfAttorneyRequestSerializer do - subject { described_class.new(request).serializable_hash[:data][:attributes] } - - let(:request) { create(:power_of_attorney_request, created_at: '2024-12-17T00:30:55Z') } - - context 'when resolution is nil' do - it 'returns the request without resolution' do - expect(subject).to eq({ - id: request.id, - claimant_id: request.claimant_id, - created_at: '2024-12-17T00:30:55.000Z', - resolution: nil - }) - end - end - - context 'when resolution is an expiration' do - let(:resolution) do - create(:power_of_attorney_request_resolution, :with_expiration, reason: 'Test reason for resolution') +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 - before { request.update(resolution: resolution) } - - it 'includes resolution details with type expiration and reason' do - expect(subject[:resolution]).to eq({ - id: resolution.id, - type: 'power_of_attorney_request_expiration', - created_at: resolution.created_at.iso8601(3), - reason: 'Test reason for resolution' - }) - end - end - - context 'when resolution is a decision with creator_id' do - let(:resolution) do - create(:power_of_attorney_request_resolution, :with_decision) - end - - before { request.update(resolution: resolution) } - - it 'includes resolution details with type decision and creator_id' do - expect(subject[:resolution]).to eq({ - id: resolution.id, - type: 'power_of_attorney_request_decision', - created_at: resolution.created_at.iso8601(3), - reason: 'Test reason for resolution', - creator_id: resolution.resolving.creator_id - }) - end - end - - context 'when resolution is a declination with reason' do - let(:resolution) do - create(:power_of_attorney_request_resolution, :with_declination, - reason: "Didn't authorize treatment record disclosure") - end - - before { request.update(resolution: resolution) } - - it 'includes resolution details with type decision, reason, and creator_id' do - expect(subject[:resolution]).to eq({ - id: resolution.id, - type: 'power_of_attorney_request_decision', - created_at: resolution.created_at.iso8601(3), - reason: "Didn't authorize treatment record disclosure", - creator_id: resolution.resolving.creator_id - }) + 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