Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lg-14277 verification data analytics event #11509

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion app/controllers/socure_webhook_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def fetch_results
if IdentityConfig.store.ruby_workers_idv_enabled
SocureDocvResultsJob.perform_later(document_capture_session_uuid: dcs.uuid)
else
SocureDocvResultsJob.perform_now(document_capture_session_uuid: dcs.uuid)
SocureDocvResultsJob.perform_now(document_capture_session_uuid: dcs.uuid, async: false)
end
end

Expand Down
61 changes: 43 additions & 18 deletions app/jobs/socure_docv_results_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,48 @@
class SocureDocvResultsJob < ApplicationJob
queue_as :high_socure_docv

attr_reader :document_capture_session_uuid
attr_reader :document_capture_session_uuid, :async

# @param [String] document_capture_session_uuid
def perform(document_capture_session_uuid:)
def perform(document_capture_session_uuid:, async: true)
@document_capture_session_uuid = document_capture_session_uuid
@async = async
AShukla-GSA marked this conversation as resolved.
Show resolved Hide resolved
solipet marked this conversation as resolved.
Show resolved Hide resolved

dcs = DocumentCaptureSession.find_by(uuid: document_capture_session_uuid)
raise "DocumentCaptureSession not found: #{document_capture_session_uuid}" if !dcs
raise "DocumentCaptureSession not found: #{document_capture_session_uuid}" unless
document_capture_session

# analytics = create_analytics(
# user: dcs.user,
# service_provider_issuer: dcs.issuer,
# )

result = socure_document_verification_result
dcs.store_result_from_response(result)
timer = JobHelpers::Timer.new
response = timer.time('vendor_request') do
socure_document_verification_result
end
log_verification_request(
docv_result_response: response,
vendor_request_time_in_ms: timer.results['vendor_request'],
)
document_capture_session.store_result_from_response(response)
end

private

def create_analytics(
user:,
service_provider_issuer:
)
Analytics.new(
user:,
def analytics
@analytics ||= Analytics.new(
user: document_capture_session.user,
request: nil,
sp: service_provider_issuer,
session: {},
sp: document_capture_session.issuer,
)
end

def log_verification_request(docv_result_response:, vendor_request_time_in_ms:)
analytics.idv_socure_verification_data_requested(
**docv_result_response.to_h.merge(
docv_transaction_token: document_capture_session.socure_docv_transaction_token,
submit_attempts: rate_limiter&.attempts,
remaining_submit_attempts: rate_limiter&.remaining_count,
vendor_request_time_in_ms:,
async:,
).except(:attention_with_barcode, :selfie_live, :selfie_quality_good,
:selfie_status).compact,
)
end

Expand All @@ -40,4 +53,16 @@ def socure_document_verification_result
document_capture_session_uuid:,
).fetch
end

def document_capture_session
@document_capture_session ||=
DocumentCaptureSession.find_by(uuid: document_capture_session_uuid)
end

def rate_limiter
@rate_limiter ||= RateLimiter.new(
user: document_capture_session.user,
rate_limit_type: :idv_doc_auth,
)
end
end
95 changes: 95 additions & 0 deletions app/services/analytics_events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4708,6 +4708,101 @@ def idv_socure_shadow_mode_proofing_result_missing(**extra)
track_event(:idv_socure_shadow_mode_proofing_result_missing, **extra)
end

