diff --git a/app/assets/stylesheets/email.css.scss b/app/assets/stylesheets/email.css.scss index 38d0dfc7a89..23df51c0b80 100644 --- a/app/assets/stylesheets/email.css.scss +++ b/app/assets/stylesheets/email.css.scss @@ -177,6 +177,10 @@ h6 { @include u-border(1px); } +.border-top-width-0 { + border-top: 0; +} + .border-primary-light { @include u-border('primary-light'); } @@ -221,6 +225,10 @@ h6 { @include u-margin-bottom(2); } +.margin-bottom-3 { + @include u-margin-bottom(3); +} + .margin-bottom-4 { @include u-margin-bottom(4); } @@ -253,10 +261,22 @@ h6 { @include u-padding(4); } +.padding-x-4 { + @include u-padding-x(4); +} + +.padding-bottom-0 { + @include u-padding-bottom(0); +} + .padding-bottom-4 { @include u-padding-bottom(4); } +.padding-top-4 { + @include u-padding-top(4); +} + .radius-lg { @include u-radius('lg'); } diff --git a/app/controllers/concerns/idv/verify_info_concern.rb b/app/controllers/concerns/idv/verify_info_concern.rb index 7cd09f84114..c8f0ac1f157 100644 --- a/app/controllers/concerns/idv/verify_info_concern.rb +++ b/app/controllers/concerns/idv/verify_info_concern.rb @@ -26,7 +26,6 @@ def shared_update Idv::Agent.new(pii).proof_resolution( document_capture_session, - should_proof_state_id: aamva_state?, trace_id: amzn_trace_id, user_id: current_user.id, threatmetrix_session_id: idv_session.threatmetrix_session_id, @@ -43,10 +42,6 @@ def ipp_enrollment_in_progress? current_user.has_in_person_enrollment? end - def aamva_state? - IdentityConfig.store.aamva_supported_jurisdictions.include?(pii['state_id_jurisdiction']) - end - def resolution_rate_limiter @resolution_rate_limiter ||= RateLimiter.new( user: current_user, diff --git a/app/controllers/idv/by_mail/enter_code_controller.rb b/app/controllers/idv/by_mail/enter_code_controller.rb index e9a3f230d49..2f8eeaf1b86 100644 --- a/app/controllers/idv/by_mail/enter_code_controller.rb +++ b/app/controllers/idv/by_mail/enter_code_controller.rb @@ -45,7 +45,7 @@ def create @gpo_verify_form = build_gpo_verify_form - result = @gpo_verify_form.submit + result = @gpo_verify_form.submit(resolved_authn_context_result.enhanced_ipp?) analytics.idv_verify_by_mail_enter_code_submitted(**result.to_h) if !result.success? diff --git a/app/controllers/idv/enter_password_controller.rb b/app/controllers/idv/enter_password_controller.rb index 22d5af84833..b2c2963aa97 100644 --- a/app/controllers/idv/enter_password_controller.rb +++ b/app/controllers/idv/enter_password_controller.rb @@ -124,8 +124,10 @@ def gpo_mail_service end def init_profile - idv_session.create_profile_from_applicant_with_password(password) - + idv_session.create_profile_from_applicant_with_password( + password, + resolved_authn_context_result.enhanced_ipp?, + ) if idv_session.verify_by_mail? current_user.send_email_to_all_addresses(:verify_by_mail_letter_requested) analytics.idv_gpo_address_letter_enqueued( diff --git a/app/controllers/idv/in_person/ready_to_verify_controller.rb b/app/controllers/idv/in_person/ready_to_verify_controller.rb index a3f9f4b4d50..ab70eeb3f32 100644 --- a/app/controllers/idv/in_person/ready_to_verify_controller.rb +++ b/app/controllers/idv/in_person/ready_to_verify_controller.rb @@ -17,9 +17,12 @@ class ReadyToVerifyController < ApplicationController before_action :confirm_in_person_session def show - @is_eipp = resolved_authn_context_result.enhanced_ipp? + @is_enhanced_ipp = resolved_authn_context_result.enhanced_ipp? analytics.idv_in_person_ready_to_verify_visit(**opt_in_analytics_properties) - @presenter = ReadyToVerifyPresenter.new(enrollment: enrollment, is_eipp: @is_eipp) + @presenter = ReadyToVerifyPresenter.new( + enrollment: enrollment, + is_enhanced_ipp: @is_enhanced_ipp, + ) end private diff --git a/app/forms/gpo_verify_form.rb b/app/forms/gpo_verify_form.rb index 8e840a01e2c..2253e49a2de 100644 --- a/app/forms/gpo_verify_form.rb +++ b/app/forms/gpo_verify_form.rb @@ -17,7 +17,7 @@ def initialize(user:, pii:, otp: nil) @otp = otp end - def submit + def submit(is_enhanced_ipp) result = valid? fraud_check_failed = pending_profile&.fraud_pending_reason.present? @@ -25,7 +25,7 @@ def submit pending_profile&.remove_gpo_deactivation_reason if user.has_establishing_in_person_enrollment_safe? - schedule_in_person_enrollment_and_deactivate_profile + schedule_in_person_enrollment_and_deactivate_profile(is_enhanced_ipp) elsif fraud_check_failed && threatmetrix_enabled? pending_profile&.deactivate_for_fraud_review elsif fraud_check_failed @@ -63,8 +63,12 @@ def gpo_confirmation_code pending_profile.gpo_confirmation_codes.first_with_otp(otp) end - def schedule_in_person_enrollment_and_deactivate_profile - UspsInPersonProofing::EnrollmentHelper.schedule_in_person_enrollment(user, pii) + def schedule_in_person_enrollment_and_deactivate_profile(is_enhanced_ipp) + UspsInPersonProofing::EnrollmentHelper.schedule_in_person_enrollment( + user:, + pii:, + is_enhanced_ipp:, + ) pending_profile&.deactivate_for_in_person_verification end diff --git a/app/javascript/packages/phone-input/package.json b/app/javascript/packages/phone-input/package.json index 20d998f4141..2a9cc2c93ea 100644 --- a/app/javascript/packages/phone-input/package.json +++ b/app/javascript/packages/phone-input/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "dependencies": { "intl-tel-input": "^17.0.19", - "libphonenumber-js": "^1.11.3" + "libphonenumber-js": "^1.11.4" }, "sideEffects": [ "./index.ts" diff --git a/app/jobs/resolution_proofing_job.rb b/app/jobs/resolution_proofing_job.rb index 5c2be8a256e..a0959d4f7bc 100644 --- a/app/jobs/resolution_proofing_job.rb +++ b/app/jobs/resolution_proofing_job.rb @@ -20,12 +20,13 @@ def perform( result_id:, encrypted_arguments:, trace_id:, - should_proof_state_id:, ipp_enrollment_in_progress:, user_id: nil, service_provider_issuer: nil, threatmetrix_session_id: nil, - request_ip: nil + request_ip: nil, + # DEPRECATED ARGUMENTS + should_proof_state_id: false # rubocop:disable Lint/UnusedMethodArgument ) timer = JobHelpers::Timer.new @@ -49,11 +50,17 @@ def perform( applicant_pii: applicant_pii, threatmetrix_session_id: threatmetrix_session_id, request_ip: request_ip, - should_proof_state_id: should_proof_state_id, ipp_enrollment_in_progress: ipp_enrollment_in_progress, current_sp: current_sp, ) + ssn_is_unique = Idv::DuplicateSsnFinder.new( + ssn: applicant_pii[:ssn], + user: user, + ).ssn_is_unique? + + callback_log_data.result[:ssn_is_unique] = ssn_is_unique + document_capture_session = DocumentCaptureSession.new(result_id: result_id) document_capture_session.store_proofing_result(callback_log_data.result) ensure @@ -77,7 +84,6 @@ def make_vendor_proofing_requests( applicant_pii:, threatmetrix_session_id:, request_ip:, - should_proof_state_id:, ipp_enrollment_in_progress:, current_sp: ) @@ -86,7 +92,6 @@ def make_vendor_proofing_requests( user_email: user.confirmed_email_addresses.first.email, threatmetrix_session_id: threatmetrix_session_id, request_ip: request_ip, - should_proof_state_id: should_proof_state_id, ipp_enrollment_in_progress: ipp_enrollment_in_progress, timer: timer, current_sp: current_sp, diff --git a/app/jobs/risc_delivery_job.rb b/app/jobs/risc_delivery_job.rb index b9d566335c0..9bdbcb7cd53 100644 --- a/app/jobs/risc_delivery_job.rb +++ b/app/jobs/risc_delivery_job.rb @@ -14,10 +14,15 @@ class RiscDeliveryJob < ApplicationJob *NETWORK_ERRORS, wait: :polynomially_longer, attempts: 2, - ) + ) do |_job, _exception| + # Don't bubble up the exception when retries are exhausted + end + retry_on RedisRateLimiter::LimitError, wait: :polynomially_longer, - attempts: 10 + attempts: 10 do |_job, _exception| + # Don't bubble up the exception when retries are exhausted + end def self.warning_error_classes NETWORK_ERRORS + [RedisRateLimiter::LimitError] diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 28d80c901fb..4282cc2e395 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -293,7 +293,7 @@ def in_person_deadline_passed(enrollment:) end end - def in_person_ready_to_verify(enrollment:) + def in_person_ready_to_verify(enrollment:, is_enhanced_ipp:) attachments.inline['barcode.png'] = BarcodeOutputter.new( code: enrollment.enrollment_code, ).image_data @@ -302,11 +302,14 @@ def in_person_ready_to_verify(enrollment:) @hide_title = IdentityConfig.store.in_person_outage_message_enabled && IdentityConfig.store.in_person_outage_emailed_by_date.present? && IdentityConfig.store.in_person_outage_expected_update_date.present? - @header = t('in_person_proofing.headings.barcode') + @header = is_enhanced_ipp ? + t('in_person_proofing.headings.barcode_eipp') : t('in_person_proofing.headings.barcode') @presenter = Idv::InPerson::ReadyToVerifyPresenter.new( enrollment: enrollment, barcode_image_url: attachments['barcode.png'].url, + is_enhanced_ipp: is_enhanced_ipp, ) + @is_enhanced_ipp = is_enhanced_ipp mail( to: email_address.email, subject: t('user_mailer.in_person_ready_to_verify.subject', app_name: APP_NAME), diff --git a/app/presenters/idv/in_person/ready_to_verify_presenter.rb b/app/presenters/idv/in_person/ready_to_verify_presenter.rb index 48b3f4f9420..a5f8462f742 100644 --- a/app/presenters/idv/in_person/ready_to_verify_presenter.rb +++ b/app/presenters/idv/in_person/ready_to_verify_presenter.rb @@ -11,11 +11,11 @@ class ReadyToVerifyPresenter delegate :selected_location_details, :enrollment_code, to: :enrollment - def initialize(enrollment:, barcode_image_url: nil, sp_name: nil, is_eipp: false) + def initialize(enrollment:, barcode_image_url: nil, sp_name: nil, is_enhanced_ipp: false) @enrollment = enrollment @barcode_image_url = barcode_image_url @sp_name = sp_name - @is_eipp = is_eipp + @is_enhanced_ipp = is_enhanced_ipp end # Reminder is exclusive of the day the email is sent (1 less than days_to_due_date) @@ -68,7 +68,7 @@ def outage_dates_present? end def barcode_heading_text - if @is_eipp + if @is_enhanced_ipp t('in_person_proofing.headings.barcode_eipp') else t('in_person_proofing.headings.barcode') @@ -76,7 +76,7 @@ def barcode_heading_text end def state_id_heading_text - if @is_eipp + if @is_enhanced_ipp t('in_person_proofing.process.state_id.heading_eipp') else t('in_person_proofing.process.state_id.heading') @@ -84,7 +84,7 @@ def state_id_heading_text end def state_id_info - if @is_eipp + if @is_enhanced_ipp t('in_person_proofing.process.state_id.info_eipp') else t('in_person_proofing.process.state_id.info') diff --git a/app/services/idv/agent.rb b/app/services/idv/agent.rb index 83733a59295..b18208c4a03 100644 --- a/app/services/idv/agent.rb +++ b/app/services/idv/agent.rb @@ -8,7 +8,6 @@ def initialize(applicant) def proof_resolution( document_capture_session, - should_proof_state_id:, trace_id:, user_id:, threatmetrix_session_id:, @@ -23,7 +22,6 @@ def proof_resolution( job_arguments = { encrypted_arguments: encrypted_arguments, - should_proof_state_id: should_proof_state_id, trace_id: trace_id, result_id: document_capture_session.result_id, user_id: user_id, @@ -31,6 +29,8 @@ def proof_resolution( threatmetrix_session_id: threatmetrix_session_id, request_ip: request_ip, ipp_enrollment_in_progress: ipp_enrollment_in_progress, + # This argument is intended to be removed + should_proof_state_id: false, } if IdentityConfig.store.ruby_workers_idv_enabled diff --git a/app/services/idv/session.rb b/app/services/idv/session.rb index df91551145f..a59e83c6d44 100644 --- a/app/services/idv/session.rb +++ b/app/services/idv/session.rb @@ -62,7 +62,7 @@ def respond_to_missing?(method_sym, include_private) VALID_SESSION_ATTRIBUTES.include?(attr_name_sym) || super end - def create_profile_from_applicant_with_password(user_password) + def create_profile_from_applicant_with_password(user_password, is_enhanced_ipp) profile_maker = build_profile_maker(user_password) profile = profile_maker.save_profile( fraud_pending_reason: threatmetrix_fraud_pending_reason, @@ -87,9 +87,10 @@ def create_profile_from_applicant_with_password(user_password) create_gpo_entry(profile_maker.pii_attributes, profile) elsif profile.in_person_verification_pending? UspsInPersonProofing::EnrollmentHelper.schedule_in_person_enrollment( - current_user, - profile_maker.pii_attributes, - opt_in_param, + user: current_user, + pii: profile_maker.pii_attributes, + is_enhanced_ipp: is_enhanced_ipp, + opt_in: opt_in_param, ) end end diff --git a/app/services/proofing/resolution/progressive_proofer.rb b/app/services/proofing/resolution/progressive_proofer.rb index a37f557ecdd..77b1a4cc1ac 100644 --- a/app/services/proofing/resolution/progressive_proofer.rb +++ b/app/services/proofing/resolution/progressive_proofer.rb @@ -10,7 +10,6 @@ module Resolution class ProgressiveProofer attr_reader :applicant_pii, :request_ip, - :should_proof_state_id, :threatmetrix_session_id, :timer, :user_email, @@ -20,8 +19,6 @@ class ProgressiveProofer # @param [Boolean] ipp_enrollment_in_progress flag that indicates if user will have # both state id address and current residential address verified # @param [String] request_ip IP address for request - # @param [Boolean] should_proof_state_id based on state id jurisdiction, indicates if - # there should be a state id proofing request made to aamva # @param [String] threatmetrix_session_id identifies the threatmetrix session # @param [JobHelpers::Timer] timer indicates time elapsed to obtain results # @param [String] user_email email address for applicant @@ -29,7 +26,6 @@ class ProgressiveProofer def proof( applicant_pii:, request_ip:, - should_proof_state_id:, threatmetrix_session_id:, timer:, user_email:, @@ -38,7 +34,6 @@ def proof( ) @applicant_pii = applicant_pii @request_ip = request_ip - @should_proof_state_id = should_proof_state_id @threatmetrix_session_id = threatmetrix_session_id @timer = timer @user_email = user_email @@ -54,7 +49,7 @@ def proof( device_profiling_result: device_profiling_result, ipp_enrollment_in_progress: ipp_enrollment_in_progress, resolution_result: instant_verify_result, - should_proof_state_id: should_proof_state_id, + should_proof_state_id: aamva_supports_state_id_jurisdiction?, state_id_result: state_id_result, residential_resolution_result: residential_instant_verify_result, same_address_as_id: applicant_pii[:same_address_as_id], @@ -126,7 +121,7 @@ def proof_id_address_with_lexis_nexis_if_needed end def should_proof_state_id_with_aamva? - return false unless should_proof_state_id + return false unless aamva_supports_state_id_jurisdiction? # If the user is in in-person-proofing and they have changed their address then # they are not eligible for get-to-yes if !ipp_enrollment_in_progress? || same_address_as_id? @@ -136,6 +131,11 @@ def should_proof_state_id_with_aamva? end end + def aamva_supports_state_id_jurisdiction? + state_id_jurisdiction = applicant_pii[:state_id_jurisdiction] + IdentityConfig.store.aamva_supported_jurisdictions.include?(state_id_jurisdiction) + end + def proof_id_with_aamva_if_needed return out_of_aamva_jurisdiction_result unless should_proof_state_id_with_aamva? diff --git a/app/services/proofing/resolution/result_adjudicator.rb b/app/services/proofing/resolution/result_adjudicator.rb index eda00d80774..3fc07cb3483 100644 --- a/app/services/proofing/resolution/result_adjudicator.rb +++ b/app/services/proofing/resolution/result_adjudicator.rb @@ -39,7 +39,6 @@ def adjudicated_result device_profiling_adjudication_reason: device_profiling_reason, resolution_adjudication_reason: resolution_reason, should_proof_state_id: should_proof_state_id?, - sp_costs_added: true, stages: { resolution: resolution_result.to_h, residential_address: residential_resolution_result.to_h, diff --git a/app/services/usps_in_person_proofing/enrollment_helper.rb b/app/services/usps_in_person_proofing/enrollment_helper.rb index ff0f6eb50e0..1a500465f57 100644 --- a/app/services/usps_in_person_proofing/enrollment_helper.rb +++ b/app/services/usps_in_person_proofing/enrollment_helper.rb @@ -3,7 +3,7 @@ module UspsInPersonProofing class EnrollmentHelper class << self - def schedule_in_person_enrollment(user, pii, opt_in = nil) + def schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:, opt_in: nil) enrollment = user.establishing_in_person_enrollment return unless enrollment @@ -17,7 +17,7 @@ def schedule_in_person_enrollment(user, pii, opt_in = nil) transform_keys(SECONDARY_ID_ADDRESS_MAP) end - enrollment_code = create_usps_enrollment(enrollment, pii) + enrollment_code = create_usps_enrollment(enrollment, pii, is_enhanced_ipp) return unless enrollment_code # update the enrollment to status pending @@ -35,13 +35,14 @@ def schedule_in_person_enrollment(user, pii, opt_in = nil) tmx_status: enrollment.profile&.tmx_status, ) - send_ready_to_verify_email(user, enrollment) + send_ready_to_verify_email(user, enrollment, is_enhanced_ipp: is_enhanced_ipp) end - def send_ready_to_verify_email(user, enrollment) + def send_ready_to_verify_email(user, enrollment, is_enhanced_ipp:) user.confirmed_email_addresses.each do |email_address| UserMailer.with(user: user, email_address: email_address).in_person_ready_to_verify( enrollment: enrollment, + is_enhanced_ipp: is_enhanced_ipp, ).deliver_now_or_later end end @@ -52,7 +53,7 @@ def send_ready_to_verify_email(user, enrollment) # @param [Pii::Attributes] pii The PII associated with the in-person enrollment # @return [String] The enrollment code # @raise [Exception::RequestEnrollException] Raised with a problem creating the enrollment - def create_usps_enrollment(enrollment, pii) + def create_usps_enrollment(enrollment, pii, is_enhanced_ipp) # Use the enrollment's unique_id value if it exists, otherwise use the deprecated # #usps_unique_id value in order to remain backwards-compatible. LG-7024 will remove this unique_id = enrollment.unique_id || enrollment.usps_unique_id @@ -71,7 +72,7 @@ def create_usps_enrollment(enrollment, pii) ) proofer = usps_proofer - response = proofer.request_enroll(applicant) + response = proofer.request_enroll(applicant, is_enhanced_ipp) response.enrollment_code rescue Faraday::BadRequestError => err handle_bad_request_error(err, enrollment) diff --git a/app/services/usps_in_person_proofing/mock/fixtures.rb b/app/services/usps_in_person_proofing/mock/fixtures.rb index 71fbdc5b71b..c5eaffaa1b7 100644 --- a/app/services/usps_in_person_proofing/mock/fixtures.rb +++ b/app/services/usps_in_person_proofing/mock/fixtures.rb @@ -19,8 +19,8 @@ def self.request_facilities_response load_response_fixture('request_facilities_response.json') end - def self.request_eipp_facilities_response - load_response_fixture('request_eipp_facilities_response.json') + def self.request_enhanced_ipp_facilities_response + load_response_fixture('request_enhanced_ipp_facilities_response.json') end def self.request_facilities_response_with_unordered_distance @@ -43,6 +43,10 @@ def self.request_enroll_response load_response_fixture('request_enroll_response.json') end + def self.request_enroll_response_enhanced_ipp + load_response_fixture('request_enroll_response_enhanced_ipp.json') + end + def self.request_enroll_bad_request_response load_response_fixture('request_enroll_failed_response.json') end diff --git a/app/services/usps_in_person_proofing/mock/proofer.rb b/app/services/usps_in_person_proofing/mock/proofer.rb index d20eeaa4d2d..10b5be38681 100644 --- a/app/services/usps_in_person_proofing/mock/proofer.rb +++ b/app/services/usps_in_person_proofing/mock/proofer.rb @@ -3,7 +3,7 @@ module UspsInPersonProofing module Mock class Proofer < UspsInPersonProofing::Proofer - def request_enroll(applicant) + def request_enroll(applicant, is_enhanced_ipp) case applicant['first_name'] when 'usps waiting' # timeout @@ -26,12 +26,15 @@ def request_enroll(applicant) res = JSON.parse(Fixtures.request_enroll_response) end + if is_enhanced_ipp + res = JSON.parse(Fixtures.request_enroll_response_enhanced_ipp) + end Response::RequestEnrollResponse.new(res) end def request_facilities(_location, is_enhanced_ipp) if is_enhanced_ipp - parse_facilities(JSON.parse(Fixtures.request_eipp_facilities_response)) + parse_facilities(JSON.parse(Fixtures.request_enhanced_ipp_facilities_response)) else parse_facilities(JSON.parse(Fixtures.request_facilities_response)) end diff --git a/app/services/usps_in_person_proofing/mock/responses/request_eipp_facilities_response.json b/app/services/usps_in_person_proofing/mock/responses/request_enhanced_ipp_facilities_response.json similarity index 100% rename from app/services/usps_in_person_proofing/mock/responses/request_eipp_facilities_response.json rename to app/services/usps_in_person_proofing/mock/responses/request_enhanced_ipp_facilities_response.json diff --git a/app/services/usps_in_person_proofing/mock/responses/request_enroll_response_enhanced_ipp.json b/app/services/usps_in_person_proofing/mock/responses/request_enroll_response_enhanced_ipp.json new file mode 100644 index 00000000000..6e08ead2c25 --- /dev/null +++ b/app/services/usps_in_person_proofing/mock/responses/request_enroll_response_enhanced_ipp.json @@ -0,0 +1,4 @@ +{ + "enrollmentCode": "314159", + "responseMessage": "Applicant 314159 successfully processed through enhanced ipp" +} diff --git a/app/services/usps_in_person_proofing/proofer.rb b/app/services/usps_in_person_proofing/proofer.rb index be92ca723e9..ccfd883c0ef 100644 --- a/app/services/usps_in_person_proofing/proofer.rb +++ b/app/services/usps_in_person_proofing/proofer.rb @@ -46,7 +46,7 @@ def request_facilities(location, is_enhanced_ipp) # stored with the unique ID to be able to request the status of proofing. # @param applicant [Hash] # @return [Hash] API response - def request_enroll(applicant) + def request_enroll(applicant, is_enhanced_ipp) url = "#{root_url}/ivs-ippaas-api/IPPRest/resources/rest/optInIPPApplicant" request_body = { sponsorID: sponsor_id, @@ -61,6 +61,11 @@ def request_enroll(applicant) IPPAssuranceLevel: '1.5', } + if is_enhanced_ipp + request_body[:sponsorID] = IdentityConfig.store.usps_eipp_sponsor_id.to_i + request_body[:IPPAssuranceLevel] = '2.0' + end + res = faraday.post(url, request_body, dynamic_headers) do |req| req.options.context = { service_name: 'usps_enroll' } end diff --git a/app/views/idv/in_person/ready_to_verify/show.html.erb b/app/views/idv/in_person/ready_to_verify/show.html.erb index ccc0fac3fe0..a8d1b4b7dce 100644 --- a/app/views/idv/in_person/ready_to_verify/show.html.erb +++ b/app/views/idv/in_person/ready_to_verify/show.html.erb @@ -33,7 +33,8 @@

<%= t('in_person_proofing.body.barcode.deadline_restart') %>

<% end %> -<% if @is_eipp %> +<%# Enhanced IPP Only - What to bring section %> +<% if @is_enhanced_ipp %>
<%# What to bring to the Post Office %>

<%= t('in_person_proofing.headings.barcode_what_to_bring') %>

@@ -143,7 +144,8 @@

<%= @presenter.state_id_info %>

<% end %> <% end %> - <% if !@is_eipp %> + + <% if !@is_enhanced_ipp %>

<%= t('in_person_proofing.body.barcode.questions') %> <%= render ClickObserverComponent.new(event_name: 'IdV: user clicked what to bring link on ready to verify page') do %> diff --git a/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb b/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb index 110781b1b05..8c095e20d82 100644 --- a/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb +++ b/app/views/user_mailer/shared/_in_person_ready_to_verify.html.erb @@ -13,7 +13,9 @@ <%= t('in_person_proofing.headings.barcode') %> <% end %> -

+ +<%# Barcode %> +
<%= render 'idv/shared/mini_logo', filename: 'email/logo.png' %> <%= render BarcodeComponent.new( barcode_data: @presenter.enrollment_code, @@ -23,7 +25,8 @@ ) %>
- +<%# Alert box %> +
<%= image_tag('email/info.png', width: 16, height: 16, alt: '') %> @@ -35,7 +38,136 @@
-
+<%# Enhanced IPP Only - What to bring section %> +<% if @is_enhanced_ipp %> +
+ <%# What to bring to the Post Office %> +

<%= t('in_person_proofing.headings.barcode_what_to_bring') %>

+

<%= t('in_person_proofing.body.barcode.what_to_bring') %>

+ + <%# Option 1: Bring a Real ID %> +

<%= t('in_person_proofing.process.eipp_bring_id.heading') %>

+
+ + + + + + + + +
+ <%= image_tag( + asset_url('idv/real-id.svg'), + width: 110, + height: 80, + alt: t('in_person_proofing.process.eipp_bring_id.image_alt_text'), + role: 'img', + class: 'margin-bottom-3', + ) %> + + +

<%= t('in_person_proofing.process.eipp_bring_id.info') %>

+
+
+
+ + <%# Option 2: Bring a standard State ID... %> +

<%= t('in_person_proofing.process.eipp_what_to_bring.heading') %>

+

<%= t('in_person_proofing.process.eipp_what_to_bring.info') %>

+ + <%# A. State ID + Passport %> + + + + + + + + +
+ <%= image_tag( + asset_url('idv/state-id-and-passport.svg'), + width: 110.46, + height: 129.11, + alt: t('in_person_proofing.process.eipp_state_id_passport.image_alt_text'), + role: 'img', + ) %> + + +

<%= t('in_person_proofing.process.eipp_state_id_passport.heading') %>

+

<%= t('in_person_proofing.process.eipp_state_id_passport.info') %>

+
+
+ + <%# B. State ID + Military ID %> + + + + + + + + +
+ <%= image_tag( + asset_url('idv/state-id-and-military-id.svg'), + width: 110.46, + height: 93, + alt: t('in_person_proofing.process.eipp_state_id_military_id.image_alt_text'), + role: 'img', + ) %> + + +

<%= t('in_person_proofing.process.eipp_state_id_military_id.heading') %>

+

<%= t('in_person_proofing.process.eipp_state_id_military_id.info') %>

+
+
+ + <%# C. State ID + two supporting documents %> + + + + + + + + +
+ <%= image_tag( + asset_url('idv/state-id-and-fair-evidence-documents.svg'), + width: 110.46, + height: 107, + alt: t('in_person_proofing.process.eipp_state_id_supporting_docs.image_alt_text'), + role: 'img', + ) %> + + +

<%= t('in_person_proofing.process.eipp_state_id_supporting_docs.heading') %>

+

<%= t('in_person_proofing.process.eipp_state_id_supporting_docs.info') %>

+
    + <% t('in_person_proofing.process.eipp_state_id_supporting_docs.info_list').each do |doc| %> +
  • <%= doc %>
  • + <% end %> +
+
+ + <%# Questions? %> +

+ <%= t('in_person_proofing.body.barcode.questions') %> + <%= link_to( + t('in_person_proofing.body.barcode.learn_more'), + MarketingSite.help_center_article_url( + category: 'verify-your-identity', + article: 'verify-your-identity-in-person', + ), + ) %> +

+
+<% end %> + +<%# What to expect at the Post Office %> +

<%= t('in_person_proofing.body.barcode.what_to_expect') %>

@@ -43,36 +175,39 @@
1
-

<%= t('in_person_proofing.process.what_to_do.heading') %>

-

<%= t('in_person_proofing.process.what_to_do.info', app_name: APP_NAME) %>

+

<%= t('in_person_proofing.process.what_to_do.heading') %>

+

<%= t('in_person_proofing.process.what_to_do.info', app_name: APP_NAME) %>

2
-

<%= t('in_person_proofing.process.barcode.heading', app_name: APP_NAME) %>

-

<%= t('in_person_proofing.process.barcode.info') %>

+

<%= t('in_person_proofing.process.barcode.heading', app_name: APP_NAME) %>

+

<%= t('in_person_proofing.process.barcode.info') %>

-
3
- -

<%= t('in_person_proofing.process.state_id.heading') %>

-

<%= t('in_person_proofing.process.state_id.info') %>

+
3
+ +

<%= @presenter.state_id_heading_text %>

+

<%= @presenter.state_id_info %>

-

- <%= t('in_person_proofing.body.barcode.questions') %> - <%= link_to( - t('in_person_proofing.body.barcode.learn_more'), - MarketingSite.help_center_article_url( - category: 'verify-your-identity', - article: 'verify-your-identity-in-person', - ), - ) %> -

+ + <% if !@is_enhanced_ipp %> +

+ <%= t('in_person_proofing.body.barcode.questions') %> + <%= link_to( + t('in_person_proofing.body.barcode.learn_more'), + MarketingSite.help_center_article_url( + category: 'verify-your-identity', + article: 'verify-your-identity-in-person', + ), + ) %> +

+ <% end %>

<%= t('in_person_proofing.body.location.heading') %>

diff --git a/config/initializers/job_configurations.rb b/config/initializers/job_configurations.rb index c15b6af5f9d..e1e7e7fb71b 100644 --- a/config/initializers/job_configurations.rb +++ b/config/initializers/job_configurations.rb @@ -6,7 +6,7 @@ cron_24h = '0 0 * * *' cron_24h_1am = '0 1 * * *' # 1am UTC is 8pm EST/9pm EDT gpo_cron_24h = '0 10 * * *' # 10am UTC is 5am EST/6am EDT -cron_1w = '0 0 * * 0' +cron_every_monday = 'every Monday at 0:00 UTC' # equivalent to '0 0 * * 1' if defined?(Rails::Console) Rails.logger.info 'job_configurations: console detected, skipping schedule' @@ -211,11 +211,11 @@ cron: cron_24h, args: -> { [Time.zone.yesterday.end_of_day] }, }, - # Send weekly authentication reports to partners + # Send previous week's authentication reports to partners weekly_authentication_report: { class: 'Reports::AuthenticationReport', - cron: cron_1w, - args: -> { [Time.zone.now] }, + cron: cron_every_monday, + args: -> { [Time.zone.yesterday] }, }, # Send fraud metrics to Team Judy fraud_metrics_report: { @@ -223,11 +223,11 @@ cron: cron_24h, args: -> { [Time.zone.yesterday.end_of_day] }, }, - # Weekly drop of report - drop_off_report: { + # Previous week's drop of report + weekly_drop_off_report: { class: 'Reports::DropOffReport', - cron: cron_1w, - args: -> { [Time.zone.today] }, + cron: cron_every_monday, + args: -> { [Time.zone.yesterday] }, }, }.compact end diff --git a/config/locales/zh.yml b/config/locales/zh.yml index 2e4f95e01fa..a8b5be89b5e 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -632,7 +632,7 @@ doc_auth.info.verify_at_post_office_description_selfie: 如果你没有手机可 doc_auth.info.verify_at_post_office_instruction: 你在网上输入身份证件信息,然后到一个参与本项目的邮局去亲身验证身份。 doc_auth.info.verify_at_post_office_instruction_selfie: 你在网上输入身份证件信息,然后到一个参与本项目的邮局去亲身验证身份。 doc_auth.info.verify_at_post_office_link_text: 对亲身验证获得更多了解 -doc_auth.info.verify_identity: 我们会要求获得你的个人信息并通过与公共记录核对来验证你的身份。 +doc_auth.info.verify_identity: 我们会要求获得你的身份识别、电话号码和其他个人信息并通过与公共记录核对来验证你的身份。 doc_auth.info.verify_online_description: 如果你没有移动设备或者无法轻松拍身份证件照片,这一选项更好。 doc_auth.info.verify_online_description_selfie: 如果你有手机可以拍照,请选择该选项。 doc_auth.info.verify_online_instruction: 你将拍身份证件的照片来完全在网上验证身份。大多数用户都能轻松完成这样流程。 @@ -1028,7 +1028,7 @@ idv.failure.phone.rate_limited.body: 为了你的安全,我们限制你在网 idv.failure.phone.rate_limited.gpo.button: 通过普通邮件验证 idv.failure.phone.rate_limited.heading: 我们无法通过电话验证你的身份。 idv.failure.phone.rate_limited.option_try_again_later_html: 取消并在 %{time_left} 后再试 -idv.failure.phone.rate_limited.option_verify_by_mail_html: 通过普通邮件验证,这需要5 到 10 天 +idv.failure.phone.rate_limited.option_verify_by_mail_html: 通过普通邮件验证,这需要五到十天 idv.failure.phone.rate_limited.options_header: 你可以: idv.failure.phone.timeout: 我们请你验证自己信息的请求已过期。请再试一次。 idv.failure.phone.warning.attempts_html.one: 出于安全考虑,你只能再试一次了。 @@ -1036,10 +1036,10 @@ idv.failure.phone.warning.attempts_html.other: 出于安全考虑,你只能再 idv.failure.phone.warning.gpo.button: 通过普通邮件验证 idv.failure.phone.warning.gpo.explanation: 如果你没有别的电话号码可以尝试,那请通过普通邮件验证。 idv.failure.phone.warning.gpo.heading: 通过普通邮件验证 -idv.failure.phone.warning.gpo.how_long_it_takes_html: 这需要5 到 10 天。 +idv.failure.phone.warning.gpo.how_long_it_takes_html: 这需要五到十天。 idv.failure.phone.warning.heading: 我们无法将你与该号码匹配。 idv.failure.phone.warning.learn_more_link: 了解有关使用什么号码的更多信息。 -idv.failure.phone.warning.next_steps_html: 尝试 a另一个 你经常使用并用了很久的号码。 工作或住宅号码都行。 +idv.failure.phone.warning.next_steps_html: 尝试 另一个 你经常使用并用了很久的号码。 工作或住宅号码都行。 idv.failure.phone.warning.try_again_button: 尝试另一个号码 idv.failure.phone.warning.you_entered: 你输入了: idv.failure.sessions.exception: 处理你的请求时内部出错。 @@ -1086,9 +1086,9 @@ idv.gpo.did_not_receive_letter.title: 没收到信? idv.gpo.form.otp_label: 验证码 idv.gpo.form.submit: 提交 idv.gpo.intro: 欢迎回来输入你收到信中的由 10 个字符组成的代码。 -idv.gpo.last_letter_request_message_html: 你最近一次要求我们发信是%{date_letter_was_sent}。如果你的信件还没到,请耐心一点,因为信件有可能需要10 days才能送到。感谢你的耐心。 +idv.gpo.last_letter_request_message_html: 你最近一次要求我们发信是%{date_letter_was_sent}。如果你的信件还没到,请耐心一点,因为信件有可能需要十天才能送到。感谢你的耐心。 idv.gpo.request_another_letter.button: 要求再发一封信 -idv.gpo.request_another_letter.instructions_html: 如果你目前的信有问题或者从未收到,请再要求发一封信。信件需要5 到 10 天到达。 +idv.gpo.request_another_letter.instructions_html: 如果你目前的信有问题或者从未收到,请再要求发一封信。信件需要五到十天到达。 idv.gpo.request_another_letter.learn_more_link: 对通过邮件验证你地址获得更多了解 idv.gpo.request_another_letter.title: 要求再发一封信? idv.gpo.return_to_profile: 返回你的用户资料 @@ -1183,7 +1183,7 @@ in_person_proofing.body.barcode.learn_more: 了解有关携带物品的更多信 in_person_proofing.body.barcode.location_details: 详细地址信息 in_person_proofing.body.barcode.questions: 有问题吗? in_person_proofing.body.barcode.retail_hours: 营业时间 -in_person_proofing.body.barcode.retail_hours_closed: 已关闭 +in_person_proofing.body.barcode.retail_hours_closed: 关闭 in_person_proofing.body.barcode.return_to_partner_html: 你现在可以 %{link_html}来完成你可做的任何随后步骤,直到你的身份得到验证。 in_person_proofing.body.barcode.return_to_partner_link: 登出 %{sp_name} 并返回 %{sp_name} in_person_proofing.body.barcode.what_to_bring: 取决于你身份证件或驾照的类型,你可能会被要求出示支持性文件。请仔细阅读以下选项: @@ -1331,7 +1331,7 @@ instructions.mfa.piv_cac.not_auth_cert_html: 你选择的证书对这个账户 instructions.mfa.piv_cac.please_try_again: 再试一次 instructions.mfa.piv_cac.sign_in_html: 确保 你有 %{app_name} 账户 而且 PIV/CAC 已被你设置为一个双因素身份证实方法。 instructions.mfa.piv_cac.step_1: 给它一个昵称 -instructions.mfa.piv_cac.step_1_info: 这样如果你添加了一个以上 PIV/CA 话,你就能把它们分辨开来。 +instructions.mfa.piv_cac.step_1_info: 这样如果你添加了一个以上 PIV/CAC 话,你就能把它们分辨开来。 instructions.mfa.piv_cac.step_2: 把 PIV/CAC 插入读卡器 instructions.mfa.piv_cac.step_3: 添加 PIV/CAC instructions.mfa.piv_cac.step_3_info_html: 你将需要选择一个证书 (恰当的证书可能会有你的名字)而且输入你的个人识别号码(PIN) (你的个人识别号码(PIN)是在设置 PIV/CAC 时设立的)。 @@ -1415,15 +1415,15 @@ notices.privacy.security_and_privacy_practices: 安全实践和隐私法声明 notices.resend_confirmation_email.success: 我们发送了另外一个确认电邮。 notices.session_cleared: 为了你的安全,如果你在 %{minutes} 分钟内不移动到一个新页面,我们会清除你输入的内容。 notices.session_timedout: 我们已将你登出。为了你的安全,如果你在 %{minutes} 分钟内不移动到一个新页面,%{app_name} 会结束你此次访问。 -notices.signed_up_and_confirmed.first_paragraph_end: 带有重设你密码的链接。点击链接去继续把这个电邮添加到你的账户。 +notices.signed_up_and_confirmed.first_paragraph_end: 带有确认你的电邮地址的链接。点击链接去继续把这个电邮添加到你的账户。 notices.signed_up_and_confirmed.first_paragraph_start: 我们已发电邮到 notices.signed_up_and_confirmed.no_email_sent_explanation_start: 没有收到电邮? -notices.signed_up_but_unconfirmed.first_paragraph_end: 带有确认你电邮的链接。点击链接来继续设立你的账户。 +notices.signed_up_but_unconfirmed.first_paragraph_end: 带有确认你的电邮地址的链接。点击链接来继续设立你的账户。 notices.signed_up_but_unconfirmed.first_paragraph_start: 我们已发电邮到 notices.signed_up_but_unconfirmed.resend_confirmation_email: 重新发送确认电邮 notices.timeout_warning.partially_signed_in.continue: 继续登录 notices.timeout_warning.partially_signed_in.live_region_message_html: '%{time_left_in_session_html} 后你会被登出。选择“保持我登录状态”保持登录;选择“把我登出”来登出。' -notices.timeout_warning.partially_signed_in.message_html: 为了你的安全, %{time_left_in_session_html} 后我们将取消你的登录。 +notices.timeout_warning.partially_signed_in.message_html: 为了你的安全, %{time_left_in_session_html}分钟后我们将取消你的登录。 notices.timeout_warning.partially_signed_in.sign_out: 取消登录 notices.timeout_warning.signed_in.continue: 保持我登录状态 notices.timeout_warning.signed_in.live_region_message_html: '%{time_left_in_session_html} 后你会被登出。选择“保持我登录状态”保持登录;选择“把我登出”来登出。' @@ -1531,7 +1531,7 @@ time.am: 上午 time.formats.event_date: '%B %-d, %Y' time.formats.event_time: '%-l:%M %p' time.formats.event_timestamp: '%B %-d, %Y at %-l:%M %p' -time.formats.event_timestamp_js: '%{year} %{month} %{day}, %{hour}:%{minute} %{day_period}' +time.formats.event_timestamp_js: '%{year}年%{month}月%{day}日, %{hour}:%{minute} %{day_period}' time.formats.event_timestamp_utc: '%B %-d, %Y, %-l:%M %p UTC' time.formats.event_timestamp_with_zone: '%B %-d, %Y,%-l:%M %p %Z' time.formats.full_date: '%Y 年 %B %-d 日' @@ -1937,7 +1937,7 @@ users.rules_of_use.details_html: |-
  • 解释 %{app_name} 服务原理以及你应有的期望,
  • 我们给你提供 %{app_name} 服务的服务条款,
  • -
  • 我们如何使用你的信息以及你对此信息拥有的权力,以及 and
  • +
  • 我们如何使用你的信息以及你对此信息拥有的权力,以及
  • 你同意的在 %{app_name} 采取某些行动的前提条件。
users.rules_of_use.overview_html: 我们已更新了我们的 %{link_html}。请审阅并在下面方框里打勾来继续。 @@ -1954,7 +1954,7 @@ vendor_outage.alerts.phone.idv: 我们目前无法验证电话。请等一会再 vendor_outage.alerts.pinpoint.idv.header: 我们正在争取解决错误。 vendor_outage.alerts.pinpoint.idv.message_html: '%{sp_name_html}需要确保你是你,而不是别人冒充你。' vendor_outage.alerts.pinpoint.idv.options_html: - - 现在继续并通过普通邮件验证,这需要5 到 10 天。 + - 现在继续并通过普通邮件验证,这需要五到十天。 - 退出 %{app_name},稍后再试。 vendor_outage.alerts.pinpoint.idv.options_prompt: 你可以: vendor_outage.alerts.pinpoint.idv.status_page_html: 遗憾的是,我们目前遇到技术困难。到 %{link_html} 了解错误何时能解决。 diff --git a/lib/reporting/identity_verification_report.rb b/lib/reporting/identity_verification_report.rb index 9acf6ef530d..1ff5f959aec 100644 --- a/lib/reporting/identity_verification_report.rb +++ b/lib/reporting/identity_verification_report.rb @@ -37,14 +37,20 @@ def self.all_events end module Results + # rubocop:disable Layout/LineLength IDV_FINAL_RESOLUTION_VERIFIED = 'IdV: final resolution - Verified' IDV_FINAL_RESOLUTION_FRAUD_REVIEW = 'IdV: final resolution - Fraud Review Pending' IDV_FINAL_RESOLUTION_GPO = 'IdV: final resolution - GPO Pending' + IDV_FINAL_RESOLUTION_GPO_FRAUD_REVIEW = 'Idv: final resolution - GPO Pending + Fraud Review Pending' IDV_FINAL_RESOLUTION_IN_PERSON = 'IdV: final resolution - In Person Proofing' + IDV_FINAL_RESOLUTION_IN_PERSON_FRAUD_REVIEW = 'IdV: final resolution - In Person Proofing + Fraud Review Pending' + IDV_FINAL_RESOLUTION_GPO_IN_PERSON = 'IdV: final resolution - GPO Pending + In Person Pending' + IDV_FINAL_RESOLUTION_GPO_IN_PERSON_FRAUD_REVIEW = 'IdV: final resolution - GPO Pending + In Person Pending + Fraud Review' IDV_REJECT_DOC_AUTH = 'IdV Reject: Doc Auth' IDV_REJECT_VERIFY = 'IdV Reject: Verify' IDV_REJECT_PHONE_FINDER = 'IdV Reject: Phone Finder' + # rubocop:enable Layout/LineLength end # @param [Array] issuers @@ -101,11 +107,14 @@ def as_csv csv << ['Image Submitted', idv_doc_auth_image_vendor_submitted] csv << [] csv << ['Workflow completed', idv_final_resolution] - csv << ['Workflow completed - Verified', idv_final_resolution_verified] - csv << ['Workflow completed - Total Pending', idv_final_resolution_total_pending] + csv << ['Workflow completed - With Phone Number', idv_final_resolution_verified] + csv << ['Workflow completed - With Phone Number - Fraud Review', idv_final_resolution_fraud_review] csv << ['Workflow completed - GPO Pending', idv_final_resolution_gpo] + csv << ['Workflow completed - GPO Pending - Fraud Review', idv_final_resolution_gpo_fraud_review] csv << ['Workflow completed - In-Person Pending', idv_final_resolution_in_person] - csv << ['Workflow completed - Fraud Review Pending', idv_final_resolution_fraud_review] + csv << ['Workflow completed - In-Person Pending - Fraud Review', idv_final_resolution_in_person_fraud_review] + csv << ['Workflow completed - GPO + In-Person Pending', idv_final_resolution_gpo_in_person] + csv << ['Workflow completed - GPO + In-Person Pending - Fraud Review', idv_final_resolution_gpo_in_person_fraud_review] csv << [] csv << ['Fraud review rejected', idv_fraud_rejected] csv << ['Successfully Verified', successfully_verified_users] @@ -167,21 +176,32 @@ def idv_final_resolution_verified data[Results::IDV_FINAL_RESOLUTION_VERIFIED].count end + def idv_final_resolution_fraud_review + data[Results::IDV_FINAL_RESOLUTION_FRAUD_REVIEW].count + end + def idv_final_resolution_gpo data[Results::IDV_FINAL_RESOLUTION_GPO].count end + def idv_final_resolution_gpo_fraud_review + data[Results::IDV_FINAL_RESOLUTION_GPO_FRAUD_REVIEW].count + end + def idv_final_resolution_in_person data[Results::IDV_FINAL_RESOLUTION_IN_PERSON].count end - def idv_final_resolution_fraud_review - data[Results::IDV_FINAL_RESOLUTION_FRAUD_REVIEW].count + def idv_final_resolution_in_person_fraud_review + data[Results::IDV_FINAL_RESOLUTION_IN_PERSON_FRAUD_REVIEW].count end - def idv_final_resolution_total_pending - @idv_final_resolution_total_pending ||= - (data[Events::IDV_FINAL_RESOLUTION] - data[Results::IDV_FINAL_RESOLUTION_VERIFIED]).count + def idv_final_resolution_gpo_in_person + data[Results::IDV_FINAL_RESOLUTION_GPO_IN_PERSON].count + end + + def idv_final_resolution_gpo_in_person_fraud_review + data[Results::IDV_FINAL_RESOLUTION_GPO_IN_PERSON_FRAUD_REVIEW].count end def gpo_verification_submitted @@ -236,6 +256,7 @@ def fraud_review_passed end # rubocop:disable Layout/LineLength + # rubocop:disable Metrics/BlockLength # Turns query results into a hash keyed by event name, values are a count of unique users # for that event # @return [Hash>] @@ -257,9 +278,23 @@ def data case event when Events::IDV_FINAL_RESOLUTION event_users[Results::IDV_FINAL_RESOLUTION_VERIFIED] << user_id if row['identity_verified'] == '1' - event_users[Results::IDV_FINAL_RESOLUTION_GPO] << user_id if row['gpo_verification_pending'] == '1' - event_users[Results::IDV_FINAL_RESOLUTION_IN_PERSON] << user_id if row['in_person_verification_pending'] == '1' - event_users[Results::IDV_FINAL_RESOLUTION_FRAUD_REVIEW] << user_id if row['fraud_review_pending'] == '1' + + gpo_verification_pending = row['gpo_verification_pending'] == '1' + in_person_verification_pending = row['in_person_verification_pending'] == '1' + fraud_review_pending = row['fraud_review_pending'] == '1' + + if !gpo_verification_pending && !in_person_verification_pending + event_users[Results::IDV_FINAL_RESOLUTION_FRAUD_REVIEW] << user_id if fraud_review_pending + elsif gpo_verification_pending && !in_person_verification_pending + event_users[Results::IDV_FINAL_RESOLUTION_GPO] << user_id if !fraud_review_pending + event_users[Results::IDV_FINAL_RESOLUTION_GPO_FRAUD_REVIEW] << user_id if fraud_review_pending + elsif !gpo_verification_pending && in_person_verification_pending + event_users[Results::IDV_FINAL_RESOLUTION_IN_PERSON] << user_id if !fraud_review_pending + event_users[Results::IDV_FINAL_RESOLUTION_IN_PERSON_FRAUD_REVIEW] << user_id if fraud_review_pending + elsif gpo_verification_pending && in_person_verification_pending + event_users[Results::IDV_FINAL_RESOLUTION_GPO_IN_PERSON] << user_id if !fraud_review_pending + event_users[Results::IDV_FINAL_RESOLUTION_GPO_IN_PERSON_FRAUD_REVIEW] << user_id if fraud_review_pending + end when Events::IDV_DOC_AUTH_IMAGE_UPLOAD event_users[Results::IDV_REJECT_DOC_AUTH] << user_id if row['doc_auth_failed_non_fraud'] == '1' when Events::IDV_DOC_AUTH_VERIFY_RESULTS @@ -272,6 +307,7 @@ def data event_users end end + # rubocop:enable Metrics/BlockLength # rubocop:enable Layout/LineLength def fetch_results diff --git a/lib/tasks/dev.rake b/lib/tasks/dev.rake index f24664d0356..880a26e0361 100644 --- a/lib/tasks/dev.rake +++ b/lib/tasks/dev.rake @@ -81,6 +81,7 @@ namespace :dev do desc 'Create in-person enrollments for N random users' task random_in_person_users: [:environment, :random_users] do + is_enhanced_ipp = false usps_request_delay_ms = (ENV['USPS_REQUEST_DELAY_MS'] || 0).to_i num_users = (ENV['NUM_USERS'] || 100).to_i pw = 'salty pickles' @@ -149,8 +150,9 @@ namespace :dev do num_attempts += 1 begin UspsInPersonProofing::EnrollmentHelper.schedule_in_person_enrollment( - user, - pii, + user: user, + pii: pii, + is_enhanced_ipp: is_enhanced_ipp, ) rescue StandardError => e Rails.logger.error 'Exception raised while enrolling user: ' + e.message diff --git a/spec/config/initializers/job_configurations_spec.rb b/spec/config/initializers/job_configurations_spec.rb index cb03410ce42..0ebf67e9a93 100644 --- a/spec/config/initializers/job_configurations_spec.rb +++ b/spec/config/initializers/job_configurations_spec.rb @@ -11,4 +11,28 @@ end end end + + describe 'weekly reporting' do + %w[drop_off_report authentication_report].each do |job_name| + it "schedules the #{job_name} to run after the end of the week with yesterday's date" do + report = GoodJob.configuration.cron[:"weekly_#{job_name}"] + expect(report[:class]).to eq("Reports::#{job_name.camelize}") + + freeze_time do + # Always passes the previous day as the argument + expect(report[:args].call).to eq([Time.zone.yesterday]) + + now = Time.zone.now + next_time = Fugit.parse(report[:cron]).next_time + expect(next_time.utc > now.utc.end_of_week). + to be(true), "Expected #{job_name} to next run after the end of this week" + expect(next_time.utc). + to be_within(1).of(now.utc.end_of_week), <<~EOS.squish + Expected #{job_name} to run soon after the end of week, + so CONUS 'yesterday' and UTC 'yesterday' will never be different + EOS + end + end + end + end end diff --git a/spec/controllers/idv/by_mail/enter_code_controller_spec.rb b/spec/controllers/idv/by_mail/enter_code_controller_spec.rb index d34ea5750a1..199513694a8 100644 --- a/spec/controllers/idv/by_mail/enter_code_controller_spec.rb +++ b/spec/controllers/idv/by_mail/enter_code_controller_spec.rb @@ -446,5 +446,28 @@ end end end + + context 'when the user is going through enhanced ipp' do + subject(:action) do + post(:create, params: { gpo_verify_form: { otp: good_otp } }) + end + let(:is_enhanced_ipp) { true } + let(:user) { create(:user, :with_pending_gpo_profile, created_at: 2.days.ago) } + let(:gpo_verify_form) { GpoVerifyForm.new(user: user, pii: {}, otp: good_otp) } + before do + authn_context_result = Vot::Parser.new(vector_of_trust: 'Pe').parse + allow(controller).to( + receive(:resolved_authn_context_result).and_return(authn_context_result), + ) + allow(GpoVerifyForm).to receive(:new).and_return(gpo_verify_form) + allow(gpo_verify_form).to receive(:submit).and_call_original + end + + it 'passes the correct param to the gpo verify form submit method' do + action + + expect(gpo_verify_form).to have_received(:submit).with(is_enhanced_ipp) + end + end end end diff --git a/spec/controllers/idv/enter_password_controller_spec.rb b/spec/controllers/idv/enter_password_controller_spec.rb index 33f10acad3b..78f5133256f 100644 --- a/spec/controllers/idv/enter_password_controller_spec.rb +++ b/spec/controllers/idv/enter_password_controller_spec.rb @@ -313,15 +313,59 @@ def show expect(response).to redirect_to idv_personal_key_path end - it 'creates Profile with applicant attributes' do - put :create, params: { user: { password: ControllerHelper::VALID_PASSWORD } } + context 'when the vector of trust is undefined' do + it 'creates Profile with applicant attributes' do + put :create, params: { user: { password: ControllerHelper::VALID_PASSWORD } } - profile = subject.idv_session.profile - pii = profile.decrypt_pii(ControllerHelper::VALID_PASSWORD) + profile = subject.idv_session.profile + pii = profile.decrypt_pii(ControllerHelper::VALID_PASSWORD) - expect(pii.zipcode).to eq subject.idv_session.applicant[:zipcode] + expect(pii.zipcode).to eq subject.idv_session.applicant[:zipcode] - expect(pii.first_name).to eq subject.idv_session.applicant[:first_name] + expect(pii.first_name).to eq subject.idv_session.applicant[:first_name] + end + end + + context 'when the vector of trust is defined' do + context 'when the vector of trust is not Enhanced IPP' do + before do + resolved_authn_context_result = Vot::Parser.new(vector_of_trust: 'Pb').parse + + allow(controller).to receive(:resolved_authn_context_result). + and_return(resolved_authn_context_result) + end + + it 'creates Profile with applicant attributes' do + put :create, params: { user: { password: ControllerHelper::VALID_PASSWORD } } + + profile = subject.idv_session.profile + pii = profile.decrypt_pii(ControllerHelper::VALID_PASSWORD) + + expect(pii.zipcode).to eq subject.idv_session.applicant[:zipcode] + + expect(pii.first_name).to eq subject.idv_session.applicant[:first_name] + end + end + + context 'when the vector of trust is Enhanced IPP' do + before do + resolved_authn_context_result = Vot::Parser.new(vector_of_trust: 'Pe').parse + + allow(controller).to receive(:resolved_authn_context_result). + and_return(resolved_authn_context_result) + end + + it 'creates Profile with applicant attributes' do + put :create, params: { user: { password: ControllerHelper::VALID_PASSWORD } } + + profile = subject.idv_session.profile + pii = profile.decrypt_pii(ControllerHelper::VALID_PASSWORD) + + expect(pii.zipcode).to eq subject.idv_session.applicant[:zipcode] + + expect(pii.first_name).to eq subject.idv_session.applicant[:first_name] + end + end end context 'user picked phone confirmation' do @@ -890,5 +934,29 @@ def show end end end + + context 'user is going through enhanced ipp' do + let(:is_enhanced_ipp) { true } + let!(:enrollment) do + create(:in_person_enrollment, :establishing, user: user, profile: nil) + end + before do + authn_context_result = Vot::Parser.new(vector_of_trust: 'Pe').parse + allow(controller).to( + receive(:resolved_authn_context_result).and_return(authn_context_result), + ) + end + it 'passes the correct param to the enrollment helper method' do + expect(UspsInPersonProofing::EnrollmentHelper).to receive(:schedule_in_person_enrollment). + with( + user: user, + pii: Pii::Attributes.new_from_hash(applicant), + is_enhanced_ipp: is_enhanced_ipp, + opt_in: nil, + ) + + put :create, params: { user: { password: ControllerHelper::VALID_PASSWORD } } + end + end end end diff --git a/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb b/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb index 712ddf496b4..17f4be87a7c 100644 --- a/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb +++ b/spec/controllers/idv/in_person/ready_to_verify_controller_spec.rb @@ -98,10 +98,10 @@ and_return(resolved_authn_context_result) end - it 'evaluates to IPP' do + it 'evaluates to In Person Proofing' do response - expect(assigns(:is_eipp)).to be false + expect(assigns(:is_enhanced_ipp)).to be false end end @@ -113,10 +113,10 @@ and_return(resolved_authn_context_result) end - it 'evaluates to EIPP' do + it 'evaluates to Enhanced IPP' do response - expect(assigns(:is_eipp)).to be true + expect(assigns(:is_enhanced_ipp)).to be true end end end diff --git a/spec/controllers/idv/in_person/usps_locations_controller_spec.rb b/spec/controllers/idv/in_person/usps_locations_controller_spec.rb index 68913117d91..8d0a7228a43 100644 --- a/spec/controllers/idv/in_person/usps_locations_controller_spec.rb +++ b/spec/controllers/idv/in_person/usps_locations_controller_spec.rb @@ -85,18 +85,18 @@ allow(UspsInPersonProofing::Proofer).to receive(:new).and_return(proofer) end - context 'with EIPP enabled' do + context 'with a user going through enhanced ipp' do let(:vtr) { ['C1.C2.P1.Pe'] } - let(:eipp_sp_session) { { vtr: vtr, acr_values: nil } } + let(:enhanced_ipp_sp_session) { { vtr: vtr, acr_values: nil } } let(:user) { build(:user) } let(:sp) { build(:service_provider, ial: 2) } before do - allow(controller).to receive(:sp_session).and_return(eipp_sp_session) + allow(controller).to receive(:sp_session).and_return(enhanced_ipp_sp_session) allow(controller).to receive(:sp_from_sp_session).and_return(sp) end - it 'requests EIPP locations' do + it 'requests enhanced ipp locations' do expect(AuthnContextResolver).to receive(:new).with( user: user, service_provider: sp, vtr: vtr, acr_values: nil diff --git a/spec/controllers/idv/in_person/verify_info_controller_spec.rb b/spec/controllers/idv/in_person/verify_info_controller_spec.rb index 2db02ec4455..ab4e5bbe6ee 100644 --- a/spec/controllers/idv/in_person/verify_info_controller_spec.rb +++ b/spec/controllers/idv/in_person/verify_info_controller_spec.rb @@ -156,7 +156,6 @@ expect_any_instance_of(Idv::Agent).to receive(:proof_resolution). with( kind_of(DocumentCaptureSession), - should_proof_state_id: anything, trace_id: subject.send(:amzn_trace_id), threatmetrix_session_id: nil, user_id: anything, @@ -172,7 +171,6 @@ it 'indicates to the IDV agent that ipp_enrollment_in_progress is enabled' do expect_any_instance_of(Idv::Agent).to receive(:proof_resolution).with( kind_of(DocumentCaptureSession), - should_proof_state_id: anything, trace_id: anything, threatmetrix_session_id: anything, user_id: anything, @@ -195,7 +193,6 @@ expect_any_instance_of(Idv::Agent).to receive(:proof_resolution). with( kind_of(DocumentCaptureSession), - should_proof_state_id: anything, trace_id: subject.send(:amzn_trace_id), threatmetrix_session_id: nil, user_id: anything, diff --git a/spec/controllers/idv/personal_key_controller_spec.rb b/spec/controllers/idv/personal_key_controller_spec.rb index 49c87cf6fcb..2899e92299c 100644 --- a/spec/controllers/idv/personal_key_controller_spec.rb +++ b/spec/controllers/idv/personal_key_controller_spec.rb @@ -30,6 +30,7 @@ def assert_personal_key_generated_for_profiles(*profile_pii_pairs) let(:applicant) { Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE } let(:password) { 'sekrit phrase' } let(:user) { create(:user, :fully_registered, password: password) } + let(:is_enhanced_ipp) { false } # Most (but not all) of these tests assume that a profile has been minted # from the data in idv_session. Set this to false to prevent this behavior @@ -68,7 +69,7 @@ def assert_personal_key_generated_for_profiles(*profile_pii_pairs) idv_session.applicant = applicant if mint_profile_from_idv_session - idv_session.create_profile_from_applicant_with_password(password) + idv_session.create_profile_from_applicant_with_password(password, is_enhanced_ipp) end end diff --git a/spec/controllers/idv/verify_info_controller_spec.rb b/spec/controllers/idv/verify_info_controller_spec.rb index 93ee6516bf1..5bef7b24c89 100644 --- a/spec/controllers/idv/verify_info_controller_spec.rb +++ b/spec/controllers/idv/verify_info_controller_spec.rb @@ -273,7 +273,6 @@ same_address_as_id: true, should_proof_state_id: true, ).adjudicated_result.to_h - adjudicated_result[:context].delete(:sp_costs_added) document_capture_session.create_proofing_session diff --git a/spec/features/idv/analytics_spec.rb b/spec/features/idv/analytics_spec.rb index a87a9792f7f..9b4cc3cd9b1 100644 --- a/spec/features/idv/analytics_spec.rb +++ b/spec/features/idv/analytics_spec.rb @@ -45,6 +45,92 @@ base_proofing_components.merge(address_check: 'gpo_letter') end + let(:state_id_resolution) do + { success: true, + errors: {}, + exception: nil, + mva_exception: nil, + requested_attributes: {}, + timed_out: false, + transaction_id: 'state-id-mock-transaction-id-456', + vendor_name: 'StateIdMock', + verified_attributes: [], + state: 'MT', + state_id_jurisdiction: 'ND', + state_id_number: '#############' } + end + + let(:resolution_block) do + { success: true, + errors: {}, + exception: nil, + timed_out: false, + transaction_id: 'resolution-mock-transaction-id-123', + reference: 'aaa-bbb-ccc', + can_pass_with_additional_verification: false, + attributes_requiring_additional_verification: [], + vendor_name: 'ResolutionMock', + vendor_workflow: nil } + end + + let(:base_proofing_results) do + { + exception: nil, + ssn_is_unique: true, + timed_out: false, + threatmetrix_review_status: 'pass', + context: { + device_profiling_adjudication_reason: 'device_profiling_result_pass', + resolution_adjudication_reason: 'pass_resolution_and_state_id', + should_proof_state_id: true, + stages: { + resolution: resolution_block, + residential_address: { attributes_requiring_additional_verification: [], + can_pass_with_additional_verification: false, + errors: {}, + exception: nil, + reference: '', + success: true, + timed_out: false, + transaction_id: '', + vendor_name: 'ResidentialAddressNotRequired', + vendor_workflow: nil }, + state_id: state_id_resolution, + threatmetrix: threatmetrix_response, + }, + }, + } + end + + let(:in_person_path_proofing_results) do + { + exception: nil, + ssn_is_unique: true, + timed_out: false, + threatmetrix_review_status: 'pass', + context: { + device_profiling_adjudication_reason: 'device_profiling_result_pass', + resolution_adjudication_reason: 'pass_resolution_and_state_id', + should_proof_state_id: true, + stages: { + resolution: resolution_block, + residential_address: { errors: {}, + exception: nil, + reference: 'aaa-bbb-ccc', + success: true, + timed_out: false, + transaction_id: 'resolution-mock-transaction-id-123', + can_pass_with_additional_verification: false, + attributes_requiring_additional_verification: [], + vendor_name: 'ResolutionMock', + vendor_workflow: nil }, + state_id: state_id_resolution, + threatmetrix: threatmetrix_response, + }, + }, + } + end + # rubocop:disable Layout/LineLength # rubocop:disable Layout/MultilineHashKeyLineBreaks @@ -113,7 +199,7 @@ }, 'IdV: doc auth verify proofing results' => { success: true, errors: {}, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', ssn_is_unique: true, step: 'verify', acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil, - proofing_results: { exception: nil, timed_out: false, threatmetrix_review_status: 'pass', context: { device_profiling_adjudication_reason: 'device_profiling_result_pass', resolution_adjudication_reason: 'pass_resolution_and_state_id', should_proof_state_id: true, sp_costs_added: true, stages: { resolution: { success: true, errors: {}, exception: nil, timed_out: false, transaction_id: 'resolution-mock-transaction-id-123', reference: 'aaa-bbb-ccc', can_pass_with_additional_verification: false, attributes_requiring_additional_verification: [], vendor_name: 'ResolutionMock', vendor_workflow: nil }, residential_address: { attributes_requiring_additional_verification: [], can_pass_with_additional_verification: false, errors: {}, exception: nil, reference: '', success: true, timed_out: false, transaction_id: '', vendor_name: 'ResidentialAddressNotRequired', vendor_workflow: nil }, state_id: { success: true, errors: {}, exception: nil, mva_exception: nil, requested_attributes: {}, timed_out: false, transaction_id: 'state-id-mock-transaction-id-456', vendor_name: 'StateIdMock', verified_attributes: [], state: 'MT', state_id_jurisdiction: 'ND', state_id_number: '#############' }, threatmetrix: threatmetrix_response } } } + proofing_results: base_proofing_results }, 'IdV: phone of record visited' => { acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil, @@ -239,7 +325,7 @@ }, 'IdV: doc auth verify proofing results' => { success: true, errors: {}, flow_path: 'hybrid', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', ssn_is_unique: true, step: 'verify', acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil, - proofing_results: { exception: nil, timed_out: false, threatmetrix_review_status: 'pass', context: { device_profiling_adjudication_reason: 'device_profiling_result_pass', resolution_adjudication_reason: 'pass_resolution_and_state_id', should_proof_state_id: true, sp_costs_added: true, stages: { resolution: { success: true, errors: {}, exception: nil, timed_out: false, transaction_id: 'resolution-mock-transaction-id-123', reference: 'aaa-bbb-ccc', can_pass_with_additional_verification: false, attributes_requiring_additional_verification: [], vendor_name: 'ResolutionMock', vendor_workflow: nil }, residential_address: { attributes_requiring_additional_verification: [], can_pass_with_additional_verification: false, errors: {}, exception: nil, reference: '', success: true, timed_out: false, transaction_id: '', vendor_name: 'ResidentialAddressNotRequired', vendor_workflow: nil }, state_id: { success: true, errors: {}, exception: nil, mva_exception: nil, requested_attributes: {}, timed_out: false, transaction_id: 'state-id-mock-transaction-id-456', vendor_name: 'StateIdMock', verified_attributes: [], state: 'MT', state_id_jurisdiction: 'ND', state_id_number: '#############' }, threatmetrix: threatmetrix_response } } } + proofing_results: base_proofing_results }, 'IdV: phone of record visited' => { acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil, @@ -362,7 +448,7 @@ }, 'IdV: doc auth verify proofing results' => { success: true, errors: {}, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', ssn_is_unique: true, step: 'verify', acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil, - proofing_results: { exception: nil, timed_out: false, threatmetrix_review_status: 'pass', context: { device_profiling_adjudication_reason: 'device_profiling_result_pass', resolution_adjudication_reason: 'pass_resolution_and_state_id', should_proof_state_id: true, sp_costs_added: true, stages: { resolution: { success: true, errors: {}, exception: nil, timed_out: false, transaction_id: 'resolution-mock-transaction-id-123', reference: 'aaa-bbb-ccc', can_pass_with_additional_verification: false, attributes_requiring_additional_verification: [], vendor_name: 'ResolutionMock', vendor_workflow: nil }, residential_address: { attributes_requiring_additional_verification: [], can_pass_with_additional_verification: false, errors: {}, exception: nil, reference: '', success: true, timed_out: false, transaction_id: '', vendor_name: 'ResidentialAddressNotRequired', vendor_workflow: nil }, state_id: { success: true, errors: {}, exception: nil, mva_exception: nil, requested_attributes: {}, timed_out: false, transaction_id: 'state-id-mock-transaction-id-456', vendor_name: 'StateIdMock', verified_attributes: [], state: 'MT', state_id_jurisdiction: 'ND', state_id_number: '#############' }, threatmetrix: threatmetrix_response } } } + proofing_results: base_proofing_results }, 'IdV: phone of record visited' => { acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil, @@ -480,7 +566,7 @@ }, 'IdV: doc auth verify proofing results' => { success: true, errors: {}, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'In Person Proofing', ssn_is_unique: true, step: 'verify', acuant_sdk_upgrade_ab_test_bucket: :default, same_address_as_id: false, skip_hybrid_handoff: nil, - proofing_results: { exception: nil, timed_out: false, threatmetrix_review_status: 'pass', context: { device_profiling_adjudication_reason: 'device_profiling_result_pass', resolution_adjudication_reason: 'pass_resolution_and_state_id', should_proof_state_id: true, sp_costs_added: true, stages: { resolution: { success: true, errors: {}, exception: nil, timed_out: false, transaction_id: 'resolution-mock-transaction-id-123', reference: 'aaa-bbb-ccc', can_pass_with_additional_verification: false, attributes_requiring_additional_verification: [], vendor_name: 'ResolutionMock', vendor_workflow: nil }, residential_address: { errors: {}, exception: nil, reference: 'aaa-bbb-ccc', success: true, timed_out: false, transaction_id: 'resolution-mock-transaction-id-123', can_pass_with_additional_verification: false, attributes_requiring_additional_verification: [], vendor_name: 'ResolutionMock', vendor_workflow: nil }, state_id: { success: true, errors: {}, exception: nil, mva_exception: nil, requested_attributes: {}, timed_out: false, transaction_id: 'state-id-mock-transaction-id-456', vendor_name: 'StateIdMock', verified_attributes: [], state: 'MT', state_id_jurisdiction: 'ND', state_id_number: '#############' }, threatmetrix: threatmetrix_response } } } + proofing_results: in_person_path_proofing_results }, 'IdV: phone confirmation form' => { success: true, errors: {}, error_details: nil, phone_type: :mobile, types: [:fixed_or_mobile], carrier: 'Test Mobile Carrier', country_code: 'US', area_code: '202', acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: nil, otp_delivery_preference: 'sms', @@ -613,7 +699,7 @@ }, 'IdV: doc auth verify proofing results' => { success: true, errors: {}, flow_path: 'standard', address_edited: false, address_line2_present: false, analytics_id: 'Doc Auth', ssn_is_unique: true, step: 'verify', acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: anything, - proofing_results: { exception: nil, timed_out: false, threatmetrix_review_status: 'pass', context: { device_profiling_adjudication_reason: 'device_profiling_result_pass', resolution_adjudication_reason: 'pass_resolution_and_state_id', should_proof_state_id: true, sp_costs_added: true, stages: { resolution: { success: true, errors: {}, exception: nil, timed_out: false, transaction_id: 'resolution-mock-transaction-id-123', reference: 'aaa-bbb-ccc', can_pass_with_additional_verification: false, attributes_requiring_additional_verification: [], vendor_name: 'ResolutionMock', vendor_workflow: nil }, residential_address: { attributes_requiring_additional_verification: [], can_pass_with_additional_verification: false, errors: {}, exception: nil, reference: '', success: true, timed_out: false, transaction_id: '', vendor_name: 'ResidentialAddressNotRequired', vendor_workflow: nil }, state_id: { success: true, errors: {}, exception: nil, mva_exception: nil, requested_attributes: {}, timed_out: false, transaction_id: 'state-id-mock-transaction-id-456', vendor_name: 'StateIdMock', verified_attributes: [], state: 'MT', state_id_jurisdiction: 'ND', state_id_number: '#############' }, threatmetrix: threatmetrix_response } } } + proofing_results: base_proofing_results }, 'IdV: phone of record visited' => { acuant_sdk_upgrade_ab_test_bucket: :default, skip_hybrid_handoff: anything, diff --git a/spec/features/idv/doc_auth/verify_info_step_spec.rb b/spec/features/idv/doc_auth/verify_info_step_spec.rb index 41040492220..f002b2c5005 100644 --- a/spec/features/idv/doc_auth/verify_info_step_spec.rb +++ b/spec/features/idv/doc_auth/verify_info_step_spec.rb @@ -249,29 +249,17 @@ let(:mock_state_id_jurisdiction) do [Idp::Constants::MOCK_IDV_APPLICANT[:state_id_jurisdiction]] end - let(:proof_resolution_args) do - { - trace_id: anything, - threatmetrix_session_id: anything, - request_ip: kind_of(String), - ipp_enrollment_in_progress: false, - } - end context 'when the user lives in an AAMVA supported state' do it 'performs a resolution and state ID check' do allow(IdentityConfig.store).to receive(:aamva_supported_jurisdictions).and_return( mock_state_id_jurisdiction, ) - expect_any_instance_of(Idv::Agent). - to receive(:proof_resolution). - with( - anything, - should_proof_state_id: true, - user_id: user.id, - **proof_resolution_args, - ). - and_call_original + expect_any_instance_of(Proofing::Mock::StateIdMockClient).to receive(:proof).with( + hash_including( + **Idp::Constants::MOCK_IDV_APPLICANT, + ), + ).and_call_original complete_ssn_step complete_verify_step @@ -284,15 +272,7 @@ IdentityConfig.store.aamva_supported_jurisdictions - mock_state_id_jurisdiction, ) - expect_any_instance_of(Idv::Agent). - to receive(:proof_resolution). - with( - anything, - should_proof_state_id: false, - user_id: user.id, - **proof_resolution_args, - ). - and_call_original + expect_any_instance_of(Proofing::Mock::StateIdMockClient).to_not receive(:proof) complete_ssn_step complete_verify_step diff --git a/spec/forms/gpo_verify_form_spec.rb b/spec/forms/gpo_verify_form_spec.rb index 771d059e97a..774213f7805 100644 --- a/spec/forms/gpo_verify_form_spec.rb +++ b/spec/forms/gpo_verify_form_spec.rb @@ -19,6 +19,7 @@ ) end let(:proofing_components) { nil } + let(:is_enhanced_ipp) { false } before do next if pending_profile.blank? @@ -36,7 +37,7 @@ let(:entered_otp) { nil } it 'is invalid' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.success?).to eq(false) expect(result.errors[:otp]).to eq [t('errors.messages.blank')] end @@ -47,7 +48,7 @@ let(:user) { build_stubbed(:user) } it 'is invalid' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.success?).to eq(false) expect(result.errors[:base]).to eq [t('errors.messages.no_pending_profile')] end @@ -59,7 +60,7 @@ let(:otp) { 'ABCDEF12345' } it 'is valid' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.success?).to eq(true) end end @@ -69,7 +70,7 @@ let(:otp) { '0000000000' } it 'is valid' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.success?).to eq(true) end end @@ -79,7 +80,7 @@ let(:entered_otp) { 'wrong' } it 'is invalid' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.success?).to eq(false) expect(result.errors[:otp]).to eq [t('errors.messages.confirmation_code_incorrect')] end @@ -98,7 +99,7 @@ end it 'is invalid' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.success?).to eq(false) expect(subject.errors[:otp]).to eq [t('errors.messages.gpo_otp_expired')] end @@ -108,7 +109,7 @@ allow(subject).to receive(:user_can_request_another_letter?).and_return(false) end it 'is invalid and uses different messaging' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.success?).to eq(false) expect(subject.errors[:otp]).to eq [ t('errors.messages.gpo_otp_expired_and_cannot_request_another'), @@ -121,20 +122,20 @@ describe '#submit' do context 'correct OTP' do it 'returns true' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.success?).to eq true end it 'activates the pending profile' do expect(pending_profile).to_not be_active - subject.submit + subject.submit(is_enhanced_ipp) expect(pending_profile.reload).to be_active end it 'logs the date the code was sent at' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) confirmation_code = pending_profile.gpo_confirmation_codes.last expect(result.to_h[:enqueued_at]).to eq(confirmation_code.code_sent_at) @@ -159,7 +160,7 @@ end it 'sets profile to pending in person verification' do - subject.submit + subject.submit(is_enhanced_ipp) pending_profile.reload expect(pending_profile).not_to be_active @@ -168,7 +169,7 @@ end it 'updates establishing in-person enrollment to pending' do - subject.submit + subject.submit(is_enhanced_ipp) establishing_enrollment.reload @@ -197,7 +198,7 @@ end it 'changes profile from pending to active' do - subject.submit + subject.submit(is_enhanced_ipp) pending_profile.reload expect(pending_profile).to be_active @@ -217,19 +218,19 @@ end it 'returns true' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.success?).to eq true end it 'does not activate the users profile' do - subject.submit + subject.submit(is_enhanced_ipp) profile = user.profiles.first expect(profile.active).to eq(false) expect(profile.fraud_review_pending?).to eq(true) end it 'notes that threatmetrix failed' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.extra).to include(fraud_check_failed: true) end @@ -239,19 +240,19 @@ end it 'returns true' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.success?).to eq true end it 'does activate the users profile' do - subject.submit + subject.submit(is_enhanced_ipp) profile = user.profiles.first expect(profile.active).to eq(true) expect(profile.deactivation_reason).to eq(nil) end it 'notes that threatmetrix failed' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.extra).to include(fraud_check_failed: true) end end @@ -262,7 +263,7 @@ let(:entered_otp) { 'wrong' } it 'clears form' do - subject.submit + subject.submit(is_enhanced_ipp) expect(subject.otp).to be_nil end @@ -293,7 +294,7 @@ let(:entered_otp) { first_otp } it 'logs which letter and letter count' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.to_h[:which_letter]).to eq(1) expect(result.to_h[:letter_count]).to eq(3) @@ -304,7 +305,7 @@ let(:entered_otp) { second_otp } it 'logs which letter and letter count' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.to_h[:which_letter]).to eq(2) expect(result.to_h[:letter_count]).to eq(3) @@ -315,12 +316,30 @@ let(:entered_code) { third_otp } it 'logs which letter and letter count' do - result = subject.submit + result = subject.submit(is_enhanced_ipp) expect(result.to_h[:which_letter]).to eq(3) expect(result.to_h[:letter_count]).to eq(3) end end end + + context 'when the user is going through enhanced ipp' do + let(:is_enhanced_ipp) { true } + let!(:establishing_enrollment) do + create( + :in_person_enrollment, + :establishing, + profile: pending_profile, + user: user, + ) + end + it 'sends the correct information for scheduling an in person enrollment' do + expect(UspsInPersonProofing::EnrollmentHelper).to receive(:schedule_in_person_enrollment). + with(user: anything, pii: anything, is_enhanced_ipp: is_enhanced_ipp) + + subject.submit(is_enhanced_ipp) + end + end end end diff --git a/spec/jobs/resolution_proofing_job_spec.rb b/spec/jobs/resolution_proofing_job_spec.rb index f6d5bd89db2..d4c2db323c2 100644 --- a/spec/jobs/resolution_proofing_job_spec.rb +++ b/spec/jobs/resolution_proofing_job_spec.rb @@ -10,7 +10,6 @@ let(:document_capture_session) do DocumentCaptureSession.new(result_id: SecureRandom.hex, uuid: SecureRandom.uuid) end - let(:should_proof_state_id) { true } let(:trace_id) { SecureRandom.uuid } let(:user) { create(:user, :fully_registered) } let(:service_provider) { create(:service_provider, app_id: 'fake-app-id') } @@ -35,7 +34,6 @@ subject(:perform) do instance.perform( result_id: document_capture_session.result_id, - should_proof_state_id: should_proof_state_id, encrypted_arguments: encrypted_arguments, trace_id: trace_id, user_id: user.id, @@ -46,6 +44,32 @@ ) end + context 'ssn_is_unique attribute' do + context 'when the SSN is unique' do + it 'sets ssn_is_unique: true on the result' do + stub_vendor_requests + perform + + result = document_capture_session.load_proofing_result[:result] + expect(result[:ssn_is_unique]).to eq(true) + end + end + + context 'when the SSN is not unique' do + before do + create(:profile, pii: Idp::Constants::MOCK_IDV_APPLICANT_WITH_SSN) + end + + it 'sets ssn_is_unique: false on the result' do + stub_vendor_requests + perform + + result = document_capture_session.load_proofing_result[:result] + expect(result[:ssn_is_unique]).to eq(false) + end + end + end + context 'all of the vendor requests pass' do it 'stores a successful result' do stub_vendor_requests @@ -249,7 +273,9 @@ end context 'in a state where AAMVA is not supported' do - let(:should_proof_state_id) { false } + let(:pii) do + Idp::Constants::MOCK_IDV_APPLICANT_SAME_ADDRESS_AS_ID.merge(state_id_jurisdiction: 'NY') + end it 'does not make an AAMVA request' do stub_vendor_requests @@ -332,7 +358,6 @@ subject(:perform) do instance.perform( result_id: document_capture_session.result_id, - should_proof_state_id: should_proof_state_id, encrypted_arguments: encrypted_arguments, trace_id: trace_id, user_id: user.id, diff --git a/spec/lib/reporting/identity_verification_report_spec.rb b/spec/lib/reporting/identity_verification_report_spec.rb index 742e062cf03..1fc617d509a 100644 --- a/spec/lib/reporting/identity_verification_report_spec.rb +++ b/spec/lib/reporting/identity_verification_report_spec.rb @@ -80,11 +80,14 @@ ['Image Submitted', 5], [], ['Workflow completed', 4], - ['Workflow completed - Verified', 1], - ['Workflow completed - Total Pending', 3], + ['Workflow completed - With Phone Number', 1], + ['Workflow completed - With Phone Number - Fraud Review', 1], ['Workflow completed - GPO Pending', 1], + ['Workflow completed - GPO Pending - Fraud Review', 0], ['Workflow completed - In-Person Pending', 1], - ['Workflow completed - Fraud Review Pending', 1], + ['Workflow completed - In-Person Pending - Fraud Review', 0], + ['Workflow completed - GPO + In-Person Pending', 0], + ['Workflow completed - GPO + In-Person Pending - Fraud Review', 0], [], ['Fraud review rejected', 1], ['Successfully Verified', 4], @@ -123,11 +126,14 @@ ['Image Submitted', '5'], [], ['Workflow completed', '4'], - ['Workflow completed - Verified', '1'], - ['Workflow completed - Total Pending', '3'], + ['Workflow completed - With Phone Number', '1'], + ['Workflow completed - With Phone Number - Fraud Review', '1'], ['Workflow completed - GPO Pending', '1'], + ['Workflow completed - GPO Pending - Fraud Review', '0'], ['Workflow completed - In-Person Pending', '1'], - ['Workflow completed - Fraud Review Pending', '1'], + ['Workflow completed - In-Person Pending - Fraud Review', '0'], + ['Workflow completed - GPO + In-Person Pending', '0'], + ['Workflow completed - GPO + In-Person Pending - Fraud Review', '0'], [], ['Fraud review rejected', '1'], ['Successfully Verified', '4'], diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb index 240d1b1a0ed..7134e098494 100644 --- a/spec/mailers/previews/user_mailer_preview.rb +++ b/spec/mailers/previews/user_mailer_preview.rb @@ -173,6 +173,14 @@ def in_person_deadline_passed def in_person_ready_to_verify UserMailer.with(user: user, email_address: email_address_record).in_person_ready_to_verify( enrollment: in_person_enrollment, + is_enhanced_ipp: false, + ) + end + + def in_person_ready_to_verify_enhanced_ipp_enabled + UserMailer.with(user: user, email_address: email_address_record).in_person_ready_to_verify( + enrollment: in_person_enrollment, + is_enhanced_ipp: true, ) end diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index a1b00c28697..39fc0003001 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -5,6 +5,7 @@ let(:email_address) { user.email_addresses.first } let(:banned_email) { 'banned_email+123abc@gmail.com' } let(:banned_email_address) { create(:email_address, email: banned_email, user: user) } + let(:is_enhanced_ipp) { false } describe '#validate_user_and_email_address' do let(:mail) { UserMailer.with(user: user, email_address: email_address).signup_with_your_email } @@ -604,6 +605,7 @@ def expect_email_body_to_have_help_and_contact_links let(:mail) do UserMailer.with(user: user, email_address: email_address).in_person_ready_to_verify( enrollment: enrollment, + is_enhanced_ipp:, ) end @@ -659,11 +661,157 @@ def expect_email_body_to_have_help_and_contact_links end end - it 'renders the body' do - expect(mail.html_part.body). - to have_content( - t('in_person_proofing.process.state_id.heading'), + context 'For In-Person Proofing (IPP)' do + context 'template displays modified content' do + it 'conditionally renders content in the what to expect section applicable to IPP' do + aggregate_failures do + [ + t('in_person_proofing.headings.barcode'), + t('in_person_proofing.process.state_id.heading'), + t('in_person_proofing.process.state_id.info'), + ].each do |copy| + Array(copy).each do |part| + expect(mail.html_part.body).to have_content(part) + end + end + end + end + end + + it 'renders Questions? and Learn more link only once' do + expect(mail.html_part.body).to have_content( + t('in_person_proofing.body.barcode.questions'), + ).once + expect(mail.html_part.body).to have_link( + t('in_person_proofing.body.barcode.learn_more'), + href: MarketingSite.help_center_article_url( + category: 'verify-your-identity', + article: 'verify-your-identity-in-person', + ), + ).once + end + + it 'template does not display Enhanced In-Person Proofing specific content' do + aggregate_failures do + [ + t('in_person_proofing.headings.barcode_eipp'), + t('in_person_proofing.process.state_id.heading_eipp'), + t('in_person_proofing.process.state_id.info_eipp'), + t('in_person_proofing.headings.barcode_what_to_bring'), + t('in_person_proofing.body.barcode.what_to_bring'), + t('in_person_proofing.process.eipp_bring_id.heading'), + t('in_person_proofing.process.eipp_bring_id.info'), + t('in_person_proofing.process.eipp_what_to_bring.heading'), + t('in_person_proofing.process.eipp_what_to_bring.info'), + t('in_person_proofing.process.eipp_state_id_passport.heading'), + t('in_person_proofing.process.eipp_state_id_passport.info'), + t('in_person_proofing.process.eipp_state_id_military_id.heading'), + t('in_person_proofing.process.eipp_state_id_military_id.info'), + t('in_person_proofing.process.eipp_state_id_supporting_docs.heading'), + t('in_person_proofing.process.eipp_state_id_supporting_docs.info'), + ].each do |copy| + Array(copy).each do |part| + expect(mail.html_part.body).to_not have_content(part) + end + end + end + + t('in_person_proofing.process.eipp_state_id_supporting_docs.info_list').each do |item| + expect(mail.html_part.body).to_not have_content(strip_tags(item)) + end + end + end + + context 'For Enhanced In-Person Proofing (Enhanced IPP)' do + let(:is_enhanced_ipp) { true } + let(:mail) do + UserMailer.with(user: user, email_address: email_address).in_person_ready_to_verify( + enrollment: enrollment, + is_enhanced_ipp:, ) + end + + context 'template displays modified content' do + it 'conditionally renders content in the what to expect section + applicable to Enhanced In-Person Proofing (Enhanced IPP)' do + aggregate_failures do + [ + t('in_person_proofing.headings.barcode_eipp'), + t('in_person_proofing.process.state_id.heading_eipp'), + t('in_person_proofing.process.state_id.info_eipp'), + ].each do |copy| + Array(copy).each do |part| + expect(mail.html_part.body).to have_content(part) + end + end + end + end + end + + it 'renders Questions? and Learn more link only once' do + expect(mail.html_part.body).to have_content( + t('in_person_proofing.body.barcode.questions'), + ).once + expect(mail.html_part.body).to have_link( + t('in_person_proofing.body.barcode.learn_more'), + href: MarketingSite.help_center_article_url( + category: 'verify-your-identity', + article: 'verify-your-identity-in-person', + ), + ).once + end + + context 'template displays additional Enhanced In-Person Proofing specific content' do + it 'renders What to bring section' do + aggregate_failures do + [ + t('in_person_proofing.headings.barcode_what_to_bring'), + t('in_person_proofing.body.barcode.what_to_bring'), + ].each do |copy| + Array(copy).each do |part| + expect(mail.html_part.body).to have_content(part) + end + end + end + end + + it 'renders Option 1 content' do + aggregate_failures do + [ + t('in_person_proofing.process.eipp_bring_id.heading'), + t('in_person_proofing.process.eipp_bring_id.info'), + ].each do |copy| + Array(copy).each do |part| + expect(mail.html_part.body).to have_content(part) + end + end + end + end + + it 'renders Option 2 content' do + aggregate_failures do + [ + t('in_person_proofing.process.eipp_what_to_bring.heading'), + t('in_person_proofing.process.eipp_what_to_bring.info'), + t('in_person_proofing.process.eipp_state_id_passport.heading'), + t('in_person_proofing.process.eipp_state_id_passport.info'), + t('in_person_proofing.process.eipp_state_id_military_id.heading'), + t('in_person_proofing.process.eipp_state_id_military_id.info'), + t('in_person_proofing.process.eipp_state_id_supporting_docs.heading'), + t('in_person_proofing.process.eipp_state_id_supporting_docs.info'), + ].each do |copy| + Array(copy).each do |part| + expect(mail.html_part.body).to have_content(part) + end + + t('in_person_proofing.process.eipp_state_id_supporting_docs.info_list'). + each do |item| + expect(mail.html_part.body).to have_content(strip_tags(item)) + end + end + end + end + end end end diff --git a/spec/policies/idv/flow_policy_spec.rb b/spec/policies/idv/flow_policy_spec.rb index b3fe49dfa26..885649250d4 100644 --- a/spec/policies/idv/flow_policy_spec.rb +++ b/spec/policies/idv/flow_policy_spec.rb @@ -6,6 +6,7 @@ include FlowPolicyHelper let(:user) { create(:user) } + let(:is_enhanced_ipp) { false } let(:user_session) { { 'idv/in_person' => {} } } @@ -312,12 +313,13 @@ end context 'preconditions for personal_key are present' do + let(:is_enhanced_ipp) { false } let(:password) { 'sekrit phrase' } context 'user has a verify by mail pending profile' do it 'returns personal_key' do stub_up_to(:request_letter, idv_session: idv_session) idv_session.gpo_code_verified = true - idv_session.create_profile_from_applicant_with_password('password') + idv_session.create_profile_from_applicant_with_password('password', is_enhanced_ipp) expect(subject.info_for_latest_step.key).to eq(:personal_key) expect(subject.controller_allowed?(controller: Idv::PersonalKeyController)).to be @@ -325,9 +327,10 @@ end context 'user has a newly activated profile' do + let(:is_enhanced_ipp) { false } it 'returns personal_key' do stub_up_to(:otp_verification, idv_session: idv_session) - idv_session.create_profile_from_applicant_with_password('password') + idv_session.create_profile_from_applicant_with_password('password', is_enhanced_ipp) expect(subject.info_for_latest_step.key).to eq(:personal_key) expect(subject.controller_allowed?(controller: Idv::PersonalKeyController)).to be diff --git a/spec/services/gpo_reminder_sender_spec.rb b/spec/services/gpo_reminder_sender_spec.rb index ec07520a29c..797937626b7 100644 --- a/spec/services/gpo_reminder_sender_spec.rb +++ b/spec/services/gpo_reminder_sender_spec.rb @@ -158,6 +158,7 @@ def set_reminder_sent_at(to_time) end context 'but the user has completed gpo verification' do + let(:is_enhanced_ipp) { false } before do otp = 'ABC123' pending_profile = user.gpo_verification_pending_profile @@ -175,7 +176,7 @@ def set_reminder_sent_at(to_time) user: user, pii: Idp::Constants::MOCK_IDV_APPLICANT_WITH_PHONE, otp: otp, - ).submit + ).submit(is_enhanced_ipp) end include_examples 'sends no emails' diff --git a/spec/services/idv/agent_spec.rb b/spec/services/idv/agent_spec.rb index ed062547aba..f3c701a9206 100644 --- a/spec/services/idv/agent_spec.rb +++ b/spec/services/idv/agent_spec.rb @@ -9,7 +9,6 @@ end describe 'instance' do - let(:applicant) { { foo: 'bar' } } let(:trace_id) { SecureRandom.uuid } let(:request_ip) { Faker::Internet.ip_v4_address } let(:issuer) { 'fake-issuer' } @@ -17,8 +16,6 @@ let(:app_id) { 'fake-app-id' } let(:ipp_enrollment_in_progress) { false } - let(:agent) { Idv::Agent.new(applicant) } - before do ServiceProvider.create( issuer: issuer, @@ -30,14 +27,13 @@ describe '#proof_resolution' do let(:document_capture_session) { DocumentCaptureSession.new(result_id: SecureRandom.hex) } - context 'proofing state_id enabled' do + context 'proofing in an AAMVA state' do it 'does not proof state_id if resolution fails' do agent = Idv::Agent.new( Idp::Constants::MOCK_IDV_APPLICANT.merge(ssn: '444-55-6666'), ) agent.proof_resolution( document_capture_session, - should_proof_state_id: true, trace_id: trace_id, user_id: user.id, threatmetrix_session_id: nil, @@ -54,7 +50,6 @@ agent = Idv::Agent.new(Idp::Constants::MOCK_IDV_APPLICANT_WITH_SSN) agent.proof_resolution( document_capture_session, - should_proof_state_id: true, trace_id: trace_id, user_id: user.id, threatmetrix_session_id: nil, @@ -76,11 +71,12 @@ context 'proofing state_id disabled' do it 'does not proof state_id if resolution fails' do agent = Idv::Agent.new( - Idp::Constants::MOCK_IDV_APPLICANT.merge(ssn: '444-55-6666'), + Idp::Constants::MOCK_IDV_APPLICANT.merge( + ssn: '444-55-6666', state_id_jurisdiction: 'NY', + ), ) agent.proof_resolution( document_capture_session, - should_proof_state_id: false, trace_id: trace_id, user_id: user.id, threatmetrix_session_id: nil, @@ -93,10 +89,13 @@ end it 'does not proof state_id if resolution succeeds' do - agent = Idv::Agent.new(Idp::Constants::MOCK_IDV_APPLICANT_WITH_SSN) + agent = Idv::Agent.new( + Idp::Constants::MOCK_IDV_APPLICANT_WITH_SSN.merge( + state_id_jurisdiction: 'NY', + ), + ) agent.proof_resolution( document_capture_session, - should_proof_state_id: false, trace_id: trace_id, user_id: user.id, threatmetrix_session_id: nil, @@ -110,27 +109,26 @@ transaction_id: Proofing::Mock::StateIdMockClient::TRANSACTION_ID, ) end + end - it 'returns a successful result if SSN does not start with 900 but is in SSN allowlist' do - agent = Idv::Agent.new( - Idp::Constants::MOCK_IDV_APPLICANT.merge(ssn: '999-99-9999'), - ) + it 'returns a successful result if SSN does not start with 900 but is in SSN allowlist' do + agent = Idv::Agent.new( + Idp::Constants::MOCK_IDV_APPLICANT.merge(ssn: '999-99-9999'), + ) - agent.proof_resolution( - document_capture_session, - should_proof_state_id: false, - trace_id: trace_id, - user_id: user.id, - threatmetrix_session_id: nil, - request_ip: request_ip, - ipp_enrollment_in_progress: ipp_enrollment_in_progress, - ) - result = document_capture_session.load_proofing_result.result + agent.proof_resolution( + document_capture_session, + trace_id: trace_id, + user_id: user.id, + threatmetrix_session_id: nil, + request_ip: request_ip, + ipp_enrollment_in_progress: ipp_enrollment_in_progress, + ) + result = document_capture_session.load_proofing_result.result - expect(result).to include( - success: true, - ) - end + expect(result).to include( + success: true, + ) end it 'passes the correct service provider to the ResolutionProofingJob' do @@ -148,7 +146,6 @@ agent.proof_resolution( document_capture_session, - should_proof_state_id: true, trace_id: trace_id, user_id: user.id, threatmetrix_session_id: nil, @@ -164,7 +161,6 @@ agent.proof_resolution( document_capture_session, - should_proof_state_id: true, trace_id: trace_id, user_id: user.id, threatmetrix_session_id: nil, @@ -187,7 +183,6 @@ agent = Idv::Agent.new(Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS) agent.proof_resolution( document_capture_session, - should_proof_state_id: true, trace_id: trace_id, user_id: user.id, threatmetrix_session_id: nil, diff --git a/spec/services/idv/session_spec.rb b/spec/services/idv/session_spec.rb index 59f17f4365d..b02a08fba08 100644 --- a/spec/services/idv/session_spec.rb +++ b/spec/services/idv/session_spec.rb @@ -3,6 +3,7 @@ RSpec.describe Idv::Session, allowed_extra_analytics: [:*] do let(:user) { create(:user) } let(:user_session) { {} } + let(:is_enhanced_ipp) { false } subject do Idv::Session.new(user_session: user_session, current_user: user, service_provider: nil) @@ -128,6 +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 @@ -144,7 +146,7 @@ now = Time.zone.now subject.user_phone_confirmation = true - subject.create_profile_from_applicant_with_password(user.password) + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) profile = subject.profile expect(profile.activated_at).to eq now @@ -163,7 +165,7 @@ it 'does not complete the profile if the user has not completed OTP phone confirmation' do subject.user_phone_confirmation = nil - subject.create_profile_from_applicant_with_password(user.password) + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) profile = subject.profile expect(profile.activated_at).to eq nil @@ -192,7 +194,7 @@ end it 'sets profile to pending in person verification' do - subject.create_profile_from_applicant_with_password(user.password) + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) profile = subject.profile expect(profile.activated_at).to eq nil @@ -211,9 +213,11 @@ it 'creates a USPS enrollment' do expect(UspsInPersonProofing::EnrollmentHelper). to receive(:schedule_in_person_enrollment). - with(user, Pii::Attributes.new_from_hash(subject.applicant), opt_in_param) + with(user: user, pii: Pii::Attributes.new_from_hash(subject.applicant), + is_enhanced_ipp: is_enhanced_ipp, + opt_in: opt_in_param) - subject.create_profile_from_applicant_with_password(user.password) + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) profile = enrollment.reload.profile expect(profile).to eq(user.profiles.last) @@ -235,7 +239,7 @@ end it 'sets profile to pending gpo verification' do - subject.create_profile_from_applicant_with_password(user.password) + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) profile = subject.profile expect(profile.activated_at).to eq nil @@ -259,7 +263,7 @@ end it 'does not complete the user profile' do - subject.create_profile_from_applicant_with_password(user.password) + subject.create_profile_from_applicant_with_password(user.password, is_enhanced_ipp) profile = subject.profile expect(profile.activated_at).to eq nil diff --git a/spec/services/proofing/resolution/progressive_proofer_spec.rb b/spec/services/proofing/resolution/progressive_proofer_spec.rb index 7b80ff5a010..17fcf87abb3 100644 --- a/spec/services/proofing/resolution/progressive_proofer_spec.rb +++ b/spec/services/proofing/resolution/progressive_proofer_spec.rb @@ -52,7 +52,6 @@ address2: applicant_pii[:identity_doc_address2], city: applicant_pii[:identity_doc_city], state: applicant_pii[:identity_doc_address_state], - state_id_jurisdiction: applicant_pii[:state_id_jurisdiction], zipcode: applicant_pii[:identity_doc_zipcode], } end @@ -63,7 +62,6 @@ address2: applicant_pii[:address2], city: applicant_pii[:city], state: applicant_pii[:state], - state_id_jurisdiction: applicant_pii[:state_id_jurisdiction], zipcode: applicant_pii[:zipcode], } end @@ -77,7 +75,7 @@ address2: '2nd Address Line', city: 'Best City', zipcode: '12345', - state_id_jurisdiction: 'Virginia', + state_id_jurisdiction: 'VA', address_state: 'VA', state_id_number: '1111111111111', same_address_as_id: 'true', @@ -120,7 +118,6 @@ def block_real_instant_verify_requests applicant_pii: applicant_pii, ipp_enrollment_in_progress: ipp_enrollment_in_progress, request_ip: Faker::Internet.ip_v4_address, - should_proof_state_id: true, threatmetrix_session_id: threatmetrix_session_id, timer: JobHelpers::Timer.new, user_email: Faker::Internet.email, diff --git a/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb b/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb index 6f72187974c..91c905eaf1d 100644 --- a/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb +++ b/spec/services/usps_in_person_proofing/enrollment_helper_spec.rb @@ -22,6 +22,7 @@ 'registration@usps.local.identitysandbox.gov' end let(:proofer) { UspsInPersonProofing::Mock::Proofer.new } + let(:is_enhanced_ipp) { false } before(:each) do stub_request_token @@ -56,7 +57,7 @@ it 'uses a mock proofer' do expect(UspsInPersonProofing::Mock::Proofer).to receive(:new).and_call_original - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) end end @@ -71,7 +72,7 @@ it 'updates the existing enrollment record' do expect(user.in_person_enrollments.length).to eq(1) - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) enrollment.reload # tests that the value of current_address_matches_id on the enrollment corresponds @@ -93,10 +94,10 @@ expect(applicant.zip_code).to eq(Idp::Constants::MOCK_IDV_APPLICANT[:zipcode]) expect(applicant.unique_id).to eq(enrollment.unique_id) - UspsInPersonProofing::Mock::Proofer.new.request_enroll(applicant) + UspsInPersonProofing::Mock::Proofer.new.request_enroll(applicant, is_enhanced_ipp) end - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) end context 'same address as id is false' do @@ -122,10 +123,10 @@ zip_code: Idp::Constants::MOCK_IDV_APPLICANT_STATE_ID_ADDRESS[:identity_doc_zipcode], ) - UspsInPersonProofing::Mock::Proofer.new.request_enroll(applicant) + UspsInPersonProofing::Mock::Proofer.new.request_enroll(applicant, is_enhanced_ipp) end - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) end end end @@ -158,10 +159,10 @@ expect(applicant.email).to eq(usps_ipp_enrollment_status_update_email_address) expect(applicant.unique_id).to eq(enrollment.unique_id) - UspsInPersonProofing::Mock::Proofer.new.request_enroll(applicant) + UspsInPersonProofing::Mock::Proofer.new.request_enroll(applicant, is_enhanced_ipp) end - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) end end @@ -171,15 +172,15 @@ expect(proofer).to receive(:request_enroll) do |applicant| expect(applicant.unique_id).to eq(enrollment.usps_unique_id) - UspsInPersonProofing::Mock::Proofer.new.request_enroll(applicant) + UspsInPersonProofing::Mock::Proofer.new.request_enroll(applicant, is_enhanced_ipp) end - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) end end it 'sets enrollment status to pending and sets established at date and unique id' do - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) expect(user.in_person_enrollments.first.status).to eq(InPersonEnrollment::STATUS_PENDING) expect(user.in_person_enrollments.first.enrollment_established_at).to_not be_nil @@ -189,7 +190,7 @@ context 'event logging' do context 'with no service provider' do it 'logs event' do - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) expect(subject_analytics).to have_logged_event( 'USPS IPPaaS enrollment created', @@ -208,7 +209,7 @@ let(:service_provider) { build(:service_provider, issuer: issuer) } it 'logs event' do - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) expect(subject_analytics).to have_logged_event( 'USPS IPPaaS enrollment created', @@ -235,7 +236,7 @@ it 'does not log the presence of address line 2 only in residential address' do pii['identity_doc_address2'] = nil - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) expect(subject_analytics).to have_logged_event( 'USPS IPPaaS enrollment created', @@ -255,7 +256,7 @@ pii['same_address_as_id'] = false pii['address2'] = nil - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) expect(subject_analytics).to have_logged_event( 'USPS IPPaaS enrollment created', @@ -274,7 +275,7 @@ let(:opt_in) { true } it 'logs user\'s opt-in choice' do - subject.schedule_in_person_enrollment(user, pii, opt_in) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:, opt_in:) expect(subject_analytics).to have_logged_event( 'USPS IPPaaS enrollment created', @@ -290,7 +291,7 @@ end it 'sends verification emails' do - subject.schedule_in_person_enrollment(user, pii) + subject.schedule_in_person_enrollment(user:, pii:, is_enhanced_ipp:) expect_delivered_email_count(1) expect_delivered_email( @@ -301,6 +302,42 @@ end end + describe '#create_usps_enrollment' do + let(:usps_mock_fallback) { true } + let(:enrollment) { create(:in_person_enrollment, :with_service_provider) } + let(:usps_eipp_sponsor_id) { '314159265359' } + let(:is_enhanced_ipp) { true } + let(:pii) do + Pii::Attributes.new_from_hash( + Idp::Constants::MOCK_IDV_APPLICANT, + ) + end + let(:applicant) do + UspsInPersonProofing::Applicant.new( + unique_id: enrollment.unique_id, + first_name: Idp::Constants::MOCK_IDV_APPLICANT[:first_name], + last_name: Idp::Constants::MOCK_IDV_APPLICANT[:last_name], + address: Idp::Constants::MOCK_IDV_APPLICANT[:address1], + city: Idp::Constants::MOCK_IDV_APPLICANT[:city], + state: Idp::Constants::MOCK_IDV_APPLICANT[:state], + zip_code: Idp::Constants::MOCK_IDV_APPLICANT[:zipcode], + email: usps_ipp_enrollment_status_update_email_address, + ) + end + before do + allow(IdentityConfig.store).to receive(:usps_eipp_sponsor_id). + and_return(usps_eipp_sponsor_id) + allow(UspsInPersonProofing::Mock::Proofer).to receive(:new).and_return(proofer) + allow(proofer).to receive(:request_enroll).and_call_original + end + context 'when the user is going through enhanced ipp' do + it 'creates an enhanced ipp enrollment' do + expect(proofer).to receive(:request_enroll).with(applicant, is_enhanced_ipp) + subject.create_usps_enrollment(enrollment, pii, is_enhanced_ipp) + end + end + end + def transliterated_without_change(value) UspsInPersonProofing::Transliterator::TransliterationResult.new( changed?: false, diff --git a/spec/services/usps_in_person_proofing/proofer_spec.rb b/spec/services/usps_in_person_proofing/proofer_spec.rb index ba73c6cccd6..000dac22c58 100644 --- a/spec/services/usps_in_person_proofing/proofer_spec.rb +++ b/spec/services/usps_in_person_proofing/proofer_spec.rb @@ -101,9 +101,9 @@ def expect_facility_fields_to_be_present(facility) stub_request_token stub_request_enroll - subject.request_enroll(applicant) - subject.request_enroll(applicant) - subject.request_enroll(applicant) + subject.request_enroll(applicant, false) + subject.request_enroll(applicant, false) + subject.request_enroll(applicant, false) expect(WebMock).to have_requested(:post, %r{/oauth/authenticate}).once expect(WebMock).to have_requested( @@ -219,15 +219,15 @@ def expect_facility_fields_to_be_present(facility) ).to eq(1) end - context 'when the user is going through EIPP' do + context 'when the user is going through enhanced ipp' do let(:usps_eipp_sponsor_id) { '314159265359' } let(:is_enhanced_ipp) { true } before do allow(IdentityConfig.store).to receive(:usps_eipp_sponsor_id). and_return(usps_eipp_sponsor_id) end - it 'uses the EIPP usps_ipp_sponsor_id in calls to the USPS API' do - stub_request_eipp_facilities + it 'uses the usps_eipp_sponsor_id in calls to the USPS API' do + stub_request_enhanced_ipp_facilities subject.request_facilities(location, is_enhanced_ipp) expect(WebMock).to have_requested(:post, request_url). @@ -281,15 +281,21 @@ def expect_facility_fields_to_be_present(facility) unique_id: '123456789', ) end + let(:is_enhanced_ipp) { false } + let(:request_url) { "#{root_url}/ivs-ippaas-api/IPPRest/resources/rest/optInIPPApplicant" } + let(:usps_ipp_sponsor_id) { '42' } + let(:ipp_assurance_level) { '1.5' } before do stub_request_token + allow(IdentityConfig.store).to receive(:usps_ipp_sponsor_id). + and_return(usps_ipp_sponsor_id) end it 'returns enrollment information' do stub_request_enroll - enrollment = subject.request_enroll(applicant) + enrollment = subject.request_enroll(applicant, is_enhanced_ipp) expect(enrollment.enrollment_code).to be_present expect(enrollment.response_message).to be_present end @@ -297,7 +303,7 @@ def expect_facility_fields_to_be_present(facility) it 'returns 400 error' do stub_request_enroll_bad_request_response - expect { subject.request_enroll(applicant) }.to raise_error( + expect { subject.request_enroll(applicant, is_enhanced_ipp) }.to raise_error( an_instance_of(Faraday::BadRequestError). and(having_attributes( response: include( @@ -312,7 +318,7 @@ def expect_facility_fields_to_be_present(facility) it 'returns 500 error' do stub_request_enroll_internal_server_error_response - expect { subject.request_enroll(applicant) }.to raise_error( + expect { subject.request_enroll(applicant, is_enhanced_ipp) }.to raise_error( an_instance_of(Faraday::ServerError). and(having_attributes( response: include( @@ -324,6 +330,21 @@ def expect_facility_fields_to_be_present(facility) ) end + it 'uses the usps_ipp_sponsor_id and IPPAssurance Level in calls to the USPS API' do + stub_request_enroll + subject.request_enroll(applicant, is_enhanced_ipp) + + expect(WebMock).to have_requested(:post, request_url). + with( + body: hash_including( + { + sponsorID: usps_ipp_sponsor_id.to_i, + IPPAssuranceLevel: ipp_assurance_level, + }, + ), + ) + end + context 'when the auth token is expired' do expires_at = nil let(:expires_in) { 15.minutes } @@ -341,7 +362,7 @@ def expect_facility_fields_to_be_present(facility) subject.token enrollment = nil travel_to(expires_at) do - enrollment = subject.request_enroll(applicant) + enrollment = subject.request_enroll(applicant, false) end expect(WebMock).to have_requested(:post, "#{root_url}/oauth/authenticate").twice @@ -350,6 +371,30 @@ def expect_facility_fields_to_be_present(facility) expect(enrollment.response_message).to be_present end end + + context 'when the enrollment is enhanced ipp' do + let(:usps_eipp_sponsor_id) { '314159265359' } + let(:ipp_assurance_level) { '2.0' } + let(:is_enhanced_ipp) { true } + before do + allow(IdentityConfig.store).to receive(:usps_eipp_sponsor_id). + and_return(usps_eipp_sponsor_id) + end + it 'uses the enhanced ipp usps_eipp_sponsor_id & IPPAssuranceLevel in calls to USPS API' do + stub_request_enroll + subject.request_enroll(applicant, is_enhanced_ipp) + + expect(WebMock).to have_requested(:post, request_url). + with( + body: hash_including( + { + sponsorID: usps_eipp_sponsor_id.to_i, + IPPAssuranceLevel: ipp_assurance_level, + }, + ), + ) + end + end end describe '#request_proofing_results' do diff --git a/spec/support/usps_ipp_helper.rb b/spec/support/usps_ipp_helper.rb index 0154bc8991e..a73504ba76d 100644 --- a/spec/support/usps_ipp_helper.rb +++ b/spec/support/usps_ipp_helper.rb @@ -35,10 +35,10 @@ def stub_request_facilities ) end - def stub_request_eipp_facilities + def stub_request_enhanced_ipp_facilities stub_request(:post, %r{/ivs-ippaas-api/IPPRest/resources/rest/getIppFacilityList}).to_return( status: 200, - body: UspsInPersonProofing::Mock::Fixtures.request_eipp_facilities_response, + body: UspsInPersonProofing::Mock::Fixtures.request_enhanced_ipp_facilities_response, headers: { 'content-type' => 'application/json' }, ) end diff --git a/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb b/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb index b1fb401087d..94915e0bcc9 100644 --- a/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb +++ b/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb @@ -22,9 +22,12 @@ user: user ) end - let(:is_eipp) { false } + let(:is_enhanced_ipp) { false } let(:presenter) do - Idv::InPerson::ReadyToVerifyPresenter.new(enrollment: enrollment, is_eipp: is_eipp) + Idv::InPerson::ReadyToVerifyPresenter.new( + enrollment: enrollment, + is_enhanced_ipp: is_enhanced_ipp, + ) end let(:step_indicator_steps) { Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS } let(:sp_event_name) { 'IdV: user clicked sp link on ready to verify page' } @@ -141,18 +144,26 @@ end context 'For IPP (Not Enhanced IPP)' do - let(:is_eipp) { false } + let(:is_enhanced_ipp) { false } before do - @is_eipp = false + @is_enhanced_ipp = false end context 'template displays modified content' do it 'conditionally renders content in the what to expect section applicable to IPP' do render - expect(rendered).to have_content(t('in_person_proofing.headings.barcode')) - expect(rendered).to have_content(t('in_person_proofing.process.state_id.heading')) - expect(rendered).to have_content(t('in_person_proofing.process.state_id.info')) + aggregate_failures do + [ + t('in_person_proofing.headings.barcode'), + t('in_person_proofing.process.state_id.heading'), + t('in_person_proofing.process.state_id.info'), + ].each do |copy| + Array(copy).each do |part| + expect(rendered).to have_content(part) + end + end + end end end @@ -169,38 +180,32 @@ ).once end - it 'template does not displays EIPP specific content' do + it 'template does not display Enhanced In-Person Proofing specific content' do render - expect(rendered).to_not have_content(t('in_person_proofing.headings.barcode_eipp')) - expect(rendered).to_not have_content(t('in_person_proofing.process.state_id.heading_eipp')) - expect(rendered).to_not have_content(t('in_person_proofing.process.state_id.info_eipp')) - expect(rendered).to_not have_content(t('in_person_proofing.headings.barcode_what_to_bring')) - expect(rendered).to_not have_content(t('in_person_proofing.body.barcode.what_to_bring')) - expect(rendered).to_not have_content(t('in_person_proofing.process.eipp_bring_id.heading')) - expect(rendered).to_not have_content(t('in_person_proofing.process.eipp_bring_id.info')) - expect(rendered).to_not have_content( - t('in_person_proofing.process.eipp_what_to_bring.heading'), - ) - expect(rendered).to_not have_content(t('in_person_proofing.process.eipp_what_to_bring.info')) - expect(rendered).to_not have_content( - t('in_person_proofing.process.eipp_state_id_passport.heading'), - ) - expect(rendered).to_not have_content( - t('in_person_proofing.process.eipp_state_id_passport.info'), - ) - expect(rendered).to_not have_content( - t('in_person_proofing.process.eipp_state_id_military_id.heading'), - ) - expect(rendered).to_not have_content( - t('in_person_proofing.process.eipp_state_id_military_id.info'), - ) - expect(rendered).to_not have_content( - t('in_person_proofing.process.eipp_state_id_supporting_docs.heading'), - ) - expect(rendered).to_not have_content( - t('in_person_proofing.process.eipp_state_id_supporting_docs.info'), - ) + aggregate_failures do + [ + t('in_person_proofing.headings.barcode_eipp'), + t('in_person_proofing.process.state_id.heading_eipp'), + t('in_person_proofing.process.state_id.info_eipp'), + t('in_person_proofing.headings.barcode_what_to_bring'), + t('in_person_proofing.body.barcode.what_to_bring'), + t('in_person_proofing.process.eipp_bring_id.heading'), + t('in_person_proofing.process.eipp_bring_id.info'), + t('in_person_proofing.process.eipp_what_to_bring.heading'), + t('in_person_proofing.process.eipp_what_to_bring.info'), + t('in_person_proofing.process.eipp_state_id_passport.heading'), + t('in_person_proofing.process.eipp_state_id_passport.info'), + t('in_person_proofing.process.eipp_state_id_military_id.heading'), + t('in_person_proofing.process.eipp_state_id_military_id.info'), + t('in_person_proofing.process.eipp_state_id_supporting_docs.heading'), + t('in_person_proofing.process.eipp_state_id_supporting_docs.info'), + ].each do |copy| + Array(copy).each do |part| + expect(rendered).to_not have_content(part) + end + end + end t('in_person_proofing.process.eipp_state_id_supporting_docs.info_list').each do |item| expect(rendered).to_not have_content(strip_tags(item)) @@ -208,20 +213,28 @@ end end - context 'For Enhanced IPP (EIPP)' do - let(:is_eipp) { true } + context 'For Enhanced In-Person Proofing (EIPP)' do + let(:is_enhanced_ipp) { true } before do - @is_eipp = true + @is_enhanced_ipp = true end context 'template displays modified content' do it 'conditionally renders content in the what to expect section applicable to EIPP' do render - expect(rendered).to have_content(t('in_person_proofing.headings.barcode_eipp')) - expect(rendered).to have_content(t('in_person_proofing.process.state_id.heading_eipp')) - expect(rendered).to have_content(t('in_person_proofing.process.state_id.info_eipp')) + aggregate_failures do + [ + t('in_person_proofing.headings.barcode_eipp'), + t('in_person_proofing.process.state_id.heading_eipp'), + t('in_person_proofing.process.state_id.info_eipp'), + ].each do |copy| + Array(copy).each do |part| + expect(rendered).to have_content(part) + end + end + end end end @@ -256,26 +269,22 @@ it 'renders Option 2 content' do render - expect(rendered).to have_content(t('in_person_proofing.process.eipp_what_to_bring.heading')) - expect(rendered).to have_content(t('in_person_proofing.process.eipp_what_to_bring.info')) - expect(rendered).to have_content( - t('in_person_proofing.process.eipp_state_id_passport.heading'), - ) - expect(rendered).to have_content( - t('in_person_proofing.process.eipp_state_id_passport.info'), - ) - expect(rendered).to have_content( - t('in_person_proofing.process.eipp_state_id_military_id.heading'), - ) - expect(rendered).to have_content( - t('in_person_proofing.process.eipp_state_id_military_id.info'), - ) - expect(rendered).to have_content( - t('in_person_proofing.process.eipp_state_id_supporting_docs.heading'), - ) - expect(rendered).to have_content( - t('in_person_proofing.process.eipp_state_id_supporting_docs.info'), - ) + aggregate_failures do + [ + t('in_person_proofing.process.eipp_what_to_bring.heading'), + t('in_person_proofing.process.eipp_what_to_bring.info'), + t('in_person_proofing.process.eipp_state_id_passport.heading'), + t('in_person_proofing.process.eipp_state_id_passport.info'), + t('in_person_proofing.process.eipp_state_id_military_id.heading'), + t('in_person_proofing.process.eipp_state_id_military_id.info'), + t('in_person_proofing.process.eipp_state_id_supporting_docs.heading'), + t('in_person_proofing.process.eipp_state_id_supporting_docs.info'), + ].each do |copy| + Array(copy).each do |part| + expect(rendered).to have_content(part) + end + end + end t('in_person_proofing.process.eipp_state_id_supporting_docs.info_list').each do |item| expect(rendered).to have_content(strip_tags(item)) diff --git a/yarn.lock b/yarn.lock index a337272274d..2c06bca13a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4654,10 +4654,10 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -libphonenumber-js@^1.11.3: - version "1.11.3" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.3.tgz#18126a2eec754eacd36f1f0d58590077fa5539ff" - integrity sha512-RU0CTsLCu2v6VEzdP+W6UU2n5+jEpMDRkGxUeBgsAJgre3vKgm17eApISH9OQY4G0jZYJVIc8qXmz6CJFueAFg== +libphonenumber-js@^1.11.4: + version "1.11.4" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.4.tgz#e63fe553f45661b30bb10bb8c82c9cf2b22ec32a" + integrity sha512-F/R50HQuWWYcmU/esP5jrH5LiWYaN7DpN0a/99U8+mnGGtnx8kmRE+649dQh3v+CowXXZc8vpkf5AmYkO0AQ7Q== lightningcss-darwin-arm64@1.23.0: version "1.23.0" @@ -6327,7 +6327,16 @@ strict-event-emitter@^0.5.1: resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz#1602ece81c51574ca39c6815e09f1a3e8550bd93" integrity sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -6400,7 +6409,14 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -7119,7 +7135,7 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -7137,6 +7153,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"