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
43 changes: 30 additions & 13 deletions app/jobs/get_usps_proofing_results_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ def enrollment_analytics_attributes(enrollment, complete:)
}
end

def response_analytics_attributes(response)
{
fraud_suspected: response['fraudSuspected'],
primary_id_type: response['primaryIdType'],
secondary_id_type: response['secondaryIdType'],
failure_reason: response['failureReason'],
transaction_end_date_time: response['transactionEndDateTime'],
transaction_start_date_time: response['transactionStartDateTime'],
status: response['status'],
Comment on lines +33 to +39
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.

IMO I think all this switching of cases might be a good hint to move the processing of the response to the USPS proofer client class, have it return a Struct or equivalent object that has snake_case keys already (similar to https://cm-jira.usa.gov/browse/LG-7025)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for raising this point! I will make another ticket to address it.

assurance_level: response['assuranceLevel'],
proofing_post_office: response['proofingPostOffice'],
proofing_city: response['proofingCity'],
proofing_state: response['proofingState'],
scan_count: response['scanCount'],
response_message: response['responseMessage'],
}
end

def perform(_now)
return true unless IdentityConfig.store.in_person_proofing_enabled

Expand Down Expand Up @@ -107,10 +125,11 @@ def handle_bad_request_error(err, enrollment)
# Customer has not been to post office for IPP
enrollment_outcomes[:enrollments_in_progress] += 1
when IPP_EXPIRED_ERROR_MESSAGE
handle_expired_status_update(enrollment)
handle_expired_status_update(enrollment, err.response)
else
analytics(user: enrollment.user).idv_in_person_usps_proofing_results_job_exception(
**enrollment_analytics_attributes(enrollment, complete: false),
**response_analytics_attributes(err.response),
reason: 'Request exception',
exception_class: err.class.to_s,
exception_message: err.message,
Expand All @@ -123,6 +142,7 @@ def handle_standard_error(err, enrollment)
enrollment_outcomes[:enrollments_errored] += 1
analytics(user: enrollment.user).idv_in_person_usps_proofing_results_job_exception(
**enrollment_analytics_attributes(enrollment, complete: false),
**response_analytics_attributes(err.response),
reason: 'Request exception',
exception_class: err.class.to_s,
exception_message: err.message,
Expand All @@ -137,19 +157,21 @@ def handle_response_is_not_a_hash(enrollment)
)
end

def handle_unsupported_status(enrollment, status)
def handle_unsupported_status(enrollment, response)
enrollment_outcomes[:enrollments_errored] += 1
analytics(user: enrollment.user).idv_in_person_usps_proofing_results_job_exception(
**enrollment_analytics_attributes(enrollment, complete: false),
**response_analytics_attributes(response),
reason: 'Unsupported status',
status: status,
status: response['status'],
)
end

def handle_unsupported_id_type(enrollment, response)
enrollment_outcomes[:enrollments_failed] += 1
analytics(user: enrollment.user).idv_in_person_usps_proofing_results_job_enrollment_updated(
**enrollment_analytics_attributes(enrollment, complete: true),
**response_analytics_attributes(response),
fraud_suspected: response['fraudSuspected'],
passed: false,
primary_id_type: response['primaryIdType'],
Expand All @@ -158,11 +180,11 @@ def handle_unsupported_id_type(enrollment, response)
enrollment.update(status: :failed)
end

def handle_expired_status_update(enrollment)
def handle_expired_status_update(enrollment, response)
enrollment_outcomes[:enrollments_expired] += 1
analytics(user: enrollment.user).idv_in_person_usps_proofing_results_job_enrollment_updated(
**enrollment_analytics_attributes(enrollment, complete: true),
fraud_suspected: nil,
**response_analytics_attributes(response[:body]),
passed: false,
reason: 'Enrollment has expired',
)
Expand All @@ -173,15 +195,9 @@ def handle_failed_status(enrollment, response)
enrollment_outcomes[:enrollments_failed] += 1
analytics(user: enrollment.user).idv_in_person_usps_proofing_results_job_enrollment_updated(
**enrollment_analytics_attributes(enrollment, complete: true),
failure_reason: response['failureReason'],
fraud_suspected: response['fraudSuspected'],
**response_analytics_attributes(response),
passed: false,
primary_id_type: response['primaryIdType'],
proofing_state: response['proofingState'],
reason: 'Failed status',
secondary_id_type: response['secondaryIdType'],
transaction_end_date_time: response['transactionEndDateTime'],
transaction_start_date_time: response['transactionStartDateTime'],
)

enrollment.update(status: :failed)
Expand All @@ -192,6 +208,7 @@ def handle_successful_status_update(enrollment, response)
enrollment_outcomes[:enrollments_passed] += 1
analytics(user: enrollment.user).idv_in_person_usps_proofing_results_job_enrollment_updated(
**enrollment_analytics_attributes(enrollment, complete: true),
**response_analytics_attributes(**response),
fraud_suspected: response['fraudSuspected'],
passed: true,
reason: 'Successful status update',
Expand All @@ -218,7 +235,7 @@ def process_enrollment_response(enrollment, response)
when IPP_STATUS_FAILED
handle_failed_status(enrollment, response)
else
handle_unsupported_status(enrollment, response['status'])
handle_unsupported_status(enrollment, response)
end
end

Expand Down
51 changes: 51 additions & 0 deletions app/services/analytics_events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2521,11 +2521,45 @@ def idv_in_person_usps_proofing_results_job_completed(
# @param [String] enrollment_id
# @param [String] exception_class
# @param [String] exception_message
# @param [String] enrollment_code
# @param [Float] minutes_since_last_status_check
# @param [Float] minutes_since_last_status_update
# @param [Float] minutes_to_completion
# @param [Boolean] fraud_suspected
# @param [String] primary_id_type
# @param [String] secondary_id_type
# @param [String] failure_reason
# @param [String] transaction_end_date_time
# @param [String] transaction_start_date_time
# @param [String] status
# @param [String] assurance_level
# @param [String] proofing_post_office
# @param [String] proofing_city
# @param [String] proofing_state
# @param [String] scan_count
# @param [String] response_message
def idv_in_person_usps_proofing_results_job_exception(
reason:,
enrollment_id:,
exception_class: nil,
exception_message: nil,
enrollment_code: nil,
minutes_since_last_status_check: nil,
minutes_since_last_status_update: nil,
minutes_to_completion: nil,
fraud_suspected: nil,
primary_id_type: nil,
secondary_id_type: nil,
failure_reason: nil,
transaction_end_date_time: nil,
transaction_start_date_time: nil,
status: nil,
assurance_level: nil,
proofing_post_office: nil,
proofing_city: nil,
proofing_state: nil,
scan_count: nil,
response_message: nil,
**extra
)
track_event(
Expand All @@ -2534,6 +2568,23 @@ def idv_in_person_usps_proofing_results_job_exception(
enrollment_id: enrollment_id,
exception_class: exception_class,
exception_message: exception_message,
enrollment_code: enrollment_code,
minutes_since_last_status_check: minutes_since_last_status_check,
minutes_since_last_status_update: minutes_since_last_status_update,
minutes_to_completion: minutes_to_completion,
fraud_suspected: fraud_suspected,
primary_id_type: primary_id_type,
secondary_id_type: secondary_id_type,
failure_reason: failure_reason,
transaction_end_date_time: transaction_end_date_time,
transaction_start_date_time: transaction_start_date_time,
status: status,
assurance_level: assurance_level,
proofing_post_office: proofing_post_office,
proofing_city: proofing_city,
proofing_state: proofing_state,
scan_count: scan_count,
response_message: response_message,
**extra,
)
end
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
{
"status": "In-person expired",
"proofingPostOffice": "WILKES BARRE",
"proofingCity": "WILKES BARRE",
"proofingState": "PA",
"enrollmentCode": "2090002197604352",
"primaryIdType": "Uniformed Services identification card",
"transactionStartDateTime": "12/17/2020 033855",
"transactionEndDateTime": "12/17/2020 034055",
"secondaryIdType": "Deed of Trust",
"responseMessage": "More than 30 days have passed since opt-in to IPP",
"fraudSuspected": false,
"proofingConfirmationNumber": "350040248346707",
"ippAssuranceLevel": "1.5"
}
"responseMessage": "More than 30 days have passed since opt-in to IPP"
}
69 changes: 51 additions & 18 deletions spec/jobs/get_usps_proofing_results_job_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'rails_helper'

RSpec.shared_examples 'enrollment with a status update' do |passed:, status:|
RSpec.shared_examples 'enrollment with a status update' do |passed:, status:, response_json:|
it 'logs a message with common attributes' do
freeze_time do
pending_enrollment.update(
Expand All @@ -12,14 +12,28 @@
job.perform(Time.zone.now)
end

response = JSON.parse(response_json)
expect(job_analytics).to have_logged_event(
'GetUspsProofingResultsJob: Enrollment status updated',
assurance_level: response['assuranceLevel'],
enrollment_code: pending_enrollment.enrollment_code,
enrollment_id: pending_enrollment.id,
failure_reason: response['failureReason'],
fraud_suspected: response['fraudSuspected'],
minutes_since_last_status_check: 15.0,
minutes_since_last_status_update: 2.days.in_minutes,
minutes_to_completion: 3.days.in_minutes,
passed: passed,
primary_id_type: response['primaryIdType'],
proofing_city: response['proofingCity'],
proofing_post_office: response['proofingPostOffice'],
proofing_state: response['proofingState'],
response_message: response['responseMessage'],
scan_count: response['scanCount'],
secondary_id_type: response['secondaryIdType'],
status: response['status'],
transaction_end_date_time: response['transactionEndDateTime'],
transaction_start_date_time: response['transactionStartDateTime'],
)
end

Expand Down Expand Up @@ -300,14 +314,19 @@
stub_request_passed_proofing_results
end

it_behaves_like('enrollment with a status update', passed: true, status: 'passed')
it_behaves_like(
'enrollment with a status update',
passed: true,
status: 'passed',
response_json: UspsInPersonProofing::Mock::Fixtures.
request_passed_proofing_results_response,
)

it 'logs details about the success' do
job.perform(Time.zone.now)

expect(job_analytics).to have_logged_event(
'GetUspsProofingResultsJob: Enrollment status updated',
fraud_suspected: false,
reason: 'Successful status update',
)
end
Expand All @@ -318,21 +337,19 @@
stub_request_failed_proofing_results
end

it_behaves_like('enrollment with a status update', passed: false, status: 'failed')
it_behaves_like(
'enrollment with a status update',
passed: false,
status: 'failed',
response_json: UspsInPersonProofing::Mock::Fixtures.
request_failed_proofing_results_response,
)

it 'logs failure details' do
job.perform(Time.zone.now)

expect(job_analytics).to have_logged_event(
'GetUspsProofingResultsJob: Enrollment status updated',
failure_reason: 'Clerk indicates that ID name or address does not match source data.',
fraud_suspected: false,
primary_id_type: 'Uniformed Services identification card',
proofing_state: 'PA',
reason: 'Failed status',
secondary_id_type: 'Deed of Trust',
transaction_end_date_time: '12/17/2020 034055',
transaction_start_date_time: '12/17/2020 033855',
Comment on lines -328 to -335
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.

😎

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

😎

)
end
end
Expand All @@ -342,15 +359,19 @@
stub_request_passed_proofing_unsupported_id_results
end

it_behaves_like('enrollment with a status update', passed: false, status: 'failed')
it_behaves_like(
'enrollment with a status update',
passed: false,
status: 'failed',
response_json: UspsInPersonProofing::Mock::Fixtures.
request_passed_proofing_unsupported_id_results_response,
)

it 'logs a message about the unsupported ID' do
job.perform Time.zone.now

expect(job_analytics).to have_logged_event(
'GetUspsProofingResultsJob: Enrollment status updated',
fraud_suspected: false,
primary_id_type: 'Not supported',
reason: 'Unsupported ID type',
)
end
Expand All @@ -361,7 +382,13 @@
stub_request_expired_proofing_results
end

it_behaves_like('enrollment with a status update', passed: false, status: 'expired')
it_behaves_like(
'enrollment with a status update',
passed: false,
status: 'expired',
response_json: UspsInPersonProofing::Mock::Fixtures.
request_expired_proofing_results_response,
)

it 'logs that the enrollment expired' do
job.perform(Time.zone.now)
Expand All @@ -378,15 +405,21 @@
stub_request_proofing_results_with_responses({})
end

it_behaves_like('enrollment encountering an exception', reason: 'Bad response structure')
it_behaves_like(
'enrollment encountering an exception',
reason: 'Bad response structure',
)
end

context 'when USPS returns an unexpected status' do
before(:each) do
stub_request_passed_proofing_unsupported_status_results
end

it_behaves_like('enrollment encountering an exception', reason: 'Unsupported status')
it_behaves_like(
'enrollment encountering an exception',
reason: 'Unsupported status',
)

it 'logs the status received' do
job.perform(Time.zone.now)
Expand Down
9 changes: 5 additions & 4 deletions spec/support/usps_ipp_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,17 @@ def request_failed_proofing_results_args

def stub_request_passed_proofing_unsupported_id_results
stub_request(:post, %r{/ivs-ippaas-api/IPPRest/resources/rest/getProofingResults}).to_return(
status: 200, body: UspsInPersonProofing::Mock::Fixtures.
request_passed_proofing_unsupported_id_results_response
status: 200,
body: UspsInPersonProofing::Mock::
Fixtures.request_passed_proofing_unsupported_id_results_response,
)
end

def stub_request_passed_proofing_unsupported_status_results
stub_request(:post, %r{/ivs-ippaas-api/IPPRest/resources/rest/getProofingResults}).to_return(
status: 200,
body: UspsInPersonProofing::Mock::Fixtures.
request_passed_proofing_unsupported_status_results_response,
body: UspsInPersonProofing::Mock::
Fixtures.request_passed_proofing_unsupported_status_results_response,
)
end

Expand Down