Skip to content

Commit 6976f2a

Browse files
committed
Handle invalid phone errors from GOV.UK Notify
This ensures that we handle the `InvalidPhoneError: Not a UK mobile number` error from GOV.UK Notify by recording the response as a permanent failure (which is accurate since retrying is not going to succeed). This also means the job finishes and doesn't get put back on the retry queue, and also allows the nurses to see useful feedback. Sentry-Issue: 6235087330
1 parent a47ef7d commit 6976f2a

File tree

4 files changed

+86
-21
lines changed

4 files changed

+86
-21
lines changed

app/components/app_parent_summary_component.rb

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -108,20 +108,19 @@ def call
108108

109109
delegate :govuk_summary_list, to: :helpers
110110

111+
EMAIL_FAILURE_TEXTS = {
112+
"permanent_failure" => "Email address does not exist",
113+
"temporary_failure" => "Inbox not accepting messages right now"
114+
}.freeze
115+
111116
def email_address
112117
delivery_status = @parent.email_delivery_status
113118

114119
elements = [
115120
tag.p(@parent.email, class: "nhsuk-body nhsuk-u-margin-0"),
116-
if delivery_status == "permanent_failure"
117-
render AppStatusComponent.new(
118-
text: "Email address does not exist",
119-
colour: "red",
120-
small: true
121-
)
122-
elsif delivery_status == "temporary_failure"
121+
if (failure_text = EMAIL_FAILURE_TEXTS[delivery_status])
123122
render AppStatusComponent.new(
124-
text: "Inbox not accepting messages right now",
123+
text: failure_text,
125124
colour: "red",
126125
small: true
127126
)
@@ -131,20 +130,21 @@ def email_address
131130
safe_join(elements)
132131
end
133132

133+
PHONE_FAILURE_TEXTS = {
134+
"not_uk_mobile_number_failure" =>
135+
"Phone number is a landline not accepting text messages",
136+
"permanent_failure" => "Phone number does not exist",
137+
"temporary_failure" => "Inbox not accepting messages right now"
138+
}.freeze
139+
134140
def phone_number
135141
delivery_status = @parent.sms_delivery_status
136142

137143
elements = [
138144
tag.p(@parent.phone, class: "nhsuk-body nhsuk-u-margin-0"),
139-
if delivery_status == "permanent_failure"
140-
render AppStatusComponent.new(
141-
text: "Phone number does not exist",
142-
colour: "red",
143-
small: true
144-
)
145-
elsif delivery_status == "temporary_failure"
145+
if (failure_text = PHONE_FAILURE_TEXTS[delivery_status])
146146
render AppStatusComponent.new(
147-
text: "Inbox not accepting messages right now",
147+
text: failure_text,
148148
colour: "red",
149149
small: true
150150
)

app/jobs/sms_delivery_job.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
class SMSDeliveryJob < NotifyDeliveryJob
44
include NotifyThrottlingConcern
55

6+
INVALID_UK_MOBILE_NUMBER_ERROR = "InvalidPhoneError: Not a UK mobile number"
7+
68
def perform(
79
template_name,
810
consent: nil,
@@ -43,30 +45,33 @@ def perform(
4345
template_id:
4446
}
4547

46-
delivery_id =
48+
delivery_id, delivery_status =
4749
if self.class.send_via_notify?
4850
begin
49-
self.class.client.send_sms(**args).id
51+
[self.class.client.send_sms(**args).id, "sending"]
5052
rescue Notifications::Client::BadRequestError => e
5153
if !Rails.env.production? &&
5254
e.message.include?(TEAM_ONLY_API_KEY_MESSAGE)
5355
# Prevent retries and job failures.
5456
Sentry.capture_exception(e)
57+
elsif e.message == INVALID_UK_MOBILE_NUMBER_ERROR
58+
[nil, "not_uk_mobile_number_failure"]
5559
else
5660
raise
5761
end
5862
end
5963
elsif self.class.send_via_test?
6064
self.class.deliveries << args
61-
SecureRandom.uuid
65+
[SecureRandom.uuid, "delivered"]
6266
else
6367
Rails.logger.info "Sending SMS to #{phone_number} with template #{template_id}"
64-
nil
68+
[nil, "delivered"]
6569
end
6670

6771
NotifyLogEntry.create!(
6872
consent_form: personalisation.consent_form,
6973
delivery_id:,
74+
delivery_status:,
7075
parent: personalisation.parent,
7176
patient: personalisation.patient,
7277
programme_ids: personalisation.programmes.map(&:id),

app/models/notify_log_entry.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ class NotifyLogEntry < ApplicationRecord
4949
delivered: 1,
5050
permanent_failure: 2,
5151
temporary_failure: 3,
52-
technical_failure: 4
52+
technical_failure: 4,
53+
not_uk_mobile_number_failure: 5
5354
}
5455

5556
validates :recipient, presence: true

spec/jobs/sms_delivery_job_spec.rb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,36 @@
9797
end
9898
end
9999

100+
context "when the parent phone number is invalid" do
101+
before do
102+
allow(notifications_client).to receive(:send_sms).and_raise(
103+
Notifications::Client::BadRequestError.new(
104+
OpenStruct.new(
105+
code: 400,
106+
body: "InvalidPhoneError: Not a UK mobile number"
107+
)
108+
)
109+
)
110+
end
111+
112+
it "creates a log entry for the failure" do
113+
expect { perform_now }.to change(NotifyLogEntry, :count).by(1)
114+
115+
notify_log_entry = NotifyLogEntry.last
116+
expect(notify_log_entry).to be_sms
117+
expect(notify_log_entry).to be_not_uk_mobile_number_failure
118+
expect(notify_log_entry.delivery_id).to be_nil
119+
expect(notify_log_entry.recipient).to eq("01234 567890")
120+
expect(notify_log_entry.template_id).to eq(
121+
GOVUK_NOTIFY_SMS_TEMPLATES[template_name]
122+
)
123+
expect(notify_log_entry.parent).to eq(parent)
124+
expect(notify_log_entry.patient).to eq(patient)
125+
expect(notify_log_entry.programme_ids).to eq(programmes.map(&:id))
126+
expect(notify_log_entry.sent_by).to eq(sent_by)
127+
end
128+
end
129+
100130
context "with a consent form" do
101131
let(:consent_form) do
102132
create(:consent_form, session:, parent_phone: "01234567890")
@@ -137,6 +167,35 @@
137167
perform_now
138168
end
139169
end
170+
171+
context "when the parent phone number is invalid" do
172+
before do
173+
allow(notifications_client).to receive(:send_sms).and_raise(
174+
Notifications::Client::BadRequestError.new(
175+
OpenStruct.new(
176+
code: 400,
177+
body: "InvalidPhoneError: Not a UK mobile number"
178+
)
179+
)
180+
)
181+
end
182+
183+
it "creates a log entry for the failure" do
184+
expect { perform_now }.to change(NotifyLogEntry, :count).by(1)
185+
186+
notify_log_entry = NotifyLogEntry.last
187+
expect(notify_log_entry).to be_sms
188+
expect(notify_log_entry).to be_not_uk_mobile_number_failure
189+
expect(notify_log_entry.delivery_id).to be_nil
190+
expect(notify_log_entry.recipient).to eq("01234 567890")
191+
expect(notify_log_entry.template_id).to eq(
192+
GOVUK_NOTIFY_SMS_TEMPLATES[template_name]
193+
)
194+
expect(notify_log_entry.consent_form).to eq(consent_form)
195+
expect(notify_log_entry.programme_ids).to eq(programmes.map(&:id))
196+
expect(notify_log_entry.sent_by).to eq(sent_by)
197+
end
198+
end
140199
end
141200
end
142201

0 commit comments

Comments
 (0)