Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion app/forms/idv/doc_pii_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ class DocPiiForm
validates_presence_of :state_id_number, { message: proc {
I18n.t('doc_auth.errors.general.no_liveness')
} }
validate :state_id_expired?

attr_reader :first_name, :last_name, :dob, :address1, :state, :zipcode, :attention_with_barcode,
:jurisdiction, :state_id_number
:jurisdiction, :state_id_number, :state_id_expiration
alias_method :attention_with_barcode?, :attention_with_barcode

def initialize(pii:, attention_with_barcode: false)
Expand All @@ -33,6 +34,7 @@ def initialize(pii:, attention_with_barcode: false)
@zipcode = pii[:zipcode]
@jurisdiction = pii[:state_id_jurisdiction]
@state_id_number = pii[:state_id_number]
@state_id_expiration = pii[:state_id_expiration]
@attention_with_barcode = attention_with_barcode
end

Expand Down Expand Up @@ -106,6 +108,12 @@ def dob_valid?
end
end

def state_id_expired?
if state_id_expiration && DateParser.parse_legacy(state_id_expiration).past?
errors.add(:state_id_expiration, generic_error, type: :state_id_expiration)
end
end

def zipcode_valid?
return if zipcode.is_a?(String) && zipcode.present?

Expand Down
8 changes: 4 additions & 4 deletions app/services/doc_auth/mock/yml_loader_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ module YmlLoaderConcern
def parse_yaml(uploaded_file)
data = YAML.safe_load(uploaded_file, permitted_classes: [Date])
if data.is_a?(Hash)
if (m = data.dig('document', 'dob').to_s.
match(%r{(?<month>\d{1,2})/(?<day>\d{1,2})/(?<year>\d{4})}))
data['document']['dob'] =
Date.new(m[:year].to_i, m[:month].to_i, m[:day].to_i)
['dob', 'state_id_expiration'].each do |date_key|
if (date_s = data.dig('document', date_key))
data['document'][date_key] = DateParser.parse_legacy(date_s)
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah! I just got done writing a very similar code block here independently while working on LG-13517. I think our PRs are going to mesh nicely. Excellent.

end

if data.dig('document', 'zipcode')
Expand Down
108 changes: 103 additions & 5 deletions spec/controllers/idv/image_uploads_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@
let(:state) { 'ND' }
let(:state_id_type) { 'drivers_license' }
let(:dob) { '10/06/1938' }
let(:state_id_expiration) { Time.zone.today.to_s }
let(:jurisdiction) { 'ND' }
let(:zipcode) { '12345' }
let(:country_code) { 'USA' }
Expand Down Expand Up @@ -474,7 +475,7 @@
zipcode: zipcode,
address2: nil,
city: nil,
state_id_expiration: nil,
state_id_expiration: state_id_expiration,
state_id_issued: nil,
issuing_country_code: nil,
),
Expand Down Expand Up @@ -575,7 +576,7 @@
Back: hash_including(ClassName: 'Identification Card', CountryCode: 'USA'),
),
id_issued_status: 'missing',
id_expiration_status: 'missing',
id_expiration_status: 'present',
)
end
end
Expand Down Expand Up @@ -673,7 +674,7 @@
Back: hash_including(ClassName: 'Identification Card', CountryCode: 'USA'),
),
id_issued_status: 'missing',
id_expiration_status: 'missing',
id_expiration_status: 'present',
)
end
end
Expand Down Expand Up @@ -768,7 +769,7 @@
liveness_checking_required: boolean,
classification_info: hash_including(:Front, :Back),
id_issued_status: 'missing',
id_expiration_status: 'missing',
id_expiration_status: 'present',
)
end
end
Expand Down Expand Up @@ -863,7 +864,104 @@
liveness_checking_required: boolean,
classification_info: hash_including(:Front, :Back),
id_issued_status: 'missing',
id_expiration_status: 'missing',
id_expiration_status: 'present',
)
end
end

context 'but doc_pii validation fails due to invalid state_id_expiration' do
let(:state_id_expiration) { Time.zone.today - 1.day }

it 'tracks dob validation errors in analytics' do
stub_analytics

action

expect(@analytics).to have_logged_event(
'IdV: doc auth image upload form submitted',
success: true,
errors: {},
error_details: nil,
user_id: user.uuid,
submit_attempts: 1,
remaining_submit_attempts: IdentityConfig.store.doc_auth_max_attempts - 1,
flow_path: 'standard',
front_image_fingerprint: an_instance_of(String),
back_image_fingerprint: an_instance_of(String),
selfie_image_fingerprint: nil,
liveness_checking_required: boolean,
)

expect(@analytics).to have_logged_event(
'IdV: doc auth image upload vendor submitted',
success: true,
errors: {},
attention_with_barcode: false,
async: false,
billed: true,
exception: nil,
doc_auth_result: 'Passed',
state: 'ND',
state_id_type: 'drivers_license',
user_id: user.uuid,
submit_attempts: 1,
remaining_submit_attempts: IdentityConfig.store.doc_auth_max_attempts - 1,
client_image_metrics: {
front: { glare: 99.99 },
back: { glare: 99.99 },
},
flow_path: 'standard',
vendor_request_time_in_ms: a_kind_of(Float),
front_image_fingerprint: an_instance_of(String),
back_image_fingerprint: an_instance_of(String),
selfie_image_fingerprint: nil,
doc_type_supported: boolean,
doc_auth_success: boolean,
selfie_status: :not_processed,
liveness_checking_required: boolean,
selfie_live: true,
selfie_quality_good: true,
address_line2_present: nil,
alert_failure_count: nil,
conversation_id: nil,
request_id: nil,
decision_product_status: nil,
image_metrics: nil,
log_alert_results: nil,
portrait_match_results: nil,
processed_alerts: nil,
product_status: nil,
reference: nil,
transaction_reason_code: nil,
transaction_status: nil,
vendor: nil,
birth_year: 1938,
zip_code: '12345',
)

expect(@analytics).to have_logged_event(
'IdV: doc auth image upload vendor pii validation',
success: false,
errors: {
state_id_expiration: [
'Try taking new pictures.',
],
},
error_details: {
state_id_expiration: { state_id_expiration: true },
},
attention_with_barcode: false,
user_id: user.uuid,
submit_attempts: 1,
remaining_submit_attempts: IdentityConfig.store.doc_auth_max_attempts - 1,
flow_path: 'standard',
front_image_fingerprint: an_instance_of(String),
back_image_fingerprint: an_instance_of(String),
selfie_image_fingerprint: nil,
liveness_checking_required: boolean,
classification_info: hash_including(:Front, :Back),
id_issued_status: 'missing',
id_expiration_status: 'present',
)
end
end
Expand Down
Loading