Skip to content

Commit eaa4a73

Browse files
authored
Merge pull request #3860 from nhsuk/manual-consent-reminders
Manual consent reminders
2 parents 808ea3c + 180aca9 commit eaa4a73

19 files changed

+581
-162
lines changed

app/components/app_session_actions_component.rb

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,13 @@ def no_consent_response_row
5050
count =
5151
patient_sessions.has_consent_status(status, programme: programmes).count
5252
href = session_consent_path(session, consent_statuses: [status])
53-
54-
generate_row(:children_with_no_consent_response, count:, href:)
53+
actions = [
54+
{
55+
text: "Send reminders",
56+
href: session_manage_consent_reminders_path(session)
57+
}
58+
]
59+
generate_row(:children_with_no_consent_response, count:, href:, actions:)
5560
end
5661

5762
def conflicting_consent_row
@@ -140,7 +145,7 @@ def ready_for_vaccinator_row
140145
}
141146
end
142147

143-
def generate_row(key, count:, href: nil)
148+
def generate_row(key, count:, href: nil, actions: nil)
144149
return nil if count.zero?
145150

146151
{
@@ -150,7 +155,8 @@ def generate_row(key, count:, href: nil)
150155
value: {
151156
text:
152157
(href ? helpers.link_to(I18n.t(key, count:), href).html_safe : text)
153-
}
158+
},
159+
actions:
154160
}
155161
end
156162
end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# frozen_string_literal: true
2+
3+
class Sessions::ManageConsentRemindersController < ApplicationController
4+
before_action :set_session
5+
6+
def create
7+
SendManualSchoolConsentRemindersJob.perform_now(@session, current_user:)
8+
9+
redirect_to session_path(@session),
10+
flash: {
11+
success: "Manual consent reminders sent."
12+
}
13+
end
14+
15+
private
16+
17+
def set_session
18+
@session = policy_scope(Session).find_by!(slug: params[:session_slug])
19+
end
20+
end
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# frozen_string_literal: true
2+
3+
module SendSchoolConsentNotificationConcern
4+
extend ActiveSupport::Concern
5+
6+
included do
7+
self.queue_adapter = :sidekiq unless Rails.env.test?
8+
9+
queue_as :notifications
10+
end
11+
12+
def patient_programmes_eligible_for_notification(session:)
13+
return unless session.school? && session.open_for_consent?
14+
15+
session
16+
.patient_sessions
17+
.includes_programmes
18+
.includes(patient: %i[consent_notifications consents vaccination_records])
19+
.find_each do |patient_session|
20+
ProgrammeGrouper
21+
.call(patient_session.programmes)
22+
.each_value do |programmes|
23+
patient = patient_session.patient
24+
next unless patient.send_notifications?
25+
26+
programmes_that_need_response =
27+
get_programmes_that_need_consent(patient:, session:, programmes:)
28+
next if programmes_that_need_response.empty?
29+
30+
yield patient, programmes_that_need_response
31+
end
32+
end
33+
end
34+
35+
def get_programmes_that_need_consent(patient:, session:, programmes:)
36+
academic_year = session.academic_year
37+
38+
programmes.select do |programme|
39+
patient.consent_status(programme:, academic_year:).no_response? &&
40+
patient.vaccination_status(programme:, academic_year:).none_yet?
41+
end
42+
end
43+
44+
def reminder_notification_type(patient:, programmes:)
45+
sent_initial_reminder =
46+
programmes.all? do |programme|
47+
patient
48+
.consent_notifications
49+
.select { it.programmes.include?(programme) }
50+
.any?(&:initial_reminder?)
51+
end
52+
53+
sent_initial_reminder ? :subsequent_reminder : :initial_reminder
54+
end
55+
end

app/jobs/enqueue_school_consent_reminders_job.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def perform
88
Session.send_consent_reminders.joins(:location).merge(Location.school)
99

