Skip to content

Commit 25e876a

Browse files
committed
Implement logic needs consent status request scheduled/not scheduled
This adds the logic where if a child is eligible for the programme and hasn't been sent any consent requests and has parent contact details: - If part of a session where consent requests are scheduled to go out in the future, the programme status becomes `needs_consent_request_scheduled`. - If not assigned to a session with a request scheduled, the programme status becomes `needs_consent_request_not_scheduled`. Jira-Issue: MAV-5882
1 parent 142504c commit 25e876a

19 files changed

Lines changed: 380 additions & 62 deletions

app/components/app_patient_search_form_component.rb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@
22

33
class AppPatientSearchFormComponent < ViewComponent::Base
44
# Remove these statuses once implemented.
5-
HIDDEN_PROGRAMME_STATUSES = %w[
6-
needs_consent_request_failed
7-
needs_consent_request_not_scheduled
8-
needs_consent_request_scheduled
9-
].freeze
5+
HIDDEN_PROGRAMME_STATUSES = %w[needs_consent_request_failed].freeze
106

117
def initialize(
128
form,

app/components/app_patient_session_consent_component.html.erb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
<p><%= patient.full_name %> is ready for the vaccinator.</p>
2222
<% elsif consent_status_value == :no_contact_details %>
2323
<p>We cannot send consent requests because we have no parent contact details.</p>
24+
<% elsif consent_status_value == :request_not_scheduled %>
25+
<p>No consent request is scheduled to be sent because the child has not been added to a scheduled session.</p>
26+
<% elsif consent_status_value == :request_scheduled %>
27+
<p>A consent request will be sent on <%= session.send_consent_requests_at.to_fs(:long) %>.</p>
2428
<% end %>
2529

2630
<div class="nhsuk-button-group">

app/components/app_patient_session_consent_component.rb

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ def consent_status_generator
6363
patient:,
6464
consents:,
6565
vaccination_records:,
66-
parents:
66+
parents:,
67+
sessions: [session],
68+
consent_notifications:
6769
)
6870
end
6971

@@ -76,19 +78,14 @@ def triage_status_generator
7678
consents:,
7779
triages:,
7880
vaccination_records:,
79-
parents:
81+
parents:,
82+
sessions: [session],
83+
consent_notifications:
8084
)
8185
end
8286

8387
def latest_consent_request
84-
@latest_consent_request ||=
85-
patient
86-
.consent_notifications
87-
.request
88-
.has_all_programmes_of([programme])
89-
.for_academic_year(academic_year)
90-
.order(sent_at: :desc)
91-
.first
88+
@latest_consent_request ||= consent_notifications.first
9289
end
9390

9491
def consents
@@ -116,8 +113,14 @@ def vaccination_records
116113
patient.vaccination_records.for_programme(programme).order_by_performed_at
117114
end
118115

116+
SEND_CONSENT_REQUEST_STATUSES = %i[
117+
no_response
118+
request_scheduled
119+
request_not_scheduled
120+
].freeze
121+
119122
def can_send_consent_request?
120-
consent_status_value == :no_response &&
123+
consent_status_value.in?(SEND_CONSENT_REQUEST_STATUSES) &&
121124
patient.send_notifications?(team: @session.team) &&
122125
session.can_receive_consent? && patient.parents.any?(&:contactable?)
123126
end
@@ -134,4 +137,13 @@ def who_refused
134137
def show_health_answers?
135138
grouped_consents.any?(&:response_given?)
136139
end
140+
141+
def consent_notifications
142+
patient
143+
.consent_notifications
144+
.request
145+
.has_all_programmes_of([programme])
146+
.for_academic_year(academic_year)
147+
.order(sent_at: :desc)
148+
end
137149
end

