Skip to content

Commit

Permalink
adding verification history to pvc failure case (#3728)
Browse files Browse the repository at this point in the history
* adding verification history to pvc failure case

* create spec for non_esi mec error handling

* remove redundant method

* add logger files to pvc request flow (#3740)

* add additional error logging to pvc request process

* remove unnecessary test and unmerge changes from trunk

* publish pvc if at least one applicant has a valid non_esi evidence

* remove unnecessary check for github actions

* adds missing env var to test

* remove redundant logging on failure for non_esi_evidence

* change error message to expected in create_pvc_request spec

---------

Co-authored-by: TristanB17 <[email protected]>
Co-authored-by: Tristan <[email protected]>
  • Loading branch information
3 people authored and jacobkagon committed May 29, 2024
1 parent fc6d11d commit 4b8a706
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ def call(params)
values = yield validate(params)
application = yield fetch_application(values)
_evidences = yield create_non_esi_evidences(application)
cv3_application = yield transform_application(application)
cv3_application = yield transform_and_validate_application(application)
event = yield build_event(cv3_application)
publish(event)
create_evidence_history(application)

Success("Successfully published the pvc payload for family with hbx_id #{params[:family_hbx_id]}")
end
Expand All @@ -35,16 +34,16 @@ def validate(params)
errors << 'application hbx_id is missing' unless params[:application_hbx_id]
errors << 'family_hbx_id is missing' unless params[:family_hbx_id]

errors.empty? ? Success(params) : Failure(errors)
errors.empty? ? Success(params) : log_error_and_return_failure(errors)
end

def fetch_application(params)
application = ::FinancialAssistance::Application.by_hbx_id(params[:application_hbx_id]).first
if application.present?
Success(application)
else
pvc_logger.error("No applicationfound with hbx_id #{params[:application_hbx_id]}")
Failure("No applicationfound with hbx_id #{params[:application_hbx_id]}")
pvc_logger.error("No application found with hbx_id #{params[:application_hbx_id]}")
Failure("No application found with hbx_id #{params[:application_hbx_id]}")
end
end

Expand All @@ -54,39 +53,109 @@ def create_non_esi_evidences(application)

applicant.create_evidence(:non_esi_mec, "Non ESI MEC")
end
create_evidence_history(application, 'PVC_Submitted', 'PVC - Renewal verifications submitted', 'system')

Success(true)
rescue StandardError => e
pvc_logger.error("Failed to create non_esi_evidences for application with hbx_id #{application.hbx_id} due to #{e.inspect}")
Failure("Failed to create non_esi_evidences for application with hbx_id #{application.hbx_id}")
end

def transform_application(application)
payload = ::FinancialAssistance::Operations::Applications::Transformers::ApplicationTo::Cv3Application.new.call(application)
AcaEntities::MagiMedicaid::Operations::InitializeApplication.new.call(payload.value!)
def transform_and_validate_application(application)
payload_entity = ::Operations::Fdsh::BuildAndValidateApplicationPayload.new.call(application)

if EnrollRegistry.feature_enabled?(:validate_and_record_publish_application_errors) && payload_entity.failure?
record_application_failure(application, payload_entity.failure.messages)
return log_error_and_return_failure(payload_entity.failure.messages)
end

if EnrollRegistry.feature_enabled?(:validate_and_record_publish_application_errors) && payload_entity.success?
valid_applicants = validate_applicants(payload_entity, application)
return complete_create_pvc_request(valid_applicants, application, payload_entity)
end

payload_entity
rescue StandardError => e
pvc_logger.error("Failed to transform application with hbx_id #{application.hbx_id} due to #{e.inspect}")
record_application_failure(application, "transformation failure") if EnrollRegistry.feature_enabled?(:validate_and_record_publish_application_errors)
Failure("Failed to transform application with hbx_id #{application.hbx_id}")
end

def build_event(cv3_application)
event('events.fdsh.evidences.periodic_verification_confirmation', attributes: { application: cv3_application.to_h })
def validate_applicants(payload_entity, application)
applicants_entity = payload_entity.value!.applicants
results_array = []

application.active_applicants.map do |eligible_applicant|
applicant_entity = applicants_entity.detect { |appl_entity| eligible_applicant.person_hbx_id == appl_entity.person_hbx_id }
result = ::Operations::Fdsh::PayloadEligibility::CheckApplicantEligibilityRules.new.call(applicant_entity, :non_esi_mec)

if result.success?
results_array << true
else
record_applicant_failure(eligible_applicant.non_esi_evidence, result.failure)
results_array << false
end
end

results_array
end

def publish(event)
event.publish
Success("Successfully published the pvc payload")
def complete_create_pvc_request(valid_applicants, application, payload_entity)
if valid_applicants.any?(true)
payload_entity
else
error_message = "Failed to transform application with hbx_id #{application.hbx_id} due to all applicants being invalid"
log_error_and_return_failure(error_message)
end
end

def create_evidence_history(application)
def record_application_failure(application, error_messages)
application.active_applicants.each do |applicant|
evidence = applicant.non_esi_evidence
evidence&.add_verification_history('PVC_Submitted', 'PVC - Renewal verifications submitted', 'system')
next unless evidence.present?

record_applicant_failure(evidence, error_messages)
end
end

application.save
def record_applicant_failure(evidence, error_messages)
add_verification_history(evidence, 'PVC_Submission_Failed', "PVC - Periodic verifications submission failed due to #{error_messages}", 'system')
update_evidence_to_default_state(evidence)
end

def add_verification_history(evidence, action, update_reason, update_by)
evidence.add_verification_history(action, update_reason, update_by) if evidence.present?
end

def create_evidence_history(application, action, update_reason, update_by)
application.active_applicants.each do |applicant|
evidence = applicant.non_esi_evidence
next unless evidence.present?
add_verification_history(evidence, action, update_reason, update_by)
end
end

def update_evidence_to_default_state(evidence)
evidence&.determine_mec_evidence_aasm_status
end

def build_event(cv3_application)
event('events.fdsh.evidences.periodic_verification_confirmation', attributes: { application: cv3_application.to_h })
end

def publish(event)
event.publish
Success("Successfully published the pvc payload")
end

def pvc_logger
@pvc_logger ||= Logger.new("#{Rails.root}/log/pvc_non_esi_logger_#{TimeKeeper.date_of_record.strftime('%Y_%m_%d')}.log")
end

def log_error_and_return_failure(error)
pvc_logger.error(error)
Failure(error)
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,29 @@ def call(params)
private

def initialize_application_entity(params)
::AcaEntities::MagiMedicaid::Operations::InitializeApplication.new.call(params)
application_entity = ::AcaEntities::MagiMedicaid::Operations::InitializeApplication.new.call(params)
return log_and_return_failure("Failed to initialize application with hbx_id: #{params[:hbx_id]}") if application_entity.failure?

application_entity
end

def find_application(application_entity)
application = ::FinancialAssistance::Application.by_hbx_id(application_entity.hbx_id).first
application.present? ? Success(application) : Failure({:errors => ["Could not find application with given hbx_id: #{application_entity.hbx_id}"]})
application.present? ? Success(application) : log_and_return_failure("Could not find application with given hbx_id: #{application_entity.hbx_id}")
end

def update_applicant(response_app_entity, application, applicant_identifier)
enrollments = HbxEnrollment.where(:aasm_state.in => HbxEnrollment::ENROLLED_STATUSES, family_id: application.family_id)
response_applicant = response_app_entity.applicants.detect {|applicant| applicant.person_hbx_id == applicant_identifier}
applicant = application.applicants.where(person_hbx_id: applicant_identifier).first

return Failure("applicant not found with #{applicant_identifier} for pvc Medicare") unless applicant
return Failure("applicant not found in response with #{applicant_identifier} for pvc Medicare") unless response_applicant
return log_and_return_failure("applicant not found with #{applicant_identifier} for pvc Medicare") unless applicant
return log_and_return_failure("applicant not found in response with #{applicant_identifier} for pvc Medicare") unless response_applicant

update_applicant_verifications(applicant, response_applicant, enrollments)
Success('Successfully updated Applicant with evidences and verifications')
rescue StandardError => e
log_and_return_failure("Failed to update_applicant with hbx_id #{applicant&.person_hbx_id} due to #{e.inspect}")
end

def update_applicant_verifications(applicant, response_applicant_entity, enrollments)
Expand Down Expand Up @@ -91,6 +96,15 @@ def enrolled?(applicant, enrollments)
family_member_ids = enrollments.flat_map(&:hbx_enrollment_members).flat_map(&:applicant_id).uniq
family_member_ids.map(&:to_s).include?(applicant.family_member_id.to_s)
end

def log_and_return_failure(message)
pvc_logger.error(message)
Failure(message)
end

def pvc_logger
@pvc_logger ||= Logger.new("#{Rails.root}/log/pvc_non_esi_logger_#{TimeKeeper.date_of_record.strftime('%Y_%m_%d')}.log")
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def validate(params)
errors = []
errors << 'assistance_year ref missing' unless params[:assistance_year]
params[:csr_list] = PVC_CSR_LIST if params[:csr_list].blank?
errors.empty? ? Success(params) : Failure(errors)
errors.empty? ? Success(params) : log_error_and_return_failure(errors)
end

def find_families(params)
Expand All @@ -61,9 +61,7 @@ def fetch_application(family, assistance_year)

def submit(params, family_ids)
families = Family.where(:_id.in => family_ids)

count = 0
pvc_logger = Logger.new("#{Rails.root}/log/pvc_non_esi_logger_#{TimeKeeper.date_of_record.strftime('%Y_%m_%d')}.log")

families.no_timeout.each do |family|
determined_application = fetch_application(family, params[:assistance_year])
Expand All @@ -90,6 +88,15 @@ def publish(payload)

Success("Successfully published the pvc payload")
end

def pvc_logger
@pvc_logger ||= Logger.new("#{Rails.root}/log/pvc_non_esi_logger_#{TimeKeeper.date_of_record.strftime('%Y_%m_%d')}.log")
end

def log_error_and_return_failure(error)
pvc_logger.error(error)
Failure(error)
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
is_claimed_as_tax_dependent: false,
is_incarcerated: false,
net_annual_income: 10_078.90,
is_post_partum_period: false)
is_post_partum_period: false,
encrypted_ssn: "wFDFw1whehQ1Udku1/79DA==\n")
applicant
end

