Skip to content

Commit

Permalink
Dash/oren/api 34439/transform bgs response to lighthouse (#16348)
Browse files Browse the repository at this point in the history
* API-34439 option to not transform BGS response

* API-34439 begin spec + impl of v2/power-of-attorney-requests

* API-34439 specify v2/power-of-attorney-requests response schema

* API-34439 specify v2/power-of-attorney-requests response example

* API-34439 appease linter for temporary hardcoded poa requests index response

* API-34439 poa request index response schema satisfies VA API naming & formatting standards
https://department-of-veterans-affairs.github.io/va-api-standards/naming-and-formatting/

* API-34439 poa request index: service to xfrom BGS -> Lighthouse response
and tweak response schema
  • Loading branch information
nihil2501 authored Apr 18, 2024
1 parent c55e75d commit 056ccee
Show file tree
Hide file tree
Showing 9 changed files with 1,019 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# frozen_string_literal: true

module ClaimsApi
module V2
module Blueprints
class PowerOfAttorneyRequestBlueprint < Blueprinter::Base
class Veteran < Blueprinter::Base
transform Transformers::LowerCamelTransformer

fields(
:first_name,
:middle_name,
:last_name,
:participant_id
)
end

class Representative < Blueprinter::Base
transform Transformers::LowerCamelTransformer

fields(
:first_name,
:last_name,
:email
)
end

class Claimant < Blueprinter::Base
transform Transformers::LowerCamelTransformer

fields(
:first_name,
:last_name,
:participant_id,
:relationship_to_veteran
)
end

class Address < Blueprinter::Base
transform Transformers::LowerCamelTransformer

fields(
:city, :state, :zip, :country,
:military_post_office,
:military_postal_code
)
end

class Attributes < Blueprinter::Base
transform Transformers::LowerCamelTransformer

fields(
:status,
:declined_reason,
:power_of_attorney_code
)

field(
:submitted_at,
datetime_format: :iso8601.to_proc
)

field(
:accepted_or_declined_at,
datetime_format: :iso8601.to_proc
)

field(
:authorizes_address_changing?,
name: :is_address_changing_authorized
)

field(
:authorizes_treatment_disclosure?,
name: :is_treatment_disclosure_authorized
)

association :veteran, blueprint: Veteran
association :representative, blueprint: Representative
association :claimant, blueprint: Claimant
association :claimant_address, blueprint: Address
end

transform Transformers::LowerCamelTransformer

identifier :id
field(:type) { 'powerOfAttorneyRequest' }

association :attributes, blueprint: Attributes do |poa_request|
poa_request
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

require 'bgs_service/manage_representative_service'

module ClaimsApi
module V2
class PowerOfAttorneyRequestsController < ClaimsApi::V2::ApplicationController
def index
poa_requests = ClaimsApi::PowerOfAttorneyRequestService::Search.perform
render json: Blueprints::PowerOfAttorneyRequestBlueprint.render(poa_requests, root: :data)
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# frozen_string_literal: true

module ClaimsApi
module PowerOfAttorneyRequestService
# Notice we're not bothering to memoize many of the instance methods which
# are very small calculations.
#
# TODO: Document philosophy around validity of source data?
class PoaRequest
module Statuses
ALL = [
NEW = 'New',
PENDING = 'Pending',
ACCEPTED = 'Accepted',
DECLINED = 'Declined'
].freeze
end

Veteran =
Data.define(
:first_name,
:middle_name,
:last_name,
:participant_id
)

Representative =
Data.define(
:first_name,
:last_name,
:email
)

Claimant =
Data.define(
:first_name,
:last_name,
:participant_id,
:relationship_to_veteran
)

Address =
Data.define(
:city, :state, :zip, :country,
:military_post_office,
:military_postal_code
)

def initialize(data)
@data = data
end

def id
@data['procID'].to_i
end

def status
@data['secondaryStatus'].presence_in(Statuses::ALL)
end

def submitted_at
Utilities.time(@data['dateRequestReceived'])
end

def accepted_or_declined_at
Utilities.time(@data['dateRequestActioned'])
end

def declined_reason
if status == Statuses::DECLINED # rubocop:disable Style/IfUnlessModifier
@data['declinedReason']
end
end

def authorizes_address_changing?
Utilities.boolean(@data['changeAddressAuth'])
end

def authorizes_treatment_disclosure?
Utilities.boolean(@data['healthInfoAuth'])
end

def power_of_attorney_code
@data['poaCode']
end

def veteran
@veteran ||=
Veteran.new(
first_name: @data['vetFirstName'],
middle_name: @data['vetMiddleName'],
last_name: @data['vetLastName'],
# TODO: Gotta figure out if this is always present or not.
participant_id: @data['vetPtcpntID']&.to_i
)
end

def representative
@representative ||=
Representative.new(
first_name: @data['VSOUserFirstName'],
last_name: @data['VSOUserLastName'],
email: @data['VSOUserEmail']
)
end

def claimant
@claimant ||= begin
# TODO: Check on `claimantRelationship` values in BGS.
relationship = @data['claimantRelationship']
if relationship.present? && relationship != 'Self'
Claimant.new(
first_name: @data['claimantFirstName'],
last_name: @data['claimantLastName'],
participant_id: @data['claimantPtcpntID'].to_i,
relationship_to_veteran: relationship
)
end
end
end

def claimant_address
@claimant_address ||=
Address.new(
city: @data['claimantCity'],
state: @data['claimantState'],
zip: @data['claimantZip'],
country: @data['claimantCountry'],
military_post_office: @data['claimantMilitaryPO'],
military_postal_code: @data['claimantMilitaryPostalCode']
)
end

module Utilities
class << self
def time(value)
ActiveSupport::TimeZone['UTC'].parse(value.to_s)
end

def boolean(value)
case value
when 'Y'
true
when 'N'
false
else # rubocop:disable Style/EmptyElse
# Just to be explicit.
nil
end
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# frozen_string_literal: true

module ClaimsApi
module PowerOfAttorneyRequestService
module Search
class << self
def perform
# `Array.wrap` (the `ActiveSupport` core extension with nicer behavior
# than Ruby core) because upstream invocation of `Hash.from_xml` has
# different output depending on the cardinality of sibling XML
# elements for a given kind:
# 0 => Absent
# 1 => Object
# >1 => Array
poa_requests = make_request['poaRequestRespondReturnVOList']
Array.wrap(poa_requests).map { |data| PoaRequest.new(data) }
end

private

def make_request
bgs_client =
ClaimsApi::ManageRepresentativeService.new(
external_uid: 'xUid',
external_key: 'xKey'
)

bgs_client.read_poa_request(
poa_codes: ['012'],
statuses: %w[
new
pending
accepted
declined
]
)
end
end
end
end
end
Loading

0 comments on commit 056ccee

Please sign in to comment.