# @param [Boolean] success Whether form validation was successful
# @param [Hash] errors Errors resulting from form validation
# @param [String] exception
# @param [Boolean] billed
# @param [String] docv_transaction_token socure transaction token
# @param [Hash] customer_profile socure customer profile
# @param [String] reference_id socure interal id for transaction
# @param [Hash] reason_codes socure internal reason codes for accept reject decision
# @param [Hash] document_type type of socument submitted (Drivers Licenese, etc.)
# @param [Hash] decision accept or reject of given ID
# @param [String] user_id internal id of socure user
# @param [String] state state of ID
# @param [String] state_id_type type of state issued ID
# @param [Boolean] async whether or not this worker is running asynchronously
# @param [Integer] submit_attempts Times that user has tried submitting (previously called
# "attempts")
# @param [Integer] remaining_submit_attempts (previously called "remaining_attempts")
# @param ["hybrid","standard"] flow_path Document capture user flow
# @param [Float] vendor_request_time_in_ms Time it took to upload images & get a response.
# @param [Boolean] doc_type_supported
# @param [Boolean] doc_auth_success
# @param [Boolean] liveness_checking_required Whether or not the selfie is required
# @param [Boolean] liveness_enabled Whether or not the selfie result is included in response
# @param [String] vendor which 2rd party we are using for doc auth
# @param [Boolean] address_line2_present wether or not we have an address that uses the 2nd line
# @param [String] zip_code zip code from state issued ID
# @param [String] birth_year Birth year from document
# @param [Integer] issue_year Year document was issued
# @param [Boolean] biometric_comparison_required does doc auth require biometirc
# The request for socure verification was sent
def idv_socure_verification_data_requested(
success:,
errors:,
async:,
customer_profile:,
reference_id:,
reason_codes:,
document_type:,
decision:,
state:,
state_id_type:,
submit_attempts:,
remaining_submit_attempts:,
liveness_checking_required:,
issue_year:,
vendor_request_time_in_ms:,
doc_type_supported:,
doc_auth_success:,
vendor:,
address_line2_present:,
zip_code:,
birth_year:,
liveness_enabled:,
biometric_comparison_required:,
docv_transaction_token: nil,
user_id: nil,
exception: nil,
flow_path: nil,
billed: nil,
**extra
)
track_event(
:idv_socure_verification_data_requested,
success:,
errors:,
exception:,
billed:,
docv_transaction_token:,
customer_profile:,
reference_id:,
reason_codes:,
document_type:,
decision:,
user_id:,
state:,
state_id_type:,
async:,
submit_attempts:,
remaining_submit_attempts:,
flow_path:,
liveness_checking_required:,
vendor_request_time_in_ms:,
doc_type_supported:,
doc_auth_success:,
vendor:,
address_line2_present:,
zip_code:,
birth_year:,
issue_year:,
liveness_enabled:,
biometric_comparison_required:,
**extra,
)
end

# @param [String] step
# @param [String] location
# @param [Hash,nil] proofing_components User's current proofing components
Expand Down
60 changes: 49 additions & 11 deletions app/services/doc_auth/socure/responses/docv_result_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ class DocvResultResponse < DocAuth::Response
document_number: %w[documentVerification documentData documentNumber],
issue_date: %w[documentVerification documentData issueDate],
expiration_date: %w[documentVerification documentData expirationDate],
customer_profile: %w[customerProfile],
socure_customer_user_id: %w[customerProfile customerUserId],
socure_user_id: %w[customerProfile userId],
}.freeze

def initialize(http_response:, biometric_comparison_required: false)
def initialize(http_response:,
biometric_comparison_required: false)
@http_response = http_response
@biometric_comparison_required = biometric_comparison_required
@pii_from_doc = read_pii
Expand Down Expand Up @@ -63,6 +67,28 @@ def selfie_status
:not_processed
end

def extra_attributes
{
reference_id: get_data(DATA_PATHS[:reference_id]),
decision: get_data(DATA_PATHS[:decision]),
biometric_comparison_required: biometric_comparison_required,
customer_profile: get_data(DATA_PATHS[:customer_profile]),
reason_codes: get_data(DATA_PATHS[:reason_codes]),
document_type: get_data(DATA_PATHS[:document_type]),
state: state,
state_id_type: state_id_type,
flow_path: nil,
liveness_checking_required: @biometric_comparison_required,
issue_year: state_id_issued&.year,
doc_auth_success: successful_result?,
vendor: 'Socure',
address_line2_present: address2.present?,
zip_code: zipcode,
birth_year: dob&.year,
liveness_enabled: @biometric_comparison_required,
}
end

private

def successful_result?
Expand All @@ -77,22 +103,14 @@ def error_messages
}
end

