From 8b7807cc19ac597c3fc2585fd448a1e606f9b384 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 12 Jul 2022 13:22:38 -0400 Subject: [PATCH 01/11] LG-6348: Implement "Ready to verify" static page content **Why**: So that a user has the instructions they need to proof their identity in person. changelog: Upcoming Features, In-Person Proofing, Redirect user to "Ready to verify" page on flow completion --- Gemfile | 1 + Gemfile.lock | 2 + app/assets/images/idv/user-in-person.svg | 1 + .../in_person/ready_to_verify_controller.rb | 20 +-- .../in_person/ready_to_verify_presenter.rb | 86 +++++++++++++ .../in_person/enrollment_code_formatter.rb | 9 ++ app/services/marketing_site.rb | 1 + .../in_person/ready_to_verify/show.html.erb | 107 +++++++++++++++- config/application.yml.default | 1 + config/locales/in_person_proofing/en.yml | 38 ++++++ config/locales/in_person_proofing/es.yml | 41 ++++++ config/locales/in_person_proofing/fr.yml | 43 +++++++ config/locales/time/en.yml | 9 ++ config/locales/time/es.yml | 9 ++ config/locales/time/fr.yml | 9 ++ lib/identity_config.rb | 1 + .../ready_to_verify_controller_spec.rb | 43 +++++-- spec/features/idv/in_person_spec.rb | 10 +- .../ready_to_verify_presenter_spec.rb | 118 ++++++++++++++++++ .../enrollment_code_formatter_spec.rb | 11 ++ .../ready_to_verify/show.html.erb_spec.rb | 46 +++++++ 21 files changed, 585 insertions(+), 21 deletions(-) create mode 100644 app/assets/images/idv/user-in-person.svg create mode 100644 app/presenters/idv/in_person/ready_to_verify_presenter.rb create mode 100644 app/services/idv/in_person/enrollment_code_formatter.rb create mode 100644 spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb create mode 100644 spec/services/idv/in_person/enrollment_code_formatter_spec.rb create mode 100644 spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb diff --git a/Gemfile b/Gemfile index 72b23bb5c58..f6f8b09a93e 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ gem 'aws-sdk-pinpoint' gem 'aws-sdk-pinpointsmsvoice' gem 'aws-sdk-ses', '~> 1.6' gem 'aws-sdk-sns' +gem 'barby', '~> 0.6.8' gem 'base32-crockford' gem 'blueprinter', '~> 0.25.3' gem 'bootsnap', '~> 1.9.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index a2aa6a9e0ef..95218c3996f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -163,6 +163,7 @@ GEM descendants_tracker (~> 0.0.4) ice_nine (~> 0.11.0) thread_safe (~> 0.3, >= 0.3.1) + barby (0.6.8) base32-crockford (0.1.0) bcrypt (3.1.16) benchmark-ips (2.9.2) @@ -706,6 +707,7 @@ DEPENDENCIES aws-sdk-ses (~> 1.6) aws-sdk-sns axe-core-rspec (~> 4.2) + barby (~> 0.6.8) base32-crockford better_errors (>= 2.5.1) binding_of_caller diff --git a/app/assets/images/idv/user-in-person.svg b/app/assets/images/idv/user-in-person.svg new file mode 100644 index 00000000000..bbf95c69bfa --- /dev/null +++ b/app/assets/images/idv/user-in-person.svg @@ -0,0 +1 @@ + \ No newline at end of file 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 5fd76305579..3262699d3ad 100644 --- a/app/controllers/idv/in_person/ready_to_verify_controller.rb +++ b/app/controllers/idv/in_person/ready_to_verify_controller.rb @@ -1,25 +1,31 @@ module Idv module InPerson class ReadyToVerifyController < ApplicationController + include RenderConditionConcern + + check_or_render_not_found -> { IdentityConfig.store.in_person_proofing_enabled } + before_action :confirm_two_factor_authenticated before_action :confirm_in_person_session def show analytics.idv_in_person_ready_to_verify_visit + @presenter = ReadyToVerifyPresenter.new(enrollment: enrollment) end private def confirm_in_person_session - redirect_to account_url unless in_person_proofing_component? - end - - def in_person_proofing_component? - proofing_component&.document_check == Idp::Constants::Vendors::USPS + redirect_to account_url unless enrollment.present? end - def proofing_component - ProofingComponent.find_by(user: current_user) + def enrollment + InPersonEnrollment.new( + user: current_user, + profile: current_user.profiles.last, + enrollment_code: '2048702198804358', + created_at: Time.zone.now, + ) end end end diff --git a/app/presenters/idv/in_person/ready_to_verify_presenter.rb b/app/presenters/idv/in_person/ready_to_verify_presenter.rb new file mode 100644 index 00000000000..3e90ba3981d --- /dev/null +++ b/app/presenters/idv/in_person/ready_to_verify_presenter.rb @@ -0,0 +1,86 @@ +require 'barby' +require 'barby/barcode/code_128' +require 'barby/outputter/png_outputter' + +module Idv + module InPerson + class ReadyToVerifyPresenter + def initialize(enrollment:) + @enrollment = enrollment + end + + def barcode_data_url + "data:image/png;base64,#{Base64.strict_encode64(barcode_image_data)}" + end + + def formatted_due_date + due_date.strftime(I18n.t('time.formats.event_date')) + end + + def formatted_enrollment_code + EnrollmentCodeFormatter.format(enrollment_code) + end + + def selected_location_details + # WILLFIX: After LG-6708, delegate this to enrollment. + { + name: 'BALTIMORE — Post Office™', + streetAddress: '900 E FAYETTE ST RM 118', + city: 'BALTIMORE', + state: 'MD', + zip5: '21233', + zip4: '9715', + phone: '555-123-6409', + hours: [ + { + weekdayHours: '8:30 AM - 4:30 PM', + }, + { + saturdayHours: '9:00 AM - 12:00 PM', + }, + { + sundayHours: 'Closed', + }, + ], + } + end + + def selected_location_hours(prefix) + selected_location_details[:hours].each do |hours_candidate| + hours = hours_candidate["#{prefix}Hours".to_sym] + return localized_hours(hours) if hours + end + end + + def needs_proof_of_address? + # WILLFIX: After LG-6708, return negated enrollment.current_address_matches_id + true + end + + private + + attr_reader :enrollment + delegate :enrollment_code, to: :enrollment + + def barcode_image_data + Barby::Code128C.new(enrollment_code).to_png(margin: 0, xdim: 2) + end + + def due_date + enrollment.created_at + IdentityConfig.store.in_person_enrollment_validity_in_days.days + end + + def localized_hours(hours) + case hours + when 'Closed' + I18n.t('in_person_proofing.body.barcode.retail_hours_closed') + else + hours. + split(' - '). # Hyphen + map { |time| Time.zone.parse(time).strftime(I18n.t('time.formats.event_time')) }. + join(' – ') # Endash + end + end + end + end +end diff --git a/app/services/idv/in_person/enrollment_code_formatter.rb b/app/services/idv/in_person/enrollment_code_formatter.rb new file mode 100644 index 00000000000..fc387858b6a --- /dev/null +++ b/app/services/idv/in_person/enrollment_code_formatter.rb @@ -0,0 +1,9 @@ +module Idv + module InPerson + class EnrollmentCodeFormatter + def self.format(code) + code.gsub(/(\d{4})/, '\1-').chomp('-') + end + end + end +end diff --git a/app/services/marketing_site.rb b/app/services/marketing_site.rb index b4f6610c60b..afc37c16d3d 100644 --- a/app/services/marketing_site.rb +++ b/app/services/marketing_site.rb @@ -12,6 +12,7 @@ class MarketingSite verify-your-identity/how-to-verify-in-person verify-your-identity/phone-number-and-phone-plan-in-your-name verify-your-identity/verify-your-address-by-mail + verify-your-identity/how-to-verify-in-person get-started/authentication-options ].to_set.freeze 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 e53fb796595..2a3d380fd83 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 @@ -1,3 +1,108 @@ <% title t('in_person_proofing.headings.barcode') %> -<%= render PageHeadingComponent.new.with_content(t('in_person_proofing.headings.barcode')) %> +<% content_for(:pre_flash_content) do %> + <%= render 'shared/step_indicator', { + steps: Idv::Flows::InPersonFlow::STEP_INDICATOR_STEPS, + current_step: :go_to_the_post_office, + locale_scope: 'idv', + class: 'margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4', + } %> +<% end %> + +<%= image_tag( + asset_url('idv/user-in-person.svg'), + width: 136, + height: 136, + class: 'display-block margin-x-auto margin-bottom-4', + ) %> + +<%= render PageHeadingComponent.new(class: 'text-center') do %> + <%= t('in_person_proofing.headings.barcode') %> +<% end %> + +<%= render AlertComponent.new(class: 'margin-y-4', text_tag: :div) do %> +

