Skip to content

Commit

Permalink
Merge branch 'master' into ndbex-70721-map-form-fields
Browse files Browse the repository at this point in the history
  • Loading branch information
evansmith authored Mar 25, 2024
2 parents c7b0e9e + 3a83f6c commit 0e89d34
Show file tree
Hide file tree
Showing 15 changed files with 275 additions and 30 deletions.
73 changes: 73 additions & 0 deletions app/controllers/v1/pension_ipf_callbacks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# frozen_string_literal: true

require 'decision_review_v1/utilities/logging_utils'

module V1
class PensionIpfCallbacksController < ApplicationController
include ActionController::HttpAuthentication::Token::ControllerMethods
include DecisionReviewV1::Appeals::LoggingUtils

service_tag 'pension-ipf-callbacks'

skip_before_action :verify_authenticity_token, only: [:create]
skip_before_action :authenticate, only: [:create]
skip_after_action :set_csrf_header, only: [:create]
before_action :authenticate_header, only: [:create]

STATUSES_TO_IGNORE = %w[sent delivered temporary-failure].freeze

def create
return render json: nil, status: :not_found unless Flipper.enabled? :pension_ipf_callbacks_endpoint

payload = JSON.parse(request.body.string)

# save encrypted request body in database table for non-successful notifications
payload_status = payload['status']&.downcase
if STATUSES_TO_IGNORE.exclude? payload_status
begin
PensionIpfNotification.create!(payload:)
rescue ActiveRecord::RecordInvalid => e
log_formatted(**log_params(payload).merge(is_success: false), params: { exception_message: e.message })
return render json: { message: 'failed' }
end
end

log_formatted(**log_params(payload).merge(is_success: true))
render json: { message: 'success' }
end

private

def authenticate_header
authenticate_user_with_token || authenticity_error
end

def authenticate_user_with_token
Rails.logger.info('pension-ipf-callbacks-69766 - Received request, authenticating')
authenticate_with_http_token do |token|
return false if bearer_token_secret.nil?

token == bearer_token_secret
end
end

def authenticity_error
Rails.logger.info('pension-ipf-callbacks-69766 - Failed to authenticate request')
render json: { message: 'Invalid credentials' }, status: :unauthorized
end

def bearer_token_secret
Settings.dig(:pension_ipf_vanotify_status_callback, :bearer_token)
end

def log_params(payload)
{
key: :callbacks,
form_id: '21P-527EZ',
user_uuid: nil,
upstream_system: 'VANotify',
body: payload.merge('to' => '<FILTERED>') # scrub PII from logs
}
end
end
end
20 changes: 20 additions & 0 deletions app/models/pension_ipf_notification.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

require 'json_marshal/marshaller'

class PensionIpfNotification < ApplicationRecord
serialize :payload, JsonMarshal::Marshaller

has_kms_key
has_encrypted :payload, key: :kms_key, **lockbox_options

validates(:payload, presence: true)

before_save :serialize_payload

private

def serialize_payload
self.payload = payload.to_json unless payload.is_a?(String)
end
end
4 changes: 4 additions & 0 deletions config/features.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,10 @@ features:
actor_type: user
description: NOD VANotify notification callbacks endpoint
enable_in_development: true
pension_ipf_callbacks_endpoint:
actor_type: user
description: Pension IPF VANotify notification callbacks endpoint
enable_in_development: true
hlr_browser_monitoring_enabled:
actor_type: user
description: HLR Datadog RUM monitoring
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@

scope format: false do
resources :nod_callbacks, only: [:create]
resources :pension_ipf_callbacks, only: [:create]
end
end

Expand Down
3 changes: 3 additions & 0 deletions config/settings/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -428,3 +428,6 @@ travel_pay:
subscription_key: 'api_key'
base_url: 'https://btsss.gov'
service_name: 'BTSSS-API'

pension_ipf_vanotify_status_callback:
bearer_token: bearer_token_secret
Binary file modified lib/pdf_fill/forms/pdfs/21P-527EZ.pdf
Binary file not shown.
12 changes: 6 additions & 6 deletions lib/pdf_fill/forms/va21p527ez.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1343,7 +1343,7 @@ def expand_veteran_service_information
@form_data['serviceBranch'] = @form_data['serviceBranch']&.select { |_, value| value == true }

