diff --git a/app/models/user.rb b/app/models/user.rb index 0721acc7bc3..0da6ccc47e2 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -235,6 +235,11 @@ def has_in_person_enrollment? pending_in_person_enrollment.present? || establishing_in_person_enrollment.present? end + # @return [Boolean] Whether the user has an establishing in person enrollment. + def has_establishing_in_person_enrollment? + establishing_in_person_enrollment.present? + end + # Trust `pending_profile` rather than enrollment associations def has_establishing_in_person_enrollment_safe? !!pending_profile&.in_person_enrollment&.establishing? diff --git a/app/services/idv/session.rb b/app/services/idv/session.rb index a59e83c6d44..ef69a96c023 100644 --- a/app/services/idv/session.rb +++ b/app/services/idv/session.rb @@ -63,6 +63,15 @@ def respond_to_missing?(method_sym, include_private) end def create_profile_from_applicant_with_password(user_password, is_enhanced_ipp) + if user_has_unscheduled_in_person_enrollment? + UspsInPersonProofing::EnrollmentHelper.schedule_in_person_enrollment( + user: current_user, + pii: Pii::Attributes.new_from_hash(applicant), + is_enhanced_ipp: is_enhanced_ipp, + opt_in: opt_in_param, + ) + end + profile_maker = build_profile_maker(user_password) profile = profile_maker.save_profile( fraud_pending_reason: threatmetrix_fraud_pending_reason, @@ -85,13 +94,6 @@ def create_profile_from_applicant_with_password(user_password, is_enhanced_ipp) if profile.gpo_verification_pending? create_gpo_entry(profile_maker.pii_attributes, profile) - elsif profile.in_person_verification_pending? - UspsInPersonProofing::EnrollmentHelper.schedule_in_person_enrollment( - user: current_user, - pii: profile_maker.pii_attributes, - is_enhanced_ipp: is_enhanced_ipp, - opt_in: opt_in_param, - ) end end @@ -323,5 +325,9 @@ def threatmetrix_fraud_pending_reason 'threatmetrix_review' end end + + def user_has_unscheduled_in_person_enrollment? + current_user.has_establishing_in_person_enrollment? + end end end diff --git a/spec/features/idv/in_person_spec.rb b/spec/features/idv/in_person_spec.rb index 179f5006178..b9e298a8016 100644 --- a/spec/features/idv/in_person_spec.rb +++ b/spec/features/idv/in_person_spec.rb @@ -5,6 +5,7 @@ include IdvStepHelper include SpAuthHelper include InPersonHelper + include UspsIppHelper before do allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) @@ -494,4 +495,30 @@ expect(page).to have_current_path(idv_in_person_ready_to_verify_path) end end + + context 'when the USPS enrollment fails during enter password' do + before do + user = user_with_2fa + sign_in_and_2fa_user(user) + begin_in_person_proofing(user) + complete_prepare_step(user) + complete_location_step + # Causes the schedule USPS enrollment request to throw a bad request error + complete_state_id_step(user, first_name: 'usps client error') + complete_ssn_step(user) + complete_verify_step(user) + fill_out_phone_form_ok(MfaContext.new(user).phone_configurations.first.phone) + click_idv_send_security_code + fill_in_code_with_last_phone_otp + click_submit_default + complete_enter_password_step(user) + end + + it 'then an error displayed on the enter password page', allow_browser_log: true do + expect_in_person_step_indicator_current_step(t('step_indicator.flows.idv.re_enter_password')) + expect(page).to have_content( + 'There was an internal error processing your request. Please try again.', + ) + end + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 049f8691016..17e4ea85785 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -394,6 +394,24 @@ end end + describe '#has_establishing_in_person_enrollment?' do + context 'when the user has an establishing in person enrollment' do + before do + create(:in_person_enrollment, :establishing, user: subject) + end + + it 'returns true' do + expect(subject.has_establishing_in_person_enrollment?).to be(true) + end + end + + context 'when the user does not have an establishing in person enrollment' do + it 'returns false' do + expect(subject.has_establishing_in_person_enrollment?).to be(false) + end + end + end + describe 'deleting identities' do it 'does not delete identities when the user is destroyed preventing uuid reuse' do user = create(:user, :fully_registered) diff --git a/spec/services/idv/session_spec.rb b/spec/services/idv/session_spec.rb index b02a08fba08..e7009ef5352 100644 --- a/spec/services/idv/session_spec.rb +++ b/spec/services/idv/session_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -RSpec.describe Idv::Session, allowed_extra_analytics: [:*] do +RSpec.describe Idv::Session do let(:user) { create(:user) } let(:user_session) { {} } let(:is_enhanced_ipp) { false } @@ -129,7 +129,7 @@ describe '#create_profile_from_applicant_with_password' do let(:opt_in_param) { nil } - let(:is_enhanced_ipp) { false } + before do subject.applicant = Idp::Constants::MOCK_IDV_APPLICANT_WITH_SSN end @@ -181,10 +181,11 @@ expect(pii_from_session.ssn).to eq(Idp::Constants::MOCK_IDV_APPLICANT_WITH_SSN[:ssn]) end - context 'with establishing in person enrollment' do + context 'when the user has an establishing in person enrollment' do let!(:enrollment) do create(:in_person_enrollment, :establishing, user: user, profile: nil) end + let(:profile) { subject.profile } before do ProofingComponent.create(user: user, document_check: Idp::Constants::Vendors::USPS) @@ -193,41 +194,98 @@ subject.applicant = Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE.with_indifferent_access end - it 'sets profile to pending in person verification' do - subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) - profile = subject.profile + context 'when the USPS enrollment is successful' do + before do + allow(UspsInPersonProofing::EnrollmentHelper).to receive(:schedule_in_person_enrollment) + end + + it 'creates an USPS enrollment' do + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) + expect(UspsInPersonProofing::EnrollmentHelper).to have_received( + :schedule_in_person_enrollment, + ).with( + user: user, + pii: Pii::Attributes.new_from_hash(subject.applicant), + is_enhanced_ipp: is_enhanced_ipp, + opt_in: opt_in_param, + ) + end + + it 'creates a profile with in person verification pending' do + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) + expect(profile).to have_attributes( + { + activated_at: nil, + active: false, + in_person_verification_pending?: true, + fraud_review_pending?: false, + gpo_verification_pending_at: nil, + initiating_service_provider: nil, + verified_at: nil, + }, + ) + end + + it 'saves the pii to the session' do + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) + expect(Pii::Cacher.new(user, user_session).fetch(profile.id)).to_not be_nil + end + + it 'associates the in person enrollment with the created profile' do + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) + expect(enrollment.reload.profile_id).to eq(profile.id) + end + end - expect(profile.activated_at).to eq nil - expect(profile.active).to eq false - expect(profile.in_person_verification_pending?).to eq(true) - expect(profile.fraud_review_pending?).to eq(false) - expect(profile.gpo_verification_pending_at.present?).to eq false - expect(profile.initiating_service_provider).to eq nil - expect(profile.verified_at).to eq nil + context 'when the USPS enrollment throws an enroll exception' do + before do + allow(UspsInPersonProofing::EnrollmentHelper).to receive( + :schedule_in_person_enrollment, + ).and_throw('Enrollment Failure') + end + + it 'does not create a profile' do + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) + rescue + expect(profile).to be_nil + end + end + end - pii_from_session = Pii::Cacher.new(user, user_session).fetch(profile.id) - expect(pii_from_session).to_not be_nil - expect(pii_from_session.ssn).to eq(Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE[:ssn]) + context 'when the user does not have an establishing in person enrollment' do + let(:profile) { subject.profile } + + before do + allow(UspsInPersonProofing::EnrollmentHelper).to receive(:schedule_in_person_enrollment) + ProofingComponent.create(user: user, document_check: Idp::Constants::Vendors::USPS) + allow(IdentityConfig.store).to receive(:in_person_proofing_enabled).and_return(true) + subject.user_phone_confirmation = true + subject.applicant = Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE.with_indifferent_access end - it 'creates a USPS enrollment' do - expect(UspsInPersonProofing::EnrollmentHelper). - to receive(:schedule_in_person_enrollment). - with(user: user, pii: Pii::Attributes.new_from_hash(subject.applicant), - is_enhanced_ipp: is_enhanced_ipp, - opt_in: opt_in_param) + it 'does not create an USPS enrollment' do + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) + expect(UspsInPersonProofing::EnrollmentHelper).to_not have_received( + :schedule_in_person_enrollment, + ) + end + it 'creates a profile' do subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) + expect(profile).to have_attributes( + { + active: true, + in_person_verification_pending?: false, + fraud_review_pending?: false, + gpo_verification_pending_at: nil, + initiating_service_provider: nil, + }, + ) + end - profile = enrollment.reload.profile - expect(profile).to eq(user.profiles.last) - expect(profile.activated_at).to eq nil - expect(profile.active).to eq false - expect(profile.in_person_verification_pending?).to eq(true) - expect(profile.fraud_review_pending?).to eq(false) - expect(profile.gpo_verification_pending_at.present?).to eq false - expect(profile.initiating_service_provider).to eq nil - expect(profile.verified_at).to eq nil + it 'saves the pii to the session' do + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) + expect(Pii::Cacher.new(user, user_session).fetch(profile.id)).to_not be_nil end end end diff --git a/spec/support/features/in_person_helper.rb b/spec/support/features/in_person_helper.rb index ff0ab2b51a2..2f130c4a14b 100644 --- a/spec/support/features/in_person_helper.rb +++ b/spec/support/features/in_person_helper.rb @@ -32,8 +32,8 @@ module InPersonHelper GOOD_IDENTITY_DOC_ZIPCODE = (Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:identity_doc_zipcode]).freeze - def fill_out_state_id_form_ok(same_address_as_id: false) - fill_in t('in_person_proofing.form.state_id.first_name'), with: GOOD_FIRST_NAME + def fill_out_state_id_form_ok(same_address_as_id: false, first_name: GOOD_FIRST_NAME) + fill_in t('in_person_proofing.form.state_id.first_name'), with: first_name fill_in t('in_person_proofing.form.state_id.last_name'), with: GOOD_LAST_NAME year, month, day = GOOD_DOB.split('-') fill_in t('components.memorable_date.month'), with: month @@ -120,10 +120,10 @@ def complete_prepare_step(_user = nil) click_on t('forms.buttons.continue') end - def complete_state_id_step(_user = nil, same_address_as_id: true) + def complete_state_id_step(_user = nil, same_address_as_id: true, first_name: GOOD_FIRST_NAME) # Wait for page to load before attempting to fill out form expect(page).to have_current_path(idv_in_person_step_path(step: :state_id), wait: 10) - fill_out_state_id_form_ok(same_address_as_id: same_address_as_id) + fill_out_state_id_form_ok(same_address_as_id: same_address_as_id, first_name:) click_idv_continue unless same_address_as_id expect(page).to have_current_path(idv_in_person_address_path, wait: 10)