Skip to content

Commit

Permalink
[ART] Serialize POA form data with POA request
Browse files Browse the repository at this point in the history
  • Loading branch information
nihil2501 authored and ojbucao committed Jan 7, 2025
1 parent e8c3f72 commit 1ef45c0
Show file tree
Hide file tree
Showing 14 changed files with 492 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def index
def show
poa_request = PowerOfAttorneyRequest.includes(resolution: :resolving).find(params[:id])
serializer = PowerOfAttorneyRequestSerializer.new(poa_request)

render json: serializer.serializable_hash, status: :ok
rescue ActiveRecord::RecordNotFound
render json: { error: 'Record not found' }, status: :not_found
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,57 @@

module AccreditedRepresentativePortal
class PowerOfAttorneyForm < ApplicationRecord
self.ignored_columns += %w[city_bidx state_bidx zipcode_bidx]

belongs_to :power_of_attorney_request,
class_name: 'AccreditedRepresentativePortal::PowerOfAttorneyRequest',
inverse_of: :power_of_attorney_form


has_kms_key

has_encrypted :data, key: :kms_key, **lockbox_options
has_encrypted(
:data,
:claimant_city,
:claimant_state_code,
:claimant_zip_code,
key: :kms_key,
**lockbox_options
)

blind_index(
:claimant_city,
:claimant_state_code,
:claimant_zip_code
)

validate :data_must_comply_with_schema
before_validation :set_location

# Maybe can manage interdepencies between this and the POA reqeust without
# exposing this.
def parsed_data
@parsed_data ||= JSON.parse(data)
end

private

def set_location
claimant = parsed_data['dependent']
claimant ||= parsed_data['veteran']

address = claimant.to_h['address']
return unless address

self.claimant_city = address['city']
self.claimant_state_code = address['state_code']
self.claimant_zip_code = address['zip_code']
end

def data_must_comply_with_schema
data_errors = JSONSchemer.schema(SCHEMA).validate(parsed_data)
return if data_errors.none?

blind_index :city
blind_index :state
blind_index :zipcode
errors.add :data, 'does not comply with schema'
end

##
# TODO: Can couple this to the schema involved in user input during POA
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,36 @@

module AccreditedRepresentativePortal
class PowerOfAttorneyRequest < ApplicationRecord
module ClaimantTypes
DEPENDENT = 'dependent'
VETERAN = 'veteran'
end

belongs_to :claimant, class_name: 'UserAccount'

has_one :power_of_attorney_form,
class_name: 'AccreditedRepresentativePortal::PowerOfAttorneyForm',
inverse_of: :power_of_attorney_request
inverse_of: :power_of_attorney_request,
required: true

has_one :resolution,
class_name: 'AccreditedRepresentativePortal::PowerOfAttorneyRequestResolution',
inverse_of: :power_of_attorney_request

before_validation :set_claimant_type

private

def set_claimant_type
if power_of_attorney_form.parsed_data['dependent']
self.claimant_type = ClaimantTypes::DEPENDENT
return
end

if power_of_attorney_form.parsed_data['veteran']
self.claimant_type = ClaimantTypes::VETERAN
return
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

module AccreditedRepresentativePortal
class ApplicationSerializer
include JSONAPI::Serializer

# We're not building to JSONAPI.
def serializable_hash
data = super[:data]

case data
when Array
data.map(&method(:unwrap_serializable_hash))
when Hash
unwrap_serializable_hash(data)
end
end

private

def unwrap_serializable_hash(data)
data[:attributes].merge!(id: data[:id])
end
end
end

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
# frozen_string_literal: true

module AccreditedRepresentativePortal
class PowerOfAttorneyRequestSerializer
include JSONAPI::Serializer
class PowerOfAttorneyRequestSerializer < ApplicationSerializer
attributes :claimant_id, :claimant_type, :created_at

attributes :claimant_id, :created_at
attribute :power_of_attorney_form do |poa_request|
poa_request.power_of_attorney_form.parsed_data
end

attribute :resolution do |poa_request|
next unless poa_request.resolution

serializer =
case poa_request.resolution.resolving
when PowerOfAttorneyRequestDecision
PowerOfAttorneyRequestDecisionSerializer
DecisionSerializer
when PowerOfAttorneyRequestExpiration
PowerOfAttorneyRequestExpirationSerializer
ExpirationSerializer
end

serializer.new(poa_request.resolution)
serializer
.new(poa_request.resolution)
.serializable_hash
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module AccreditedRepresentativePortal
class PowerOfAttorneyRequestSerializer
class DecisionSerializer < ResolutionSerializer
attribute(:type) { 'decision' }

attribute :decision_type do |resolution|
case resolution.resolving.type
when PowerOfAttorneyRequestDecision::Types::ACCEPTANCE
'acceptance'
when PowerOfAttorneyRequestDecision::Types::DECLINATION
'declination'
end
end

attribute :reason, if: proc { |resolution|
resolution.resolving.type == PowerOfAttorneyRequestDecision::Types::DECLINATION
}

attribute :creator_id do |resolution|
resolution.resolving.creator_id
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module AccreditedRepresentativePortal
class PowerOfAttorneyRequestSerializer
class ExpirationSerializer < ResolutionSerializer
attribute(:type) { 'expiration' }
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module AccreditedRepresentativePortal
class PowerOfAttorneyRequestSerializer
class ResolutionSerializer < ApplicationSerializer
attributes :created_at
end
end
end
Original file line number Diff line number Diff line change
@@ -1,10 +1,60 @@
# frozen_string_literal: true

form_data = <<~JSON
{
"authorizations": {
"record_disclosure": true,
"record_disclosure_limitations": [],
"address_change": true
},
"dependent": {
"name": {
"first": "John",
"middle": "Middle",
"last": "Doe"
},
"address": {
"address_line1": "123 Main St",
"address_line2": "Apt 1",
"city": "Springfield",
"state_code": "IL",
"country": "US",
"zip_code": "62704",
"zip_code_suffix": "6789"
},
"date_of_birth": "1980-12-31",
"relationship": "Spouse",
"phone": "1234567890",
"email": "[email protected]"
},
"veteran": {
"name": {
"first": "John",
"middle": "Middle",
"last": "Doe"
},
"address": {
"address_line1": "123 Main St",
"address_line2": "Apt 1",
"city": "Springfield",
"state_code": "IL",
"country": "US",
"zip_code": "62704",
"zip_code_suffix": "6789"
},
"ssn": "123456789",
"va_file_number": "123456789",
"date_of_birth": "1980-12-31",
"service_number": "123456789",
"service_branch": "ARMY",
"phone": "1234567890",
"email": "[email protected]"
}
}
JSON

FactoryBot.define do
factory :power_of_attorney_form, class: 'AccreditedRepresentativePortal::PowerOfAttorneyForm' do
data_ciphertext { 'Test encrypted data' }
city_bidx { Faker::Alphanumeric.alphanumeric(number: 44) }
state_bidx { Faker::Alphanumeric.alphanumeric(number: 44) }
zipcode_bidx { Faker::Alphanumeric.alphanumeric(number: 44) }
data { form_data }
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
FactoryBot.define do
factory :power_of_attorney_request, class: 'AccreditedRepresentativePortal::PowerOfAttorneyRequest' do
association :claimant, factory: :user_account
association :power_of_attorney_form, strategy: :build

trait :with_acceptance do
resolution { create(:power_of_attorney_request_resolution, :acceptance) }
Expand Down
Loading

0 comments on commit 1ef45c0

Please sign in to comment.