<%= t('in_person_proofing.body.barcode.deadline', deadline: @presenter.formatted_due_date) %>

+

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

+<% end %> + +
+

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

+

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

+ <%= render ProcessListComponent.new(heading_level: :h3, class: 'margin-y-3') do |c| %> + <% c.item(heading: t('in_person_proofing.process.barcode.heading')) do %> +

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

+
+ <%= image_tag( + @presenter.barcode_data_url, + skip_pipeline: true, + alt: t('in_person_proofing.process.barcode.image_alt'), + class: 'display-block margin-bottom-1', + ) %> +
+ <%= t('in_person_proofing.process.barcode.caption_label') %>: + <%= @presenter.formatted_enrollment_code %> +
+
+ <% end %> + <% c.item(heading: t('in_person_proofing.process.state_id.heading')) do %> +

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

+ +

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

+ <% end %> + <% if @presenter.needs_proof_of_address? %> + <% c.item(heading: t('in_person_proofing.process.proof_of_address.heading')) do %> +

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

+ + <% end %> + <% end %> + <% end %> +

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

+
+ +
+
+

<%= @presenter.selected_location_details[:name] %>

+
+ <%= @presenter.selected_location_details[:streetAddress] %>
+ <%= @presenter.selected_location_details[:city] %>, + <%= @presenter.selected_location_details[:state] %> + <%= @presenter.selected_location_details[:zip5] %>-<%= @presenter.selected_location_details[:zip4] %> +
+

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

+
+ <%= t('date.day_names_short')[0] %>–<%= t('date.day_names_short')[4] %>: <%= @presenter.selected_location_hours(:weekday) %>
+ <%= t('date.day_names_short')[5] %>: <%= @presenter.selected_location_hours(:saturday) %>
+ <%= t('date.day_names_short')[6] %>: <%= @presenter.selected_location_hours(:sunday) %> +
+
+ <%= t('in_person_proofing.body.barcode.retail_phone_label') %>: + <%= @presenter.selected_location_details[:phone] %> +
+
+
+ +

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

+ +

+ <%= t('in_person_proofing.body.barcode.deadline', deadline: @presenter.formatted_due_date) %> + <%= t('in_person_proofing.body.barcode.no_appointment_required') %> +

