diff --git a/app/jobs/resolution_proofing_job.rb b/app/jobs/resolution_proofing_job.rb index 32bd50c5cea..df2677bbbc4 100644 --- a/app/jobs/resolution_proofing_job.rb +++ b/app/jobs/resolution_proofing_job.rb @@ -138,7 +138,7 @@ def proof_lexisnexis_then_aamva(timer:, applicant_pii:, should_proof_state_id:) state_id_result = Proofing::StateIdResult.new( success: true, errors: {}, exception: nil, vendor_name: 'UnsupportedJurisdiction', ) - if should_proof_state_id + if should_proof_state_id && user_can_pass_after_state_id_check?(resolution_result) timer.time('state_id') do state_id_result = state_id_proofer.proof(applicant_pii) end @@ -157,6 +157,20 @@ def proof_lexisnexis_then_aamva(timer:, applicant_pii:, should_proof_state_id:) ) end + def user_can_pass_after_state_id_check?(resolution_result) + return true if resolution_result.success? + # For failed IV results, this method validates that the user is eligible to pass if the + # failed attributes are covered by the same attributes in a successful AAMVA response + # aka the Get-to-Yes w/ AAMVA feature. + return false unless resolution_result.failed_result_can_pass_with_additional_verification? + + attributes_aamva_can_pass = [:address, :dob, :state_id_number] + results_that_cannot_pass_aamva = + resolution_result.attributes_requiring_additional_verification - attributes_aamva_can_pass + + results_that_cannot_pass_aamva.blank? + end + def resolution_proofer @resolution_proofer ||= if IdentityConfig.store.proofer_mock_fallback diff --git a/spec/jobs/resolution_proofing_job_spec.rb b/spec/jobs/resolution_proofing_job_spec.rb index 8b5c756e0c2..586c2ae2ccc 100644 --- a/spec/jobs/resolution_proofing_job_spec.rb +++ b/spec/jobs/resolution_proofing_job_spec.rb @@ -143,6 +143,81 @@ end end + context 'with a InstantVerify result with failed attributes covered by the AAMVA result' do + it 'stores a successful result' do + stub_vendor_requests( + instant_verify_response: LexisNexisFixtures.instant_verify_address_fail_response_json, + aamva_response: AamvaFixtures.verification_response, + ) + + perform + + result = document_capture_session.load_proofing_result[:result] + result_context = result[:context] + result_context_stages = result_context[:stages] + result_context_stages_resolution = result_context_stages[:resolution] + result_context_stages_state_id = result_context_stages[:state_id] + + expect(result[:success]).to be true + expect(result[:errors].keys).to eq([:base, :InstantVerify]) + expect(result[:exception]).to be_nil + expect(result[:timed_out]).to be false + + # result[:context][:stages][:resolution] + expect(result_context_stages_resolution[:vendor_name]). + to eq('lexisnexis:instant_verify') + expect(result_context_stages_resolution[:success]).to eq(false) + expect(result_context_stages_resolution[:can_pass_with_additional_verification]). + to eq(true) + expect(result_context_stages_resolution[:attributes_requiring_additional_verification]). + to eq(['address']) + + # result[:context][:stages][:state_id] + expect(result_context_stages_state_id[:vendor_name]).to eq('aamva:state_id') + expect(result_context_stages_state_id[:success]).to eq(true) + expect(result_context_stages_state_id[:verified_attributes]).to eq( + %w[address state_id_number state_id_type dob last_name first_name], + ) + end + end + + context 'with a InstantVerify result with failed attributes that cannot be covered by AAMVA' do + it 'stores an unsuccessful result and does not make an AAMVA request' do + stub_vendor_requests( + instant_verify_response: + LexisNexisFixtures.instant_verify_identity_not_found_response_json, + ) + + perform + + result = document_capture_session.load_proofing_result[:result] + result_context = result[:context] + result_context_stages = result_context[:stages] + result_context_stages_resolution = result_context_stages[:resolution] + result_context_stages_state_id = result_context_stages[:state_id] + + expect(result[:success]).to be false + expect(result[:errors].keys).to eq([:base, :InstantVerify]) + expect(result[:exception]).to be_nil + expect(result[:timed_out]).to be false + + # result[:context][:stages][:resolution] + expect(result_context_stages_resolution[:vendor_name]). + to eq('lexisnexis:instant_verify') + expect(result_context_stages_resolution[:success]).to eq(false) + expect(result_context_stages_resolution[:can_pass_with_additional_verification]). + to eq(true) + expect(result_context_stages_resolution[:attributes_requiring_additional_verification]). + to match(['address', 'dead', 'dob', 'ssn']) + + # result[:context][:stages][:state_id] + expect(result_context_stages_state_id[:vendor_name]).to eq('UnsupportedJurisdiction') + expect(result_context_stages_state_id[:success]).to eq(true) + + expect(@aamva_stub).to_not have_been_requested + end + end + context 'with a failed AAMVA result' do it 'stores an unsuccessful result' do stub_vendor_requests(aamva_response: AamvaFixtures.verification_response_namespaced_failure) diff --git a/spec/services/idv/agent_spec.rb b/spec/services/idv/agent_spec.rb index 26235999684..72baae98c94 100644 --- a/spec/services/idv/agent_spec.rb +++ b/spec/services/idv/agent_spec.rb @@ -32,7 +32,7 @@ let(:document_capture_session) { DocumentCaptureSession.new(result_id: SecureRandom.hex) } context 'proofing state_id enabled' do - it 'still proofs state_id if resolution fails' do + it 'does not proof state_id if resolution fails' do agent = Idv::Agent.new( Idp::Constants::MOCK_IDV_APPLICANT.merge(uuid: user.uuid, ssn: '444-55-6666'), ) @@ -47,7 +47,7 @@ result = document_capture_session.load_proofing_result.result expect(result[:errors][:ssn]).to eq ['Unverified SSN.'] - expect(result[:context][:stages][:state_id][:vendor_name]).to eq 'StateIdMock' + expect(result[:context][:stages][:state_id][:vendor_name]).to eq 'UnsupportedJurisdiction' end it 'does proof state_id if resolution succeeds' do