Expand Down Expand Up @@ -133,4 +134,48 @@
expect(result).to be_success
expect(applicant.reload.non_esi_evidence.present?).to be_falsey
end

context 'when an application fails to be transformed into an entity' do
before do
# validate_and_record_publish_application_errors needs to be true in order to check applicants' evidences at an individual level
allow(EnrollRegistry).to receive(:feature_enabled?).and_return(false)
allow(EnrollRegistry).to receive(:feature_enabled?).with(:validate_and_record_publish_application_errors).and_return(true)

application.update(aasm_state: :draft)
end

it 'will return a failure' do
result = subject.call(family_hbx_id: family.hbx_assigned_id, application_hbx_id: application.hbx_id, assistance_year: application.assistance_year)
applicant.reload
evidence = applicant.non_esi_evidence

expect(result).to be_failure
expect(evidence.verification_histories.last.update_reason).to eq("PVC - Periodic verifications submission failed due to transformation failure")
expect(evidence.aasm_state).to eq('attested')
end
end

context 'when all applicants are invalid' do
let(:service_object) { double("CheckApplicantEligibilityRules") }

before do
# validate_and_record_publish_application_errors needs to be true in order to check applicants' evidences at an individual level
allow(EnrollRegistry).to receive(:feature_enabled?).and_return(false)
allow(EnrollRegistry).to receive(:feature_enabled?).with(:validate_and_record_publish_application_errors).and_return(true)