1010
sessions.find_each do |session|
11-
SendSchoolConsentRemindersJob.perform_later(session)
11+
SendAutomaticSchoolConsentRemindersJob.perform_later(session)
1212
end
1313
end
1414
end
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# frozen_string_literal: true
2+
3+
class SendAutomaticSchoolConsentRemindersJob < ApplicationJob
4+
include SendSchoolConsentNotificationConcern
5+
6+
def perform(session)
7+
patient_programmes_eligible_for_notification(
8+
session:
9+
) do |patient, programmes|
10+
next unless should_send_notification?(patient:, session:, programmes:)
11+
12+
ConsentNotification.create_and_send!(
13+
patient:,
14+
session:,
15+
programmes:,
16+
type: notification_type(patient:, programmes:),
17+
current_user: nil
18+
)
19+
end
20+
end
21+
22+
def should_send_notification?(patient:, session:, programmes:)
23+
programmes.any? do |programme|
24+
initial_request = initial_request(patient:, programme:)
25+
return false if initial_request.nil?
26+
27+
date_to_send_reminder =
28+
earliest_date_to_send_reminder(
29+
patient:,
30+
session:,
31+
programme:,
32+
initial_request_date: initial_request.sent_at.to_date
33+
)
34+
next false if date_to_send_reminder.nil?
35+
36+
Date.current >= date_to_send_reminder
37+
end
38+
end
39+
40+
def initial_request(patient:, programme:)
41+
patient
42+
.consent_notifications
43+
.sort_by(&:sent_at)
44+
.find { it.request? && it.programmes.include?(programme) }
45+
end
46+
47+
def earliest_date_to_send_reminder(
48+
patient:,
49+
session:,
50+
programme:,
51+
initial_request_date:
52+
)
53+
session_dates_after_request =
54+
session.dates.select { it > initial_request_date }
55+
56+
scheduled_automatic_reminder_dates =
57+
session_dates_after_request.map do
58+
it - session.days_before_consent_reminders.days
59+
end
60+
61+
date_index_to_send_reminder_for =
62+
already_sent_automatic_consent_reminders_count(patient:, programme:) +
63+
manual_consent_reminders_replacing_automatic_count(
64+
patient:,
65+
programme:,
66+
scheduled_automatic_reminder_dates:
67+
)
68+
69+
if date_index_to_send_reminder_for >=
70+
scheduled_automatic_reminder_dates.length
71+
return nil
72+
end
73+
74+
scheduled_automatic_reminder_dates[date_index_to_send_reminder_for]
75+
end
76+
77+
def notification_type(patient:, programmes:)
78+
reminder_notification_type(patient:, programmes:)
79+
end
80+
81+
def already_sent_automatic_consent_reminders_count(patient:, programme:)
82+
patient.consent_notifications.count do
83+
it.automated_reminder? && it.programmes.include?(programme)
84+
end
85+
end
86+
87+
def manual_consent_reminders_replacing_automatic_count(
88+
patient:,
89+
programme:,
90+
scheduled_automatic_reminder_dates:
91+
)
92+
patient.consent_notifications.count do |notification|
93+
notification.manual_reminder? &&
94+
notification.programmes.include?(programme) &&
95+
scheduled_automatic_reminder_dates.any? do |scheduled_automatic_reminder_date|
96+
notification.sent_at < scheduled_automatic_reminder_date &&
97+
notification.sent_at >= scheduled_automatic_reminder_date - 3.days
98+
end
99+
end
100+
end
101+
end
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# frozen_string_literal: true
2+
3+
class SendManualSchoolConsentRemindersJob < ApplicationJob
4+
include SendSchoolConsentNotificationConcern
5+
6+
def perform(session, current_user:)
7+
patient_programmes_eligible_for_notification(
8+
session:
9+
) do |patient, programmes|
10+
ConsentNotification.create_and_send!(
11+
patient:,
12+
session:,
13+
programmes:,
14+
type: notification_type(patient:, programmes:),
15+
current_user:
16+
)
17+
end
18+
end
19+
20+
def notification_type(patient:, programmes:)
21+
reminder_notification_type(patient:, programmes:)
22+
end
23+
end

app/jobs/send_school_consent_reminders_job.rb

Lines changed: 0 additions & 90 deletions
This file was deleted.

0 commit comments

Comments
 (0)