+ +<%= render 'idv/doc_auth/cancel', step: 'in_person_ready_to_verify' %> diff --git a/config/application.yml.default b/config/application.yml.default index 4c0a0b42197..9b7f8c57803 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -107,6 +107,7 @@ idv_send_link_max_attempts: 5 idv_sp_required: false in_person_proofing_enabled: false in_person_proofing_enabled_issuers: '[]' +in_person_enrollment_validity_in_days: 30 include_slo_in_saml_metadata: false irs_attempt_api_audience: 'https://irs.gov' irs_attempt_api_auth_tokens: '' diff --git a/config/locales/in_person_proofing/en.yml b/config/locales/in_person_proofing/en.yml index 8549dc3e2b0..2f7dff5eb78 100644 --- a/config/locales/in_person_proofing/en.yml +++ b/config/locales/in_person_proofing/en.yml @@ -30,6 +30,21 @@ en: verify_step_enter_phone: Enter a phone number with your name on the plan. verify_step_enter_pii: 'Enter your name, date of birth, state-issued ID number, address and Social Security number.' + barcode: + deadline: Your deadline to verify your identity in person is %{deadline}. + deadline_restart: If you go after the deadline, your information will not be + saved and you will need to restart the process. + emailed_info: We have emailed this information to the email you used to log in. + items_to_bring: 'Bring these items with you to the Post Office:' + items_to_bring_questions: Questions about what to bring? + learn_more: Learn more + location_details: Location details + no_appointment_required: No appointment is required. + retail_hours: Retail hours + retail_hours_closed: Closed + retail_phone_label: Phone number + speak_to_associate: You can speak with any retail associate at this Post Office + to verify your identity. state_id: info_html: 'Enter information exactly as it appears on your state-issued ID. We will use this information to confirm it matches your @@ -64,3 +79,26 @@ en: state_id: Enter the information on your ID update_address: Update your current address update_state_id: Update the information on your ID + process: + barcode: + caption_label: Enrollment code + heading: A copy of your barcode + image_alt: Barcode + info: Print or scan from your mobile device. + proof_of_address: + acceptable_proof: + - Lease, Mortgage, or Deed of Trust + - Voter Registration + - Vehicle Registration Card + - Home or Vehicle Insurance Policy + heading: Proof of your current address + info: 'You need a proof of address if your current address is different than the + address on your ID. Acceptable forms of proof of address are:' + state_id: + acceptable_documents: + - State Driver’s License + - State Non-Driver’s Identification Card + heading: Your state-issued ID + info: 'Your ID must not be expired. Acceptable forms of ID are:' + no_other_documents: We do not currently accept any other forms of + identification, such as passports and military IDs. diff --git a/config/locales/in_person_proofing/es.yml b/config/locales/in_person_proofing/es.yml index 1b87d8a8e88..5392d62c016 100644 --- a/config/locales/in_person_proofing/es.yml +++ b/config/locales/in_person_proofing/es.yml @@ -7,6 +7,22 @@ es: identidad, deberá llevar a la oficina de correos un comprobante de su dirección actual.' learn_more: Aprende más + barcode: + deadline: El plazo para verificar su identidad en persona es el %{deadline}. + deadline_restart: Si supera la fecha límite, su información no se guardará y + tendrá que reiniciar el proceso. + emailed_info: Hemos enviado esta información al correo electrónico que utilizó + para iniciar la sesión. + items_to_bring: 'Lleve estos artículos a la oficina de correos:' + items_to_bring_questions: ¿Preguntas sobre qué llevar? + learn_more: Más información + location_details: Detalles de ubicación # WILLFIX: Use approved content (LG-6841) + no_appointment_required: No es necesario pedir cita. + retail_hours: Horario de venta al por menor # WILLFIX: Use approved content (LG-6841) + retail_hours_closed: Cerrada # WILLFIX: Use approved content (LG-6841) + retail_phone_label: Número de teléfono # WILLFIX: Use approved content (LG-6841) + speak_to_associate: Puedes hablar con cualquier socio de ventas en esta oficina + de correos para verificar tu identidad. prepare: alert_selected_post_office: 'Ha seleccionado la oficina de correos %{name}.' bring_barcode_header: Una copia de su código de barras @@ -67,3 +83,28 @@ es: state_id: Ingrese la información de su cédula update_address: Actualizar su dirección actual update_state_id: Actualizar la información de su cédula de identidad + process: + barcode: + caption_label: Código de inscripción # WILLFIX: Use approved content (LG-6841) + heading: Una copia de su código de barras + image_alt: Código de barras # WILLFIX: Use approved content (LG-6841) + info: Imprima o escanee desde su dispositivo móvil. + proof_of_address: + acceptable_proof: + - Arrendamiento, hipoteca o escritura de fideicomiso + - Registro de votantes + - Tarjeta de registro del vehículo + - Póliza de seguro del hogar o del vehículo + heading: Prueba de su dirección actual + info: 'Necesita un justificante de domicilio si su dirección actual es diferente + a la que figura en su cédula de identidad. Los comprobantes de + domicilio aceptables son:' + state_id: + acceptable_documents: + - Licencia de conducir estatal + - Tarjeta de identificación estatal para no conductores. + heading: Su cédula emitida por el estado + info: 'Su cédula de identidad no debe estar caducada. Las formas de + identificación aceptables son:' + no_other_documents: Actualmente no aceptamos otras formas de identificación, + como pasaportes y cartillas militares. diff --git a/config/locales/in_person_proofing/fr.yml b/config/locales/in_person_proofing/fr.yml index 3a62ce0035d..cf5a586efe6 100644 --- a/config/locales/in_person_proofing/fr.yml +++ b/config/locales/in_person_proofing/fr.yml @@ -7,6 +7,23 @@ fr: document d’identité, vous devrez apporter une preuve de votre adresse actuelle au bureau de poste. learn_more: Apprendre encore plus + barcode: + deadline: La date limite pour vérifier votre identité en personne est le + %{deadline}. + deadline_restart: Si vous partez après la date limite, vos informations ne + seront pas sauvegardées et vous devrez recommencer le processus. + emailed_info: Nous avons envoyé ces informations à l’adresse électronique que + vous avez utilisée pour vous connecter. + items_to_bring: 'Apportez ces articles avec vous au bureau de poste:' + items_to_bring_questions: Des questions sur ce qu’il faut apporter? + learn_more: En savoir plus + location_details: Détails de l’emplacement # WILLFIX: Use approved content (LG-6841) + no_appointment_required: Aucun rendez-vous n’est exigé. + retail_hours: Heures de vente au détail # WILLFIX: Use approved content (LG-6841) + retail_hours_closed: Fermée # WILLFIX: Use approved content (LG-6841) + retail_phone_label: Numéro de téléphone # WILLFIX: Use approved content (LG-6841) + speak_to_associate: Vous pouvez vous adresser à n’importe quel employé de ce + bureau de poste pour faire vérifier votre identité. prepare: alert_selected_post_office: 'Vous avez sélectionné le bureau de poste de %{name}.' bring_barcode_header: Une copie de votre code-barres @@ -70,3 +87,29 @@ fr: state_id: Saisissez les informations figurant sur votre document d’identité update_address: Mettre à jour votre adresse actuelle update_state_id: Mettre à jour les informations figurant sur votre document d’identité + process: + barcode: + caption_label: Code d’inscription # WILLFIX: Use approved content (LG-6841) + heading: Une copie de votre code-barres + image_alt: Code à barre # WILLFIX: Use approved content (LG-6841) + info: Imprimez ou numérisez depuis votre appareil mobile. + proof_of_address: + acceptable_proof: + - Bail, hypothèque ou acte de fiducie + - Inscription sur les listes électorales + - Carte d’immatriculation du véhicule + - Police d’assurance habitation ou véhicule + heading: Preuve de votre adresse actuelle + info: 'Vous avez besoin d’un justificatif de domicile si votre adresse actuelle + est différente de l’adresse figurant sur votre document d’identité. + Les justificatifs d’adresse acceptés sont les suivants:' + state_id: + acceptable_documents: + - Permis de conduire d’État + - Document d’identité de non-conducteur d’État + heading: Votre document d’identité délivré par l’État + info: 'Votre pièce d’identité ne doit pas être expirée. Les formes + d’identification acceptables sont:' + no_other_documents: Nous n’acceptons actuellement aucune autre forme + d’identification, comme les passeports et les documents d’identité + militaires. diff --git a/config/locales/time/en.yml b/config/locales/time/en.yml index dc94afa291b..755951121a6 100644 --- a/config/locales/time/en.yml +++ b/config/locales/time/en.yml @@ -1,6 +1,14 @@ --- en: date: + day_names_short: + - Mon + - Tue + - Wed + - Thu + - Fri + - Sat + - Sun month_names: - null - January @@ -19,6 +27,7 @@ en: am: AM formats: event_date: '%B %-d, %Y' + event_time: '%-l:%M %p' event_timestamp: '%B %-d, %Y at %-l:%M %p' event_timestamp_js: '%{month} %{day}, %{year} at %{hour}:%{minute} %{day_period}' event_timestamp_utc: '%B %-d, %Y at %-l:%M %p UTC' diff --git a/config/locales/time/es.yml b/config/locales/time/es.yml index 25f6d6d7f41..4556e5cb729 100644 --- a/config/locales/time/es.yml +++ b/config/locales/time/es.yml @@ -1,6 +1,14 @@ --- es: date: + day_names_short: + - Lu + - Ma + - Mi + - Ju + - Vi + - Sa + - Do month_names: - null - enero @@ -19,6 +27,7 @@ es: am: AM formats: event_date: '%-d de %B %Y' + event_time: '%H:%M' event_timestamp: '%e de %B de %Y a las %H:%M' event_timestamp_js: '%{day} de %{month} de %{year} a las %{hour}:%{minute}' event_timestamp_utc: '%e de %B de %Y a las %H:%M UTC' diff --git a/config/locales/time/fr.yml b/config/locales/time/fr.yml index 20d38264032..097c8e67b9d 100644 --- a/config/locales/time/fr.yml +++ b/config/locales/time/fr.yml @@ -1,6 +1,14 @@ --- fr: date: + day_names_short: + - Lun + - Mar + - Mer + - Jeu + - Ven + - Sam + - Dim month_names: - null - janvier @@ -19,6 +27,7 @@ fr: am: A.M. formats: event_date: '%-d %B %Y' + event_time: '%H:%M' event_timestamp: '%e %B %Y à %H:%M' event_timestamp_js: '%{day} %{month} %{year} à %{hour}:%{minute}' event_timestamp_utc: '%e %B %Y à %H:%M UTC' diff --git a/lib/identity_config.rb b/lib/identity_config.rb index 0e51e14bdc4..a107ce4b884 100644 --- a/lib/identity_config.rb +++ b/lib/identity_config.rb @@ -181,6 +181,7 @@ def self.build_store(config_map) config.add(:idv_sp_required, type: :boolean) config.add(:in_person_proofing_enabled, type: :boolean) config.add(:in_person_proofing_enabled_issuers, type: :json) + config.add(:in_person_enrollment_validity_in_days, type: :integer) config.add(:include_slo_in_saml_metadata, type: :boolean) config.add(:irs_attempt_api_audience) config.add(:irs_attempt_api_auth_tokens, type: :comma_separated_string_list) 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 f34fa02fb79..850dc1a7f33 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 @@ -2,10 +2,15 @@ describe Idv::InPerson::ReadyToVerifyController do let(:user) { create(:user) } + let(:in_person_proofing_enabled) { false } + let(:enrollment) { nil } before do stub_analytics stub_sign_in(user) + allow(IdentityConfig.store).to receive(:in_person_proofing_enabled). + and_return(in_person_proofing_enabled) + allow(controller).to receive(:enrollment).and_return(enrollment) end describe 'before_actions' do @@ -17,23 +22,37 @@ describe '#show' do subject(:response) { get :show } - it 'redirects to account page' do - expect(response).to redirect_to account_url + it 'renders not found' do + expect(response.status).to eq 404 end - context 'with in person proofing component' do - before do - ProofingComponent.create(user: user, document_check: Idp::Constants::Vendors::USPS) - end + context 'with in person proofing enabled' do + let(:in_person_proofing_enabled) { true } - it 'renders show template' do - expect(response).to render_template :show + it 'redirects to account page' do + expect(response).to redirect_to account_url end - it 'logs analytics' do - response - - expect(@analytics).to have_logged_event('IdV: in person ready to verify visited') + context 'with enrollment' do + let(:profile) { create(:profile, :with_pii, user: user) } + let(:enrollment) do + InPersonEnrollment.new( + user: user, + profile: profile, + enrollment_code: '2048702198804358', + created_at: Time.zone.now, + ) + end + + it 'renders show template' do + expect(response).to render_template :show + end + + it 'logs analytics' do + response + + expect(@analytics).to have_logged_event('IdV: in person ready to verify visited') + end end end end diff --git a/spec/features/idv/in_person_spec.rb b/spec/features/idv/in_person_spec.rb index 2ca984e02dd..2c48c75a122 100644 --- a/spec/features/idv/in_person_spec.rb +++ b/spec/features/idv/in_person_spec.rb @@ -99,10 +99,18 @@ # personal key page expect(page).to have_content(t('titles.idv.personal_key')) - acknowledge_and_confirm_personal_key + deadline = nil + freeze_time do + acknowledge_and_confirm_personal_key + deadline = (Time.zone.now + IdentityConfig.store.in_person_enrollment_validity_in_days.days). + strftime(t('time.formats.event_date')) + end # ready to verify page + enrollment_code = JSON.parse(UspsIppFixtures.request_enrollment_code_response)['enrollmentCode'] expect(page).to have_content(t('in_person_proofing.headings.barcode')) + expect(page).to have_content(Idv::InPerson::EnrollmentCodeFormatter.format(enrollment_code)) + expect(page).to have_content(t('in_person_proofing.body.barcode.deadline', deadline: deadline)) end def attach_images_that_fail diff --git a/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb b/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb new file mode 100644 index 00000000000..4241da4aed7 --- /dev/null +++ b/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb @@ -0,0 +1,118 @@ +require 'rails_helper' + +RSpec.describe Idv::InPerson::ReadyToVerifyPresenter do + let(:user) { build(:user) } + let(:profile) { build(:profile, user: user) } + let(:enrollment_code) { '2048702198804358' } + let(:current_address_matches_id) { true } + let(:created_at) { Time.zone.parse('2022-07-13') } + let(:enrollment) do + InPersonEnrollment.new( + user: user, + profile: profile, + enrollment_code: enrollment_code, + created_at: created_at, + ) + end + + subject(:presenter) { described_class.new(enrollment: enrollment) } + + describe '#barcode_data_url' do + subject(:barcode_data_url) { presenter.barcode_data_url } + + it 'returns a valid data URL' do + expect(barcode_data_url).to match URI::DEFAULT_PARSER.make_regexp('data') + end + end + + describe '#formatted_due_date' do + subject(:formatted_due_date) { presenter.formatted_due_date } + + it 'returns a formatted due date' do + expect(formatted_due_date).to eq 'August 12, 2022' + end + end + + describe '#formatted_enrollment_code' do + subject(:formatted_enrollment_code) { presenter.formatted_enrollment_code } + + it 'returns a formatted enrollment code' do + expect(formatted_enrollment_code).to eq( + Idv::InPerson::EnrollmentCodeFormatter.format(enrollment_code), + ) + end + end + + describe '#selected_location_details' do + subject(:selected_location_details) { presenter.selected_location_details } + + it 'returns a hash of location details associated with the enrollment' do + expect(selected_location_details).to include( + name: kind_of(String), + streetAddress: kind_of(String), + city: kind_of(String), + state: kind_of(String), + zip5: kind_of(String), + zip4: kind_of(String), + phone: kind_of(String), + hours: array_including( + hash_including(weekdayHours: kind_of(String)), + hash_including(saturdayHours: kind_of(String)), + hash_including(sundayHours: kind_of(String)), + ), + ) + end + end + + describe '#selected_location_hours' do + let(:hours_open) { '8:00 AM - 4:30 PM' } + let(:hours_closed) { 'Closed' } + + before do + allow(presenter).to receive(:selected_location_details).and_return( + hours: [ + { weekdayHours: hours_open }, + { saturdayHours: hours_open }, + { sundayHours: hours_closed }, + ], + ) + end + + it 'returns localized location hours for weekdays and weekends by prefix' do + expect(presenter.selected_location_hours(:weekday)).to eq '8:00 AM – 4:30 PM' + expect(presenter.selected_location_hours(:saturday)).to eq '8:00 AM – 4:30 PM' + expect(presenter.selected_location_hours(:sunday)).to eq( + I18n.t('in_person_proofing.body.barcode.retail_hours_closed'), + ) + end + + context 'with Spanish locale' do + before { I18n.locale = :es } + + it 'returns localized location hours for weekdays and weekends by prefix' do + expect(presenter.selected_location_hours(:weekday)).to eq '08:00 – 16:30' + expect(presenter.selected_location_hours(:saturday)).to eq '08:00 – 16:30' + expect(presenter.selected_location_hours(:sunday)).to eq( + I18n.t('in_person_proofing.body.barcode.retail_hours_closed'), + ) + end + end + end + + describe '#needs_proof_of_address?' do + subject(:needs_proof_of_address) { presenter.needs_proof_of_address? } + + context 'with current address matching id' do + let(:current_address_matches_id) { true } + + it { expect(needs_proof_of_address).to eq true } + end + + context 'with current address not matching id' do + let(:current_address_matches_id) { false } + + # WILLFIX: After LG-6708, unskip and initialize enrollment with current_address_matches_id + xit { expect(needs_proof_of_address).to eq false } + end + end +end diff --git a/spec/services/idv/in_person/enrollment_code_formatter_spec.rb b/spec/services/idv/in_person/enrollment_code_formatter_spec.rb new file mode 100644 index 00000000000..886cb319140 --- /dev/null +++ b/spec/services/idv/in_person/enrollment_code_formatter_spec.rb @@ -0,0 +1,11 @@ +require 'rails_helper' + +describe Idv::InPerson::EnrollmentCodeFormatter do + describe '.format' do + it 'returns a formatted code' do + result = described_class.format('2048702198804358') + + expect(result).to eq '2048-7021-9880-4358' + end + end +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 new file mode 100644 index 00000000000..7e8516eda8b --- /dev/null +++ b/spec/views/idv/in_person/ready_to_verify/show.html.erb_spec.rb @@ -0,0 +1,46 @@ +require 'rails_helper' + +describe 'idv/in_person/ready_to_verify/show.html.erb' do + include Devise::Test::ControllerHelpers + + let(:user) { build(:user) } + let(:profile) { build(:profile, user: user) } + let(:enrollment_code) { '2048702198804358' } + let(:current_address_matches_id) { true } + let(:created_at) { Time.zone.parse('2022-07-13') } + let(:enrollment) do + InPersonEnrollment.new( + user: user, + profile: profile, + enrollment_code: enrollment_code, + created_at: created_at, + ) + end + let(:presenter) { Idv::InPerson::ReadyToVerifyPresenter.new(enrollment: enrollment) } + + before do + assign(:presenter, presenter) + # WILLFIX: After LG-6708, remove this and initialize enrollment with current_address_matches_id + allow(presenter).to receive(:needs_proof_of_address?).and_return(!current_address_matches_id) + end + + context 'with enrollment where current address matches id' do + let(:current_address_matches_id) { true } + + it 'renders without proof of address instructions' do + render + + expect(rendered).not_to have_content(t('in_person_proofing.process.proof_of_address.heading')) + end + end + + context 'with enrollment where current address does not match id' do + let(:current_address_matches_id) { false } + + it 'renders with proof of address instructions' do + render + + expect(rendered).to have_content(t('in_person_proofing.process.proof_of_address.heading')) + end + end +end From c4e5d363474a90179e2698fdb5c0527b12d0c15e Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Thu, 14 Jul 2022 13:32:23 -0400 Subject: [PATCH 02/11] Use full day names Improve accessibility See: https://github.com/18F/identity-idp/pull/6580#issuecomment-1184586539 --- .../idv/in_person/ready_to_verify/show.html.erb | 6 +++--- config/locales/time/en.yml | 16 ++++++++-------- config/locales/time/es.yml | 16 ++++++++-------- config/locales/time/fr.yml | 16 ++++++++-------- 4 files changed, 27 insertions(+), 27 deletions(-) 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 2a3d380fd83..b4f77a8ddc6 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 @@ -87,9 +87,9 @@

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