allow(::Operations::Fdsh::PayloadEligibility::CheckApplicantEligibilityRules).to receive(:new).and_return(service_object)
allow(service_object).to receive(:call).and_return(Dry::Monads::Result::Failure.new("invalid ssn"))
end

it 'will return a failure' do
result = subject.call(family_hbx_id: family.hbx_assigned_id, application_hbx_id: application.hbx_id, assistance_year: application.assistance_year)
applicant.reload
evidence = applicant.non_esi_evidence
error_message = "PVC - Periodic verifications submission failed due to invalid ssn"

expect(result).to be_failure
expect(evidence.verification_histories.last.update_reason).to eq(error_message)
expect(evidence.aasm_state).to eq('attested')
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,81 @@
end
end
end

context 'failure' do
include_context 'FDSH PVC Medicare sample response'

let(:identifier) { '1629165429385938' }

context 'the application cannot be found' do
before do
application.destroy
end

it 'returns an error' do
result = subject.call({payload: response_payload, applicant_identifier: identifier})

expect(result).to be_failure
expect(result.failure).to eq("Could not find application with given hbx_id: #{response_payload[:hbx_id]}")
end
end

context 'an error occurs when trying to initialize an application entity' do
before do
response_payload[:hbx_id] = nil
end

it 'returns an error' do
result = subject.call({payload: response_payload, applicant_identifier: identifier})

expect(result).to be_failure
expect(result.failure).to eq("Failed to initialize application with hbx_id: ")
end
end

context 'the application applicant cannot be found' do
before do
application.applicants.first.destroy
end

it 'returns an error' do
result = subject.call({payload: response_payload, applicant_identifier: identifier})

expect(result).to be_failure
expect(result.failure).to eq("applicant not found with #{identifier} for pvc Medicare")
end
end

context 'the applicant in the response payload cannot be found' do
before do
response_payload[:applicants].first[:person_hbx_id] = '12345'
end

it 'returns an error' do
result = subject.call({payload: response_payload, applicant_identifier: identifier})

expect(result).to be_failure
expect(result.failure).to eq("applicant not found in response with #{identifier} for pvc Medicare")
end
end

context 'an error occurs when trying to update the applicant' do
let(:non_esi_evidence) do
instance_double("Eligibilities::Evidence", key: :non_esi_evidence, title: "NON ESI MEC", due_on: "error I am not a date")
end

before do
applicant = application.applicants.first
allow(applicant).to receive(:non_esi_evidence).and_return(non_esi_evidence)
allow(::FinancialAssistance::Application).to receive(:by_hbx_id).and_return([application])
end

it 'returns an error' do
result = subject.call({payload: response_payload, applicant_identifier: identifier})

expect(result).to be_failure
expect(result.failure).to include("Failed to update_applicant")
end
end
end
end
Loading

0 comments on commit 4b8a706

Please sign in to comment.