@form_data['pow'] = to_radio_yes_no(@form_data['powDateRange'].present?)
if @form_data['pow'].zero?
if @form_data['pow'] == 1
@form_data['powDateRange'] ||= {}
@form_data['powDateRange']['from'] = split_date(@form_data.dig('powDateRange', 'from'))
@form_data['powDateRange']['to'] = split_date(@form_data.dig('powDateRange', 'to'))
Expand Down Expand Up @@ -1372,10 +1372,10 @@ def expand_pension_information
)

# If "YES," skip question 4B
@form_data['medicalCondition'] = 'Off' if @form_data['socialSecurityDisability'].zero?
@form_data['medicalCondition'] = 'Off' if @form_data['socialSecurityDisability'] == 1

# If "NO," skip question 4D
@form_data['medicaidStatus'] = 'Off' if @form_data['nursingHome'] == 1
@form_data['medicaidStatus'] = 'Off' if @form_data['nursingHome'] == 2

@form_data['vaTreatmentHistory'] = to_radio_yes_no(@form_data['vaTreatmentHistory'])
@form_data['federalTreatmentHistory'] = to_radio_yes_no(@form_data['federalTreatmentHistory'])
Expand All @@ -1392,7 +1392,7 @@ def expand_employment_history
})
end

@form_data['currentEmployers'] = nil if @form_data['currentEmployment'] == 1
@form_data['currentEmployers'] = nil if @form_data['currentEmployment'] == 2
end

# SECTION VI: MARITAL STATUS
Expand Down Expand Up @@ -1575,7 +1575,7 @@ def expand_income_and_assets
end
@form_data['transferredAssets'] = to_radio_yes_no(@form_data['transferredAssets'])
@form_data['homeOwnership'] = to_radio_yes_no(@form_data['homeOwnership'])
if (@form_data['homeOwnership']).zero?
if (@form_data['homeOwnership']) == 1
@form_data['homeAcreageMoreThanTwo'] = to_radio_yes_no(@form_data['homeAcreageMoreThanTwo'])
@form_data['landMarketable'] = to_radio_yes_no(@form_data['landMarketable'])
end
Expand Down Expand Up @@ -1711,7 +1711,7 @@ def to_checkbox_on_off(obj)
end

def to_radio_yes_no(obj)
obj ? 0 : 1
obj ? 1 : 2
end
end
end
Expand Down
90 changes: 90 additions & 0 deletions spec/controllers/v1/pension_ipf_callbacks_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe V1::PensionIpfCallbacksController, type: :controller do
let(:status) { 'delivered' }
let(:params) do
{
id: '6ba01111-f3ee-4a40-9d04-234asdfb6abab9c',
reference: nil,
to: '[email protected]',
status:,
created_at: '2023-01-10T00:04:25.273410Z',
completed_at: '2023-01-10T00:05:33.255911Z',
sent_at: '2023-01-10T00:04:25.775363Z',
notification_type: 'email',
status_reason: '',
provider: 'sendgrid'
}
end

describe '#create' do
before do
request.headers['Authorization'] = "Bearer #{Settings.pension_ipf_vanotify_status_callback.bearer_token}"
Flipper.enable(:pension_ipf_callbacks_endpoint)
allow(PensionIpfNotification).to receive(:create!)
end

context 'with payload' do
context 'if status is delivered' do
it 'returns success and does not save a record of the payload' do
post(:create, params:, as: :json)

expect(PensionIpfNotification).not_to receive(:create!)

expect(response).to have_http_status(:ok)

res = JSON.parse(response.body)
expect(res['message']).to eq 'success'
end
end

context 'if status is a failure that will not retry' do
let(:status) { 'permanent-failure' }

it 'returns success' do
post(:create, params:, as: :json)

expect(response).to have_http_status(:ok)

res = JSON.parse(response.body)
expect(res['message']).to eq 'success'
end

context 'and the record failed to save' do
before do
allow(PensionIpfNotification).to receive(:create!).and_raise(ActiveRecord::RecordInvalid)
end

it 'returns failed' do
post(:create, params:, as: :json)

expect(response).to have_http_status(:ok)

res = JSON.parse(response.body)
expect(res['message']).to eq 'failed'
end
end
end
end
end

describe 'authentication' do
context 'with missing Authorization header' do
it 'returns 401' do
request.headers['Authorization'] = nil
post(:create, params:, as: :json)
expect(response).to have_http_status(:unauthorized)
end
end

context 'with invalid Authorization header' do
it 'returns 401' do
request.headers['Authorization'] = 'Bearer foo'
post(:create, params:, as: :json)
expect(response).to have_http_status(:unauthorized)
end
end
end
end
20 changes: 20 additions & 0 deletions spec/factories/pension_ipf_notifications.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