- <%= t('date.day_names_short')[0] %>–<%= t('date.day_names_short')[4] %>: <%= @presenter.selected_location_hours(:weekday) %>
- <%= t('date.day_names_short')[5] %>: <%= @presenter.selected_location_hours(:saturday) %>
- <%= t('date.day_names_short')[6] %>: <%= @presenter.selected_location_hours(:sunday) %> + <%= t('date.day_names')[0] %>–<%= t('date.day_names')[4] %>: <%= @presenter.selected_location_hours(:weekday) %>
+ <%= t('date.day_names')[5] %>: <%= @presenter.selected_location_hours(:saturday) %>
+ <%= t('date.day_names')[6] %>: <%= @presenter.selected_location_hours(:sunday) %>
<%= t('in_person_proofing.body.barcode.retail_phone_label') %>: diff --git a/config/locales/time/en.yml b/config/locales/time/en.yml index 755951121a6..93ca66c8501 100644 --- a/config/locales/time/en.yml +++ b/config/locales/time/en.yml @@ -1,14 +1,14 @@ --- en: date: - day_names_short: - - Mon - - Tue - - Wed - - Thu - - Fri - - Sat - - Sun + day_names: + - Monday + - Tuesday + - Wednesday + - Thursday + - Friday + - Saturday + - Sunday month_names: - null - January diff --git a/config/locales/time/es.yml b/config/locales/time/es.yml index 4556e5cb729..022fb7641a5 100644 --- a/config/locales/time/es.yml +++ b/config/locales/time/es.yml @@ -1,14 +1,14 @@ --- es: date: - day_names_short: - - Lu - - Ma - - Mi - - Ju - - Vi - - Sa - - Do + day_names: + - Lunes + - Martes + - Miércoles + - Jueves + - Viernes + - Sábado + - Domingo month_names: - null - enero diff --git a/config/locales/time/fr.yml b/config/locales/time/fr.yml index 097c8e67b9d..bbe2df23dbc 100644 --- a/config/locales/time/fr.yml +++ b/config/locales/time/fr.yml @@ -1,14 +1,14 @@ --- fr: date: - day_names_short: - - Lun - - Mar - - Mer - - Jeu - - Ven - - Sam - - Dim + day_names: + - Lundi + - Mardi + - Mercredi + - Jeudi + - Vendredi + - Samedi + - Dimanche month_names: - null - janvier From 49aa99d7286145ee27d25651581d94862682954b Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Thu, 14 Jul 2022 14:31:55 -0400 Subject: [PATCH 03/11] Add final translated copy --- config/locales/in_person_proofing/en.yml | 30 ++++++++++++------------ config/locales/in_person_proofing/es.yml | 12 +++++----- config/locales/in_person_proofing/fr.yml | 12 +++++----- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/config/locales/in_person_proofing/en.yml b/config/locales/in_person_proofing/en.yml index 2f7dff5eb78..faf2ce8e0e4 100644 --- a/config/locales/in_person_proofing/en.yml +++ b/config/locales/in_person_proofing/en.yml @@ -6,6 +6,21 @@ en: info: 'If your current address does not match the address on your ID, you will need to bring proof of your current address to the Post Office.' learn_more: Learn more + barcode: + deadline: Your deadline to verify your identity in person is %{deadline}. + deadline_restart: If you go after the deadline, your information will not be + saved and you will need to restart the process. + emailed_info: We have emailed this information to the email you used to log in. + items_to_bring: 'Bring these items with you to the Post Office:' + items_to_bring_questions: Questions about what to bring? + learn_more: Learn more + location_details: Location details + no_appointment_required: No appointment is required. + retail_hours: Retail hours + retail_hours_closed: Closed + retail_phone_label: Phone number + speak_to_associate: You can speak with any retail associate at this Post Office + to verify your identity. prepare: alert_selected_post_office: 'You’ve selected the %{name} Post Office.' bring_barcode_header: A copy of your barcode @@ -30,21 +45,6 @@ en: verify_step_enter_phone: Enter a phone number with your name on the plan. verify_step_enter_pii: 'Enter your name, date of birth, state-issued ID number, address and Social Security number.' - barcode: - deadline: Your deadline to verify your identity in person is %{deadline}. - deadline_restart: If you go after the deadline, your information will not be - saved and you will need to restart the process. - emailed_info: We have emailed this information to the email you used to log in. - items_to_bring: 'Bring these items with you to the Post Office:' - items_to_bring_questions: Questions about what to bring? - learn_more: Learn more - location_details: Location details - no_appointment_required: No appointment is required. - retail_hours: Retail hours - retail_hours_closed: Closed - retail_phone_label: Phone number - speak_to_associate: You can speak with any retail associate at this Post Office - to verify your identity. state_id: info_html: 'Enter information exactly as it appears on your state-issued ID. We will use this information to confirm it matches your diff --git a/config/locales/in_person_proofing/es.yml b/config/locales/in_person_proofing/es.yml index 5392d62c016..2546488f7e5 100644 --- a/config/locales/in_person_proofing/es.yml +++ b/config/locales/in_person_proofing/es.yml @@ -16,11 +16,11 @@ es: items_to_bring: 'Lleve estos artículos a la oficina de correos:' items_to_bring_questions: ¿Preguntas sobre qué llevar? learn_more: Más información - location_details: Detalles de ubicación # WILLFIX: Use approved content (LG-6841) + location_details: Detalles de la ubicación no_appointment_required: No es necesario pedir cita. - retail_hours: Horario de venta al por menor # WILLFIX: Use approved content (LG-6841) - retail_hours_closed: Cerrada # WILLFIX: Use approved content (LG-6841) - retail_phone_label: Número de teléfono # WILLFIX: Use approved content (LG-6841) + retail_hours: Heures de vente au détail + retail_hours_closed: Cerrado + retail_phone_label: Número de teléfono speak_to_associate: Puedes hablar con cualquier socio de ventas en esta oficina de correos para verificar tu identidad. prepare: @@ -85,9 +85,9 @@ es: update_state_id: Actualizar la información de su cédula de identidad process: barcode: - caption_label: Código de inscripción # WILLFIX: Use approved content (LG-6841) + caption_label: Código de registro heading: Una copia de su código de barras - image_alt: Código de barras # WILLFIX: Use approved content (LG-6841) + image_alt: Código de barras info: Imprima o escanee desde su dispositivo móvil. proof_of_address: acceptable_proof: diff --git a/config/locales/in_person_proofing/fr.yml b/config/locales/in_person_proofing/fr.yml index cf5a586efe6..0e333ff59f4 100644 --- a/config/locales/in_person_proofing/fr.yml +++ b/config/locales/in_person_proofing/fr.yml @@ -17,11 +17,11 @@ fr: items_to_bring: 'Apportez ces articles avec vous au bureau de poste:' items_to_bring_questions: Des questions sur ce qu’il faut apporter? learn_more: En savoir plus - location_details: Détails de l’emplacement # WILLFIX: Use approved content (LG-6841) + location_details: Détails de l’emplacement no_appointment_required: Aucun rendez-vous n’est exigé. - retail_hours: Heures de vente au détail # WILLFIX: Use approved content (LG-6841) - retail_hours_closed: Fermée # WILLFIX: Use approved content (LG-6841) - retail_phone_label: Numéro de téléphone # WILLFIX: Use approved content (LG-6841) + retail_hours: Heures de vente au détail + retail_hours_closed: Fermé + retail_phone_label: Numéro de téléphone speak_to_associate: Vous pouvez vous adresser à n’importe quel employé de ce bureau de poste pour faire vérifier votre identité. prepare: @@ -89,9 +89,9 @@ fr: update_state_id: Mettre à jour les informations figurant sur votre document d’identité process: barcode: - caption_label: Code d’inscription # WILLFIX: Use approved content (LG-6841) + caption_label: Code d’inscription heading: Une copie de votre code-barres - image_alt: Code à barre # WILLFIX: Use approved content (LG-6841) + image_alt: Code-barres info: Imprimez ou numérisez depuis votre appareil mobile. proof_of_address: acceptable_proof: From 91176aab61acc9e1c0698f8be8e87839d29af4cf Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Thu, 14 Jul 2022 14:35:13 -0400 Subject: [PATCH 04/11] Update ticket reference for creating enrollment --- app/controllers/api/verify/password_confirm_controller.rb | 2 +- app/controllers/idv/personal_key_controller.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/verify/password_confirm_controller.rb b/app/controllers/api/verify/password_confirm_controller.rb index eb3d8943d38..c2c0b624bf6 100644 --- a/app/controllers/api/verify/password_confirm_controller.rb +++ b/app/controllers/api/verify/password_confirm_controller.rb @@ -56,7 +56,7 @@ def completion_url(result, user) def in_person_enrollment?(user) return false unless IdentityConfig.store.in_person_proofing_enabled - # WILLFIX: After LG-6708 and we have enrollment saved, reference enrollment instead. + # WILLFIX: After LG-6872 and we have enrollment saved, reference enrollment instead. ProofingComponent.find_by(user: user)&.document_check == Idp::Constants::Vendors::USPS end end diff --git a/app/controllers/idv/personal_key_controller.rb b/app/controllers/idv/personal_key_controller.rb index ff848ce2600..271e6f71ac8 100644 --- a/app/controllers/idv/personal_key_controller.rb +++ b/app/controllers/idv/personal_key_controller.rb @@ -76,7 +76,7 @@ def generate_personal_key def in_person_enrollment? return false unless IdentityConfig.store.in_person_proofing_enabled - # WILLFIX: After LG-6708 and we have enrollment saved, reference enrollment instead. + # WILLFIX: After LG-6872 and we have enrollment saved, reference enrollment instead. ProofingComponent.find_by(user: current_user)&.document_check == Idp::Constants::Vendors::USPS end From 519ad9f699783ad0be8524e3582d7890dc49f729 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Thu, 14 Jul 2022 15:22:48 -0400 Subject: [PATCH 05/11] Use new enrollment fields As of LG-6708, now available: selected_location_hours, current_address_matches_id --- .../in_person/ready_to_verify_controller.rb | 21 ++++++++++ .../in_person/ready_to_verify_presenter.rb | 33 +++------------- .../in_person/ready_to_verify/show.html.erb | 12 +++--- .../ready_to_verify_presenter_spec.rb | 38 ++++++++++--------- .../ready_to_verify/show.html.erb_spec.rb | 5 ++- 5 files changed, 55 insertions(+), 54 deletions(-) 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 3262699d3ad..9d9ead69d37 100644 --- a/app/controllers/idv/in_person/ready_to_verify_controller.rb +++ b/app/controllers/idv/in_person/ready_to_verify_controller.rb @@ -25,6 +25,27 @@ def enrollment profile: current_user.profiles.last, enrollment_code: '2048702198804358', created_at: Time.zone.now, + current_address_matches_id: true, + selected_location_details: { + 'name' => 'BALTIMORE — Post Office™', + 'streetAddress' => '900 E FAYETTE ST RM 118', + 'city' => 'BALTIMORE', + 'state' => 'MD', + 'zip5' => '21233', + 'zip4' => '9715', + 'phone' => '555-123-6409', + 'hours' => [ + { + 'weekdayHours' => '8:30 AM - 4:30 PM', + }, + { + 'saturdayHours' => '9:00 AM - 12:00 PM', + }, + { + 'sundayHours' => 'Closed', + }, + ], + }, ) end end 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 3e90ba3981d..d0ebf04fd7f 100644 --- a/app/presenters/idv/in_person/ready_to_verify_presenter.rb +++ b/app/presenters/idv/in_person/ready_to_verify_presenter.rb @@ -5,6 +5,8 @@ module Idv module InPerson class ReadyToVerifyPresenter + delegate :selected_location_details, to: :enrollment + def initialize(enrollment:) @enrollment = enrollment end @@ -21,40 +23,15 @@ def formatted_enrollment_code EnrollmentCodeFormatter.format(enrollment_code) end - def selected_location_details - # WILLFIX: After LG-6708, delegate this to enrollment. - { - name: 'BALTIMORE — Post Office™', - streetAddress: '900 E FAYETTE ST RM 118', - city: 'BALTIMORE', - state: 'MD', - zip5: '21233', - zip4: '9715', - phone: '555-123-6409', - hours: [ - { - weekdayHours: '8:30 AM - 4:30 PM', - }, - { - saturdayHours: '9:00 AM - 12:00 PM', - }, - { - sundayHours: 'Closed', - }, - ], - } - end - def selected_location_hours(prefix) - selected_location_details[:hours].each do |hours_candidate| - hours = hours_candidate["#{prefix}Hours".to_sym] + selected_location_details['hours'].each do |hours_candidate| + hours = hours_candidate["#{prefix}Hours"] return localized_hours(hours) if hours end end def needs_proof_of_address? - # WILLFIX: After LG-6708, return negated enrollment.current_address_matches_id - true + !enrollment.current_address_matches_id end private 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 b4f77a8ddc6..87984375a1e 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 @@ -78,12 +78,12 @@
-