def extra_attributes
{
reference_id: get_data(DATA_PATHS[:reference_id]),
decision: get_data(DATA_PATHS[:decision]),
biometric_comparison_required: biometric_comparison_required,
}
end

def read_pii
Pii::StateId.new(
first_name: get_data(DATA_PATHS[:first_name]),
middle_name: get_data(DATA_PATHS[:middle_name]),
last_name: get_data(DATA_PATHS[:last_name]),
name_suffix: nil,
address1: get_data(DATA_PATHS[:address1]),
address2: get_data(DATA_PATHS[:address2]),
address2:,
city: get_data(DATA_PATHS[:city]),
state: get_data(DATA_PATHS[:state]),
zipcode: get_data(DATA_PATHS[:zipcode]),
Expand All @@ -102,7 +120,7 @@ def read_pii
weight: nil,
eye_color: nil,
state_id_number: get_data(DATA_PATHS[:document_number]),
state_id_issued: parse_date(get_data(DATA_PATHS[:issue_date])),
state_id_issued:,
state_id_expiration: parse_date(get_data(DATA_PATHS[:expiration_date])),
state_id_type: state_id_type,
state_id_jurisdiction: get_data(DATA_PATHS[:issuing_state]),
Expand All @@ -124,11 +142,31 @@ def parsed_response_body
end
end

def state
get_data(DATA_PATHS[:state])
end

def zipcode
get_data(DATA_PATHS[:zipcode])
end

def state_id_issued
parse_date(get_data(DATA_PATHS[:issue_date]))
end

def state_id_type
type = get_data(DATA_PATHS[:id_type])
type&.gsub(/\W/, '')&.underscore
end

def dob
parse_date(get_data(DATA_PATHS[:dob]))
end

def address2
get_data(DATA_PATHS[:address2])
end

def parse_date(date_string)
Date.parse(date_string)
rescue ArgumentError, TypeError
Expand Down
1 change: 1 addition & 0 deletions app/services/idv/analytics_events_enhancer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module AnalyticsEventsEnhancer
idv_doc_auth_ssn_visited
idv_doc_auth_submitted_image_upload_form
idv_doc_auth_submitted_image_upload_vendor
idv_socure_verification_data_requested
idv_doc_auth_submitted_pii_validation
idv_doc_auth_verify_proofing_results
idv_doc_auth_verify_submitted
Expand Down
14 changes: 13 additions & 1 deletion spec/features/idv/doc_auth/socure_document_capture_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@

context 'successfully processes image on last attempt' do
before do
allow(IdentityConfig.store).to receive(:ruby_workers_idv_enabled).and_return(false)
DocAuth::Mock::DocAuthMockClient.reset!
allow(Analytics).to receive(:new).and_return(fake_analytics)
end

it 'proceeds to the next page with valid info' do
Expand All @@ -76,13 +78,15 @@
socure_docv_upload_documents(
docv_transaction_token: @docv_transaction_token,
)

visit idv_socure_document_capture_update_path
expect(page).to have_current_path(idv_ssn_url)

visit idv_socure_document_capture_path

expect(page).to have_current_path(idv_session_errors_rate_limited_path)
expect(fake_analytics).to have_logged_event(
:idv_socure_verification_data_requested,
)
end
end
end
Expand Down Expand Up @@ -119,6 +123,11 @@
end

context 'standard mobile flow' do
before do
allow(IdentityConfig.store).to receive(:ruby_workers_idv_enabled).and_return(false)
allow(Analytics).to receive(:new).and_return(fake_analytics)
end

it 'proceeds to the next page with valid info' do
perform_in_browser(:mobile) do
visit_idp_from_oidc_sp_with_ial2
Expand All @@ -135,6 +144,9 @@
expect(page).to have_current_path(idv_ssn_url)

expect(DocAuthLog.find_by(user_id: @user.id).state).to eq('NY')
expect(fake_analytics).to have_logged_event(
:idv_socure_verification_data_requested,
)

fill_out_ssn_form_ok
click_idv_continue
Expand Down
Loading