FactoryBot.define do
factory :pension_ipf_notification do
payload do
{
id: '6ba01111-f3ee-4a40-9d04-234asdfb6abab9c',
reference: nil,
to: '[email protected]',
status: 'delivered',
created_at: '2023-01-10T00:04:25.273410Z',
completed_at: '2023-01-10T00:05:33.255911Z',
sent_at: '2023-01-10T00:04:25.775363Z',
notification_type: 'email',
status_reason: '',
provider: 'pinpoint'
}
end
end
end
Binary file modified spec/fixtures/pdf_fill/21P-527EZ/kitchen_sink.pdf
Binary file not shown.
42 changes: 21 additions & 21 deletions spec/fixtures/pdf_fill/21P-527EZ/merge_fields.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"second": "22",
"third": "4444"
},
"vaClaimsHistory": 0,
"vaClaimsHistory": 1,
"vaFileNumber": "12345678",
"veteranDateOfBirth": {
"month": "01",
Expand Down Expand Up @@ -55,25 +55,25 @@
"year": "1973"
}
},
"socialSecurityDisability": 1,
"medicalCondition": 1,
"nursingHome": 0,
"socialSecurityDisability": 2,
"medicalCondition": 2,
"nursingHome": 1,
"medicaidCoverage": false,
"medicaidStatus": 0,
"specialMonthlyPension": 1,
"vaTreatmentHistory": 0,
"medicaidStatus": 1,
"specialMonthlyPension": 2,
"vaTreatmentHistory": 1,
"vaMedicalCenters": [
{
"medicalCenter": "Dallas VA Medical Center"
}
],
"federalTreatmentHistory": 0,
"federalTreatmentHistory": 1,
"federalMedicalCenters": [
{
"medicalCenter": "Memphis Health Care"
}
],
"currentEmployment": 0,
"currentEmployment": 1,
"currentEmployers": [
{
"jobType": "Customer service",
Expand Down Expand Up @@ -141,7 +141,7 @@
"second": "22",
"third": "4444"
},
"spouseIsVeteran": 0,
"spouseIsVeteran": 1,
"spouseVaFileNumber": "23423444",
"spouseAddress": {
"street": "123 7th st",
Expand Down Expand Up @@ -345,7 +345,7 @@
"monthlyPaymentOverflow": "$2,300.00"
}
],
"totalNetWorth": 1,
"totalNetWorth": 2,
"netWorthEstimation": {
"part_cents": "00",
"part_two": "1",
Expand Down Expand Up @@ -579,15 +579,15 @@
"paymentAmountOverflow": "$100.00"
}
],
"transferredAssets": 0,
"homeOwnership": 0,
"homeAcreageMoreThanTwo": 0,
"transferredAssets": 1,
"homeOwnership": 1,
"homeAcreageMoreThanTwo": 1,
"homeAcreageValue": {
"part_cents": "00",
"part_two": "75",
"part_one": "000"
},
"landMarketable": 0,
"landMarketable": 1,
"receivesIncome": true,
"incomeSources": [
{
Expand Down Expand Up @@ -673,7 +673,7 @@
"noRapidProcessing": 1,
"statementOfTruthCertified": true,
"statementOfTruthSignature": "John Edmund Doe",
"pow": 0,
"pow": 1,
"placeOfSeparationLineOne": "West Brookfield, M",
"placeOfSeparationLineTwo": "A",
"previousEmployers": null,
Expand All @@ -692,10 +692,10 @@
"marriageType": 1,
"otherExplanation": "Other reason"
},
"additionalMarriages": 1,
"additionalSpouseMarriages": 1,
"additionalMarriages": 2,
"additionalSpouseMarriages": 2,
"dependentChildrenInHousehold": "2",
"dependentsNotWithYouAtSameAddress": 0,
"dependentsNotWithYouAtSameAddress": 1,
"custodians": [
{
"first": "Joe",
Expand All @@ -715,8 +715,8 @@
"dependentsWithCustodianOverflow": "Emily Anne Doe"
}
],
"moreThanFourIncomeSources": 1,
"hasAnyExpenses": 0,
"moreThanFourIncomeSources": 2,
"hasAnyExpenses": 1,
"signatureDate": {
"month": "12",
"day": "31",
Expand Down
Binary file modified spec/fixtures/pdf_fill/21P-527EZ/overflow.pdf
Binary file not shown.
Binary file modified spec/fixtures/pdf_fill/21P-527EZ/simple.pdf
Binary file not shown.
Loading

0 comments on commit 0e89d34

Please sign in to comment.