app/components/app_patient_session_triage_component.rb

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ def initialize(
1414
@current_user = current_user
1515
@triage_form = triage_form || default_triage_form
1616
@parents = patient.parents
17+
@patient_locations =
18+
patient.patient_locations.includes(
19+
location: [
20+
:location_programme_year_groups,
21+
{ team_locations: { sessions: :session_programme_year_groups } }
22+
]
23+
)
1724
end
1825

1926
def render?
@@ -28,7 +35,8 @@ def render?
2835
:programme,
2936
:current_user,
3037
:triage_form,
31-
:parents
38+
:parents,
39+
:patient_locations
3240

3341
delegate :academic_year, :team, to: :session
3442

@@ -77,7 +85,9 @@ def triage_status_generator
7785
consents:,
7886
triages:,
7987
vaccination_records:,
80-
parents:
88+
parents:,
89+
sessions: [session],
90+
consent_notifications:
8191
)
8292
end
8393

@@ -89,7 +99,9 @@ def consent_status_generator
8999
patient:,
90100
consents:,
91101
vaccination_records:,
92-
parents:
102+
parents:,
103+
sessions: [session],
104+
consent_notifications:
93105
)
94106
end
95107

@@ -118,4 +130,12 @@ def latest_triage
118130
def default_triage_form
119131
TriageForm.new(patient:, session:, programme:, current_user:)
120132
end
133+
134+
def consent_notifications
135+
patient
136+
.consent_notifications
137+
.request
138+
.has_all_programmes_of([programme])
139+
.for_academic_year(academic_year)
140+
end
121141
end

app/forms/triage_form.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ def consent_status_generator
130130
patient:,
131131
consents: patient.consents,
132132
vaccination_records: [],
133-
parents: []
133+
parents: [],
134+
sessions: [],
135+
consent_notifications: []
134136
)
135137
end
136138

app/lib/patient_status_updater.rb

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,19 @@ def update_programme_statuses!
4646
:attendance_record,
4747
:consents,
4848
:patient,
49-
:patient_locations,
5049
:triages,
5150
:vaccination_records,
52-
:parents
51+
:parents,
52+
:consent_notifications,
53+
patient_locations: {
54+
location: [
55+
{ team_locations: { sessions: :session_programme_year_groups } }
56+
]
57+
}
5358
)
5459
.find_in_batches do |batch|
60+
preload_location_programme_year_groups(batch)
61+
5562
batch.each(&:assign)
5663