<%= @presenter.selected_location_details[:name] %>

+

<%= @presenter.selected_location_details['name'] %>

- <%= @presenter.selected_location_details[:streetAddress] %>
- <%= @presenter.selected_location_details[:city] %>, - <%= @presenter.selected_location_details[:state] %> - <%= @presenter.selected_location_details[:zip5] %>-<%= @presenter.selected_location_details[:zip4] %> + <%= @presenter.selected_location_details['streetAddress'] %>
+ <%= @presenter.selected_location_details['city'] %>, + <%= @presenter.selected_location_details['state'] %> + <%= @presenter.selected_location_details['zip5'] %>-<%= @presenter.selected_location_details['zip4'] %>

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

@@ -93,7 +93,7 @@
<%= t('in_person_proofing.body.barcode.retail_phone_label') %>: - <%= @presenter.selected_location_details[:phone] %> + <%= @presenter.selected_location_details['phone'] %>
diff --git a/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb b/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb index 4241da4aed7..c7a90d8b2aa 100644 --- a/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb +++ b/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb @@ -12,6 +12,9 @@ profile: profile, enrollment_code: enrollment_code, created_at: created_at, + current_address_matches_id: current_address_matches_id, + selected_location_details: + JSON.parse(UspsIppFixtures.request_facilities_response)['postOffices'].first, ) end @@ -48,17 +51,17 @@ it 'returns a hash of location details associated with the enrollment' do expect(selected_location_details).to include( - name: kind_of(String), - streetAddress: kind_of(String), - city: kind_of(String), - state: kind_of(String), - zip5: kind_of(String), - zip4: kind_of(String), - phone: kind_of(String), - hours: array_including( - hash_including(weekdayHours: kind_of(String)), - hash_including(saturdayHours: kind_of(String)), - hash_including(sundayHours: kind_of(String)), + 'name' => kind_of(String), + 'streetAddress' => kind_of(String), + 'city' => kind_of(String), + 'state' => kind_of(String), + 'zip5' => kind_of(String), + 'zip4' => kind_of(String), + 'phone' => kind_of(String), + 'hours' => array_including( + hash_including('weekdayHours' => kind_of(String)), + hash_including('saturdayHours' => kind_of(String)), + hash_including('sundayHours' => kind_of(String)), ), ) end @@ -70,10 +73,10 @@ before do allow(presenter).to receive(:selected_location_details).and_return( - hours: [ - { weekdayHours: hours_open }, - { saturdayHours: hours_open }, - { sundayHours: hours_closed }, + 'hours' => [ + { 'weekdayHours' => hours_open }, + { 'saturdayHours' => hours_open }, + { 'sundayHours' => hours_closed }, ], ) end @@ -105,14 +108,13 @@ context 'with current address matching id' do let(:current_address_matches_id) { true } - it { expect(needs_proof_of_address).to eq true } + it { expect(needs_proof_of_address).to eq false } end context 'with current address not matching id' do let(:current_address_matches_id) { false } - # WILLFIX: After LG-6708, unskip and initialize enrollment with current_address_matches_id - xit { expect(needs_proof_of_address).to eq false } + it { expect(needs_proof_of_address).to eq true } end end 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 7e8516eda8b..4c35fde8344 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 @@ -14,14 +14,15 @@ profile: profile, enrollment_code: enrollment_code, created_at: created_at, + current_address_matches_id: current_address_matches_id, + selected_location_details: + JSON.parse(UspsIppFixtures.request_facilities_response)['postOffices'].first, ) end let(:presenter) { Idv::InPerson::ReadyToVerifyPresenter.new(enrollment: enrollment) } before do assign(:presenter, presenter) - # WILLFIX: After LG-6708, remove this and initialize enrollment with current_address_matches_id - allow(presenter).to receive(:needs_proof_of_address?).and_return(!current_address_matches_id) end context 'with enrollment where current address matches id' do From 1aebaec9494e307a4af717d58bf8c826da336ac3 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Thu, 14 Jul 2022 15:31:24 -0400 Subject: [PATCH 06/11] Remove duplicate MarketingSite article --- app/services/marketing_site.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/services/marketing_site.rb b/app/services/marketing_site.rb index afc37c16d3d..b4f6610c60b 100644 --- a/app/services/marketing_site.rb +++ b/app/services/marketing_site.rb @@ -12,7 +12,6 @@ class MarketingSite verify-your-identity/how-to-verify-in-person verify-your-identity/phone-number-and-phone-plan-in-your-name verify-your-identity/verify-your-address-by-mail - verify-your-identity/how-to-verify-in-person get-started/authentication-options ].to_set.freeze From f26906f6eaf95dc626bba369d4673caae7173037 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 15 Jul 2022 08:55:52 -0400 Subject: [PATCH 07/11] Use range text for days of week --- .../idv/in_person/ready_to_verify/show.html.erb | 2 +- config/locales/time/en.yml | 1 + config/locales/time/es.yml | 15 ++++++++------- config/locales/time/fr.yml | 15 ++++++++------- 4 files changed, 18 insertions(+), 15 deletions(-) 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 87984375a1e..585e4b53b3e 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 @@ -87,7 +87,7 @@

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

- <%= t('date.day_names')[0] %>–<%= t('date.day_names')[4] %>: <%= @presenter.selected_location_hours(:weekday) %>
+ <%= t('date.range', from: t('date.day_names')[0], to: t('date.day_names')[4]) %>: <%= @presenter.selected_location_hours(:weekday) %>
<%= t('date.day_names')[5] %>: <%= @presenter.selected_location_hours(:saturday) %>
<%= t('date.day_names')[6] %>: <%= @presenter.selected_location_hours(:sunday) %>
diff --git a/config/locales/time/en.yml b/config/locales/time/en.yml index 93ca66c8501..eeeb65fe150 100644 --- a/config/locales/time/en.yml +++ b/config/locales/time/en.yml @@ -23,6 +23,7 @@ en: - October - November - December + range: '%{from} to %{to}' time: am: AM formats: diff --git a/config/locales/time/es.yml b/config/locales/time/es.yml index 022fb7641a5..45d8a084b51 100644 --- a/config/locales/time/es.yml +++ b/config/locales/time/es.yml @@ -2,13 +2,13 @@ es: date: day_names: - - Lunes - - Martes - - Miércoles - - Jueves - - Viernes - - Sábado - - Domingo + - lunes + - martes + - miércoles + - jueves + - viernes + - sábado + - domingo month_names: - null - enero @@ -23,6 +23,7 @@ es: - octubre - noviembre - diciembre + range: 'De %{from} a %{to}' time: am: AM formats: diff --git a/config/locales/time/fr.yml b/config/locales/time/fr.yml index bbe2df23dbc..fd9d8ca42f1 100644 --- a/config/locales/time/fr.yml +++ b/config/locales/time/fr.yml @@ -2,13 +2,13 @@ fr: date: day_names: - - Lundi - - Mardi - - Mercredi - - Jeudi - - Vendredi - - Samedi - - Dimanche + - lundi + - mardi + - mercredi + - jeudi + - vendredi + - samedi + - dimanche month_names: - null - janvier @@ -23,6 +23,7 @@ fr: - octobre - novembre - décembre + range: 'Du %{from} au %{to}' time: am: A.M. formats: From 34ce738be71a0bfa7a07de73f14a6b3b69be2296 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 15 Jul 2022 10:17:12 -0400 Subject: [PATCH 08/11] Display due date as expected by USPS enrollment --- app/presenters/idv/in_person/ready_to_verify_presenter.rb | 5 ++++- .../idv/in_person/ready_to_verify_presenter_spec.rb | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) 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 d0ebf04fd7f..e48fcdced0c 100644 --- a/app/presenters/idv/in_person/ready_to_verify_presenter.rb +++ b/app/presenters/idv/in_person/ready_to_verify_presenter.rb @@ -5,6 +5,9 @@ module Idv module InPerson class ReadyToVerifyPresenter + # WILLFIX: With LG-6881, confirm timezone or use deadline from enrollment response. + USPS_SERVER_TIMEZONE = ActiveSupport::TimeZone['America/New_York'] + delegate :selected_location_details, to: :enrollment def initialize(enrollment:) @@ -16,7 +19,7 @@ def barcode_data_url end def formatted_due_date - due_date.strftime(I18n.t('time.formats.event_date')) + due_date.in_time_zone(USPS_SERVER_TIMEZONE).strftime(I18n.t('time.formats.event_date')) end def formatted_enrollment_code diff --git a/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb b/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb index c7a90d8b2aa..840ddc4a2a4 100644 --- a/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb +++ b/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb @@ -5,7 +5,9 @@ let(:profile) { build(:profile, user: user) } let(:enrollment_code) { '2048702198804358' } let(:current_address_matches_id) { true } - let(:created_at) { Time.zone.parse('2022-07-13') } + let(:created_at) do + ActiveSupport::TimeZone[described_class::USPS_SERVER_TIMEZONE].parse('2022-07-14T00:00:00Z') + end let(:enrollment) do InPersonEnrollment.new( user: user, @@ -31,6 +33,10 @@ describe '#formatted_due_date' do subject(:formatted_due_date) { presenter.formatted_due_date } + around do |example| + Time.use_zone('UTC') { example.run } + end + it 'returns a formatted due date' do expect(formatted_due_date).to eq 'August 12, 2022' end From 3aec4cce683827446109e12a9563b5778c447936 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 15 Jul 2022 10:28:12 -0400 Subject: [PATCH 09/11] Use USPS timezone in feature spec assertions --- spec/features/idv/in_person_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/features/idv/in_person_spec.rb b/spec/features/idv/in_person_spec.rb index 2c48c75a122..a9d32a4bf0d 100644 --- a/spec/features/idv/in_person_spec.rb +++ b/spec/features/idv/in_person_spec.rb @@ -103,6 +103,7 @@ freeze_time do acknowledge_and_confirm_personal_key deadline = (Time.zone.now + IdentityConfig.store.in_person_enrollment_validity_in_days.days). + in_time_zone(Idv::InPerson::ReadyToVerifyPresenter::USPS_SERVER_TIMEZONE). strftime(t('time.formats.event_date')) end From ac07bc64407788c771df2b9438eef6e33b72e7c4 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 15 Jul 2022 12:19:57 -0400 Subject: [PATCH 10/11] Timezone is already ActiveSupport::Timezone --- .../idv/in_person/ready_to_verify_presenter_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb b/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb index 840ddc4a2a4..f0951f55415 100644 --- a/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb +++ b/spec/presenters/idv/in_person/ready_to_verify_presenter_spec.rb @@ -5,9 +5,7 @@ let(:profile) { build(:profile, user: user) } let(:enrollment_code) { '2048702198804358' } let(:current_address_matches_id) { true } - let(:created_at) do - ActiveSupport::TimeZone[described_class::USPS_SERVER_TIMEZONE].parse('2022-07-14T00:00:00Z') - end + let(:created_at) { described_class::USPS_SERVER_TIMEZONE.parse('2022-07-14T00:00:00Z') } let(:enrollment) do InPersonEnrollment.new( user: user, From d52bc7966772ef0cdfa5acc01efb7e7653cbc4f6 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 15 Jul 2022 14:40:01 -0400 Subject: [PATCH 11/11] Omit profile from sample enrollment Could 500 if user doesn't have a profile --- app/controllers/idv/in_person/ready_to_verify_controller.rb | 1 - 1 file changed, 1 deletion(-) 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 9d9ead69d37..da440e4805c 100644 --- a/app/controllers/idv/in_person/ready_to_verify_controller.rb +++ b/app/controllers/idv/in_person/ready_to_verify_controller.rb @@ -22,7 +22,6 @@ def confirm_in_person_session def enrollment InPersonEnrollment.new( user: current_user, - profile: current_user.profiles.last, enrollment_code: '2048702198804358', created_at: Time.zone.now, current_address_matches_id: true,