Skip to content

Commit 84264e4

Browse files
Ndbex/95814 add va notify webhook (#21065)
* level set * level set with master * removing yarn.lock * FD * pulling in main * Levelset * state fix * Added feature flag for the dependents action needed email callback * Decided to go the simpler route and not implement a custom callback at this time * Setup email failure job * Added in a flipper feature falg and check for it in the senf_failure_email method in dependency claim * All tests are passing! Huzzahgit add . * Change to the file name of the job spec * Fix as flipper was calling a failure when calling send_failure_email * codeowners file change * meant to be sidekiq and not it's spec * whoops * more codeowners * Called personlisation from the claim.send_failure_email method * disabled :dependents_failure_callback_email flipper in before block * Removed callback_options from the submit_central_form686c job * Added context to the flipper * Rubocop * Refactor for allow(Flipper) --------- Co-authored-by: micahaspyr <[email protected]>
1 parent 7076695 commit 84264e4

File tree

7 files changed

+389
-73
lines changed

7 files changed

+389
-73
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@ app/sidekiq/central_mail/submit_form4142_job.rb @department-of-veterans-affairs/
624624
app/sidekiq/copay_notifications @department-of-veterans-affairs/vsa-debt-resolution @department-of-veterans-affairs/backend-review-group
625625
app/sidekiq/cypress_viewport_updater @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers
626626
app/sidekiq/delete_old_pii_logs_job.rb @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers
627+
app/sidekiq/dependents/form_686c_674_failure_email_job.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
627628
app/sidekiq/education_form @department-of-veterans-affairs/my-education-benefits @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
628629
app/sidekiq/education_form/templates/10203.erb @department-of-veterans-affairs/govcio-vfep-codereviewers @department-of-veterans-affairs/backend-review-group
629630
app/sidekiq/education_form/templates/1990.erb @department-of-veterans-affairs/govcio-vfep-codereviewers @department-of-veterans-affairs/backend-review-group
@@ -1386,6 +1387,7 @@ spec/sidekiq/education_form @department-of-veterans-affairs/my-education-benefit
13861387
spec/sidekiq/education_form/create_daily_spool_files.rb @department-of-veterans-affairs/my-education-benefits @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/govcio-vfep-codereviewers
13871388
spec/sidekiq/education_form/create_daily_excel_files_spec.rb @department-of-veterans-affairs/govcio-vfep-codereviewers @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
13881389
spec/sidekiq/delete_old_pii_logs_job_spec.rb @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers
1390+
spec/sidekiq/dependents/form686c674_failure_email_job_spec.rb @department-of-veterans-affairs/benefits-non-disability @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
13891391
spec/sidekiq/evss/dependents_application_job_spec.rb @department-of-veterans-affairs/benefits-dependents-management @department-of-veterans-affairs/vfs-authenticated-experience-backend @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
13901392
spec/sidekiq/evss/disability_compensation_form @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group
13911393
spec/sidekiq/evss/disability_compensation_form/form526_document_upload_failure_email_spec.rb @department-of-veterans-affairs/Disability-Experience @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group

app/models/saved_claim/dependency_claim.rb

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ def to_pdf(form_id: FORM)
161161
def send_failure_email(email) # rubocop:disable Metrics/MethodLength
162162
# if the claim is both a 686c and a 674, send a combination email.
163163
# otherwise, check to see which individual type it is and send the corresponding email.
164+
personalisation = {
165+
'first_name' => parsed_form.dig('veteran_information', 'full_name', 'first')&.upcase.presence,
166+
'date_submitted' => Time.zone.today.strftime('%B %d, %Y'),
167+
'confirmation_number' => confirmation_number
168+
}
164169
template_id = if submittable_686? && submittable_674?
165170
Settings.vanotify.services.va_gov.template_id.form21_686c_674_action_needed_email
166171
elsif submittable_686?
@@ -171,17 +176,16 @@ def send_failure_email(email) # rubocop:disable Metrics/MethodLength
171176
Rails.logger.error('Email template cannot be assigned for SavedClaim', saved_claim_id: id)
172177
nil
173178
end
174-
175179
if email.present? && template_id.present?
176-
VANotify::EmailJob.perform_async(
177-
email,
178-
template_id,
179-
{
180-
'first_name' => parsed_form.dig('veteran_information', 'full_name', 'first')&.upcase.presence,
181-
'date_submitted' => Time.zone.today.strftime('%B %d, %Y'),
182-
'confirmation_number' => confirmation_number
183-
}
184-
)
180+
if Flipper.enabled?(:dependents_failure_callback_email)
181+
Dependents::Form686c674FailureEmailJob.perform_async(id, email, template_id, personalisation)
182+
else
183+
VANotify::EmailJob.perform_async(
184+
email,
185+
template_id,
186+
personalisation
187+
)
188+
end
185189
end
186190
end
187191

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# frozen_string_literal: true
2+
3+
require 'va_notify/service'
4+
5+
class Dependents::Form686c674FailureEmailJob
6+
include Sidekiq::Job
7+
8+
FORM_ID = '686C-674'
9+
FORM_ID_674 = '21-674'
10+
STATSD_KEY_PREFIX = 'api.dependents.form_686c_674_failure_email_job'
11+
ZSF_DD_TAG_FUNCTION = '686c_674_failure_email_queuing'
12+
13+
sidekiq_options retry: 16
14+
15+
sidekiq_retries_exhausted do |msg, ex|
16+
Rails.logger.error('Form686c674FailureEmailJob exhausted all retries',
17+
{
18+
saved_claim_id: msg['args'].first,
19+
error_message: ex.message
20+
})
21+
end
22+
23+
def perform(claim_id, email, template_id, personalisation)
24+
@claim = SavedClaim::DependencyClaim.find(claim_id)
25+
va_notify_client.send_email(email_address: email,
26+
template_id:,
27+
personalisation:)
28+
rescue => e
29+
Rails.logger.warn('Form686c674FailureEmailJob failed, retrying send...', { claim_id:, error: e })
30+
end
31+
32+
private
33+
34+
def va_notify_client
35+
@va_notify_client ||= VaNotify::Service.new(Settings.vanotify.services.va_gov.api_key, callback_options)
36+
end
37+
38+
def callback_options
39+
{
40+
callback_metadata: {
41+
notification_type: 'error',
42+
form_id: @claim.form_id,
43+
statsd_tags: { service: 'dependent-change', function: ZSF_DD_TAG_FUNCTION }
44+
}
45+
}
46+
end
47+
end

app/sidekiq/lighthouse/benefits_intake/submit_central_form686c_job.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class SubmitCentralForm686cJob
1717
FORM_ID = '686C-674'
1818
FORM_ID_674 = '21-674'
1919
STATSD_KEY_PREFIX = 'worker.submit_686c_674_backup_submission'
20+
ZSF_DD_TAG_FUNCTION = 'submit_686c_674_backup_submission'
2021
# retry for 2d 1h 47m 12s
2122
# https://github.com/sidekiq/sidekiq/wiki/Error-Handling
2223
RETRY = 16

config/features.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,9 @@ features:
519519
dependents_trigger_action_needed_email:
520520
actor_type: user
521521
description: Set whether to enable VANotify email to Veteran for Dependents Backup Path failure exhaustion
522+
dependents_failure_callback_email:
523+
actor_type: user
524+
description: Enables the dependents action needed email callback to be used when an action needed email is triggered
522525
disability_526_form4142_polling_records:
523526
actor_type: user
524527
description: enables creation of, and tracking of, sent form 4142 documents, from the 526 flow, to the Lighthouse Benefits Intake API
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
RSpec.describe Dependents::Form686c674FailureEmailJob, type: :job do
6+
let(:job) { described_class.new }
7+
let(:claim_id) { 123 }
8+
let(:email) { '[email protected]' }
9+
let(:template_id) { 'test-template-id' }
10+
let(:claim) do
11+
instance_double(
12+
SavedClaim::DependencyClaim,
13+
form_id: described_class::FORM_ID,
14+
confirmation_number: 'ABCD1234',
15+
parsed_form: {
16+
'veteran_information' => {
17+
'full_name' => {
18+
'first' => 'John'
19+
}
20+
}
21+
}
22+
)
23+
end
24+
let(:personalisation) do
25+
{
26+
'first_name' => 'JOHN',
27+
'date_submitted' => 'January 01, 2023',
28+
'confirmation_number' => 'ABCD1234'
29+
}
30+
end
31+
let(:va_notify_client) { instance_double(VaNotify::Service) }
32+
33+
describe '#perform' do
34+
before do
35+
allow(SavedClaim::DependencyClaim).to receive(:find).with(claim_id).and_return(claim)
36+
allow(VaNotify::Service).to receive(:new).and_return(va_notify_client)
37+
allow(va_notify_client).to receive(:send_email)
38+
allow(Rails.logger).to receive(:warn)
39+
end
40+
41+
it 'sends an email with the correct parameters' do
42+
expect(va_notify_client).to receive(:send_email).with(
43+
email_address: email,
44+
template_id:,
45+
personalisation: {
46+
'first_name' => 'JOHN',
47+
'date_submitted' => 'January 01, 2023',
48+
'confirmation_number' => 'ABCD1234'
49+
}
50+
)
51+
52+
job.perform(claim_id, email, template_id, personalisation)
53+
end
54+
55+
context 'when an error occurs' do
56+
before do
57+
allow(va_notify_client).to receive(:send_email).and_raise(StandardError.new('Test error'))
58+
end
59+
60+
it 'logs the error and allows retry' do
61+
expect(Rails.logger).to receive(:warn).with(
62+
'Form686c674FailureEmailJob failed, retrying send...',
63+
{ claim_id:, error: instance_of(StandardError) }
64+
)
65+
66+
# Should not raise error
67+
expect { job.perform(claim_id, email, template_id, personalisation) }.not_to raise_error
68+
end
69+
end
70+
end
71+
72+
describe 'sidekiq_retries_exhausted' do
73+
it 'logs an error when retries are exhausted' do
74+
msg = { 'args' => [claim_id] }
75+
ex = StandardError.new('Test exhausted error')
76+
77+
expect(Rails.logger).to receive(:error).with(
78+
'Form686c674FailureEmailJob exhausted all retries',
79+
{
80+
saved_claim_id: claim_id,
81+
error_message: 'Test exhausted error'
82+
}
83+
)
84+
85+
described_class.sidekiq_retries_exhausted_block.call(msg, ex)
86+
end
87+
end
88+
89+
describe '#va_notify_client' do
90+
before do
91+
allow(SavedClaim::DependencyClaim).to receive(:find).with(claim_id).and_return(claim)
92+
allow(VaNotify::Service).to receive(:new).and_return(va_notify_client)
93+
94+
vanotify = double('vanotify')
95+
services = double('services')
96+
va_gov = double('va_gov')
97+
98+
allow(Settings).to receive(:vanotify).and_return(vanotify)
99+
allow(vanotify).to receive(:services).and_return(services)
100+
allow(services).to receive(:va_gov).and_return(va_gov)
101+
allow(va_gov).to receive(:api_key).and_return('test-api-key')
102+
end
103+
104+
it 'initializes VaNotify::Service with correct parameters' do
105+
expected_callback_options = {
106+
callback_metadata: {
107+
notification_type: 'error',
108+
form_id: described_class::FORM_ID,
109+
statsd_tags: { service: 'dependent-change', function: described_class::ZSF_DD_TAG_FUNCTION }
110+
}
111+
}
112+
113+
expect(VaNotify::Service).to receive(:new).with('test-api-key', expected_callback_options)
114+
115+
# Just allow the job to execute, which should create the client
116+
allow(va_notify_client).to receive(:send_email)
117+
job.perform(claim_id, email, template_id, personalisation)
118+
end
119+
end
120+
121+
describe '#personalisation' do
122+
before do
123+
allow(SavedClaim::DependencyClaim).to receive(:find).with(claim_id).and_return(claim)
124+
today = double('today')
125+
allow(Time.zone).to receive(:today).and_return(today)
126+
allow(today).to receive(:strftime).with('%B %d, %Y').and_return('January 01, 2023')
127+
# Create the service but don't set expectations on send_email yet
128+
allow(VaNotify::Service).to receive(:new).and_return(va_notify_client)
129+
end
130+
131+
it 'sends correct personalisation data in the email' do
132+
# Instead of directly calling the private method, test what gets sent to va_notify_client
133+
expect(va_notify_client).to receive(:send_email).with(
134+
email_address: email,
135+
template_id:,
136+
personalisation:
137+
)
138+
139+
job.perform(claim_id, email, template_id, {
140+
'first_name' => 'JOHN',
141+
'date_submitted' => 'January 01, 2023',
142+
'confirmation_number' => 'ABCD1234'
143+
})
144+
end
145+
146+
context 'when first name is nil' do
147+
let(:claim) do
148+
instance_double(
149+
SavedClaim::DependencyClaim,
150+
form_id: described_class::FORM_ID,
151+
confirmation_number: 'ABCD1234',
152+
parsed_form: {
153+
'veteran_information' => {
154+
'full_name' => {
155+
'first' => nil
156+
}
157+
}
158+
}
159+
)
160+
end
161+
162+
it 'handles nil first_name gracefully' do
163+
expect(va_notify_client).to receive(:send_email).with(
164+
email_address: email,
165+
template_id:,
166+
personalisation: hash_including('first_name' => nil)
167+
)
168+
personalisation['first_name'] = nil
169+
job.perform(claim_id, email, template_id, personalisation)
170+
end
171+
end
172+
end
173+
end

0 commit comments

Comments
 (0)