5764
Patient::ProgrammeStatus.import!(
@@ -180,4 +187,23 @@ def programme_types_per_session_id_and_year_group
180187
hash[session_id][year_group] << programme_type
181188
end
182189
end
190+
191+
# We preload this association separately because including it in the nested
192+
# `patient_locations` preload (see includes above) caused the updater process
193+
# to be killed, even with very small batches. The likely cause is memory pressure
194+
# from eager loading a deeply nested association graph.
195+
#
196+
# Preloading it here for the distinct `Location` records in each batch keeps
197+
# `StatusGenerator::Programme` query-free without incurring the cost of the
198+
# larger nested preload.
199+
def preload_location_programme_year_groups(batch)
200+
locations = batch.flat_map(&:patient_locations).map(&:location).uniq
201+
202+
ActiveRecord::Associations::Preloader.new(
203+
records: locations,
204+
associations: {
205+
location_programme_year_groups: :location_year_group
206+
}
207+
).call
208+
end
183209
end

app/lib/status_generator/consent.rb

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,18 @@ def initialize(
77
patient:,
88
consents:,
99
vaccination_records:,
10-
parents:
10+
parents:,
11+
sessions:,
12+
consent_notifications:
1113
)
1214
@programme_type = programme_type
1315
@academic_year = academic_year
1416
@patient = patient
1517
@consents = consents
1618
@vaccination_records = vaccination_records
1719
@parents = parents
20+
@sessions = sessions
21+
@consent_notifications = consent_notifications
1822
end
1923

2024
def programme
@@ -32,6 +36,10 @@ def status
3236
:conflicts
3337
elsif status_should_be_no_contact_details?
3438
:no_contact_details
39+
elsif status_should_be_request_scheduled?
40+
:request_scheduled
41+
elsif status_should_be_request_not_scheduled?
42+
:request_not_scheduled
3543
elsif status_should_be_no_response?
3644
:no_response
3745
else
@@ -62,7 +70,9 @@ def disease_types
6270
:patient,
6371
:consents,
6472
:vaccination_records,
65-
:parents
73+
:parents,
74+
:sessions,
75+
:consent_notifications
6676

6777
def vaccinated?
6878
return @vaccinated if defined?(@vaccinated)
@@ -162,4 +172,21 @@ def latest_consents
162172
@latest_consents ||=
163173
ConsentGrouper.call(consents, programme_type:, academic_year:)
164174
end
175+
176+
def parents_contactable? = parents.any?(&:contactable?)
177+
178+
def status_should_be_request_scheduled?
179+
parents_contactable? && consent_notifications.empty? &&
180+
sessions.any? do
181+
# Not using send_consent_requests_at.future?
182+
# because it doesn't work with Timecop.
183+
it.send_consent_requests_at &&
184+
it.send_consent_requests_at > Time.current
185+
end
186+
end
187+
188+
def status_should_be_request_not_scheduled?
189+
parents_contactable? && consent_notifications.empty? &&
190+
(sessions.empty? || sessions.any? { it.send_consent_requests_at.nil? })
191+
end
165192
end

app/lib/status_generator/programme.rb

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ def initialize(
1717
triages:,
1818
attendance_record:,
1919
vaccination_records:,
20-
parents:
20+
parents:,
21+
consent_notifications:
2122
)
2223
@programme_type = programme_type
2324
@academic_year = academic_year
@@ -28,6 +29,8 @@ def initialize(
2829
@attendance_record = attendance_record
2930
@vaccination_records = vaccination_records
3031
@parents = parents
32+
@consent_notifications =
33+
find_matching_consent_notifications(consent_notifications)
3134

3235
@vaccination_criteria =
3336
VaccinationCriteria.new(
@@ -172,7 +175,8 @@ def consent_vaccine_methods
172175
:triages,
173176
:attendance_record,
174177
:vaccination_criteria,
175-
:parents
178+
:parents,
179+
:consent_notifications
176180

177181
delegate :vaccinated?,
178182
:vaccinated_vaccination_record,
@@ -237,11 +241,11 @@ def should_be_needs_consent_request_failed?
237241
end
238242

239243
def should_be_needs_consent_request_scheduled?
240-
false # TODO: Implement this status.
244+
is_eligible? && consent_status == :request_scheduled
241245
end
242246

243247
def should_be_needs_consent_request_not_scheduled?
244-
false # TODO: Implement this status.
248+
is_eligible? && consent_status == :request_not_scheduled
245249
end
246250

247251
def should_be_needs_consent_no_contact_details?
@@ -288,6 +292,13 @@ def default_programme_year_groups
288292
Programme.find(programme_type).default_year_groups
289293
end
290294

295+
def find_matching_consent_notifications(notifications)
296+
notifications.select do |notification|
297+
notification.programme_types.include?(programme_type) &&
298+
notification.session&.team_location&.academic_year == academic_year
299+
end
300+
end
301+
291302
def consent_generator
292303
@consent_generator ||=
293304
StatusGenerator::Consent.new(
@@ -296,7 +307,9 @@ def consent_generator
296307
patient:,
297308
consents:,
298309
vaccination_records:,
299-
parents:
310+
parents:,
311+
sessions:,
312+
consent_notifications:
300313
)
301314
end
302315

@@ -309,7 +322,23 @@ def triage_generator
309322
consents:,
310323
triages:,
311324
vaccination_records:,
312-
parents:
325+
parents:,
326+
sessions:,
327+
consent_notifications:
313328
)
314329
end
330+
331+
def sessions
332+
@sessions ||=
333+
patient_locations
334+
.reject { it.location.generic_clinic? }
335+
.flat_map do |patient_location|
336+
patient_location
337+
.location
338+
.team_locations
339+
.select { it.academic_year == academic_year }
340+
.flat_map(&:sessions)
341+
.select { it.programme_types.include?(programme_type) }
342+
end
343+
end
315344
end

0 commit comments

Comments
 (0)