Skip to content

Commit 9bcd210

Browse files
authored
Merge pull request #5271 from nhsuk/refactor-important-notices
Refactor important notices
2 parents 5827c8f + fad2ee4 commit 9bcd210

26 files changed

Lines changed: 893 additions & 317 deletions

app/components/app_imports_navigation_component.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def call
2626
selected: active == :imported
2727
)
2828

29-
if policy(:notices).index?
29+
if policy(ImportantNotice).index?
3030
nav.with_item(
3131
href: imports_notices_path,
3232
text: notices_text,
@@ -48,7 +48,7 @@ def issues_text
4848
end
4949

5050
def notices_text
51-
count = ImportantNotices.call(patient_scope: policy_scope(Patient)).length
51+
count = policy_scope(ImportantNotice).count
5252

5353
text_with_count("Important notices", count)
5454
end

app/components/app_notices_table_component.html.erb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
<% body.with_row do |row| %>
2020
<% row.with_cell do %>
2121
<span class="nhsuk-table-responsive__heading">Date</span>
22-
<%= notice[:date_time].to_date.to_fs(:long) %>
22+
<%= notice.recorded_at.to_date.to_fs(:long) %>
2323
<% end %>
2424
<% row.with_cell do %>
2525
<span class="nhsuk-table-responsive__heading">Child</span>
26-
<%= link_to notice[:patient].full_name, patient_path(notice[:patient]) %>
26+
<%= link_to notice.patient.full_name, patient_path(notice.patient) %>
2727
<% end %>
2828
<% row.with_cell do %>
2929
<span class="nhsuk-table-responsive__heading">Notice</span>
30-
<%= notice[:message] %>
30+
<%= notice.message %>
3131
<% end %>
3232
<% end %>
3333
<% end %>

app/components/app_patient_card_component.rb

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class AppPatientCardComponent < ViewComponent::Base
66
<% card.with_heading(level: heading_level) { "Child’s details" } %>
77
88
<% important_notices.each do |notice| %>
9-
<%= render AppStatusComponent.new(text: notice[:message]) %>
9+
<%= render AppStatusComponent.new(text: notice) %>
1010
<% end %>
1111
1212
<%= render AppChildSummaryComponent.new(
@@ -46,5 +46,40 @@ def initialize(
4646

4747
def show_school_and_year_group = patient.show_year_group?(team: current_team)
4848

49-
def important_notices = ImportantNotices.call(patient:)
49+
def important_notices
50+
notices = patient.important_notices.where(team_id: current_team.id)
51+
52+
[
53+
(
54+
if patient.restricted?
55+
notices.restricted.order(recorded_at: :desc).first&.message
56+
end
57+
),
58+
(
59+
if patient.invalidated?
60+
notices.invalidated.order(recorded_at: :desc).first&.message
61+
end
62+
),
63+
*notices.deceased.first&.message,
64+
*gillick_no_notify_notices
65+
].compact
66+
end
67+
68+
def gillick_no_notify_notices
69+
no_notify_vaccination_records =
70+
patient.vaccination_records.select do
71+
it.notify_parents == false && it.team == current_team
72+
end
73+
74+
if no_notify_vaccination_records.any?
75+
vaccinations_sentence =
76+
"#{no_notify_vaccination_records.map(&:programme).uniq.map(&:name).to_sentence} " \
77+
"#{"vaccination".pluralize(no_notify_vaccination_records.length)}"
78+
79+
"Child gave consent for #{vaccinations_sentence} under Gillick competence and " \
80+
"does not want their parents to be notified. " \
81+
"These records will not be automatically synced with GP records. " \
82+
"Your team must let the child's GP know they were vaccinated."
83+
end
84+
end
5085
end

app/controllers/dashboard_controller.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ class DashboardController < ApplicationController
99

1010
def index
1111
@notices_count =
12-
if policy(:notices).index?
13-
ImportantNotices.call(patient_scope: policy_scope(Patient)).length
14-
end
12+
(policy_scope(ImportantNotice).count if policy(ImportantNotice).index?)
1513
end
1614

1715
def team_has_upload_access_only?

app/controllers/imports/notices_controller.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ class Imports::NoticesController < ApplicationController
44
layout "full"
55

66
def index
7-
authorize :notices
7+
authorize ImportantNotice
88

9-
@notices = ImportantNotices.call(patient_scope: policy_scope(Patient))
9+
@notices = policy_scope(ImportantNotice).order(recorded_at: :desc)
1010
end
1111
end
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# frozen_string_literal: true
2+
3+
class ImportantNoticeGeneratorJob < ApplicationJob
4+
queue_as :cache
5+
6+
BATCH_SIZE = 1000
7+
8+
def perform(patient_ids = nil)
9+
if patient_ids.present?
10+
process_batch(
11+
Patient.includes(:teams, vaccination_records: %i[team]).where(
12+
id: patient_ids
13+
)
14+
)
15+
else
16+
Patient
17+
.includes(:teams, vaccination_records: %i[team])
18+
.find_in_batches(batch_size: BATCH_SIZE) do |patients_batch|
19+
process_batch(patients_batch)
20+
end
21+
end
22+
end
23+
24+
private
25+
26+
def process_batch(patients)
27+
notices_to_create = []
28+
notice_ids_to_dismiss = []
29+
30+
patient_ids = patients.map(&:id)
31+
32+
existing_notices =
33+
ImportantNotice.where(patient_id: patient_ids).index_by { notice_key(it) }
34+
35+
patient_team_ids =
36+
patients.each_with_object({}) do |patient, hash|
37+
hash[patient.id] = patient.teams.map(&:id)
38+
end
39+
40+
patients.each do |patient|
41+
collect_notices_for_patient(
42+
patient,
43+
notices_to_create,
44+
notice_ids_to_dismiss,
45+
existing_notices,
46+
patient_team_ids[patient.id]
47+
)
48+
end
49+
50+
if notices_to_create.any?
51+
ImportantNotice.import!(notices_to_create, on_duplicate_key_ignore: true)
52+
end
53+
54+
if notice_ids_to_dismiss.any?
55+
ImportantNotice.where(id: notice_ids_to_dismiss).update_all(
56+
dismissed_at: Time.current
57+
)
58+
end
59+
end
60+
61+
def collect_notices_for_patient(
62+
patient,
63+
notices_to_create,
64+
notice_ids_to_dismiss,
65+
existing_notices,
66+
team_ids
67+
)
68+
return if team_ids.empty?
69+
70+
team_ids.each do |team_id|
71+
if patient.deceased? &&
72+
!notice_exists?(existing_notices, patient.id, :deceased, team_id)
73+
notices_to_create << ImportantNotice.new(
74+
patient:,
75+
team_id: team_id,
76+
type: :deceased,
77+
recorded_at: patient.date_of_death_recorded_at
78+
)
79+
end
80+
81+
if patient.invalidated? &&
82+
!notice_exists?(existing_notices, patient.id, :invalidated, team_id)
83+
notices_to_create << ImportantNotice.new(
84+
patient:,
85+
team_id: team_id,
86+
type: :invalidated,
87+
recorded_at: patient.invalidated_at
88+
)
89+
end
90+
91+
if patient.restricted? &&
92+
!notice_exists?(existing_notices, patient.id, :restricted, team_id)
93+
notices_to_create << ImportantNotice.new(
94+
patient:,
95+
team_id: team_id,
96+
type: :restricted,
97+
recorded_at: patient.restricted_at
98+
)
99+
end
100+
101+
collect_gillick_no_notify_notices(
102+
patient,
103+
team_id,
104+
notices_to_create,
105+
existing_notices
106+
)
107+
108+
unless patient.invalidated?
109+
existing_notices.each_value do |notice|
110+
unless notice.patient_id == patient.id && notice.team_id == team_id &&
111+
notice.type == "invalidated" && notice.dismissed_at.nil?
112+
next
113+
end
114+
notice_ids_to_dismiss << notice.id
115+
end
116+
end
117+
118+
unless patient.restricted?
119+
existing_notices.each_value do |notice|
120+
unless notice.patient_id == patient.id && notice.team_id == team_id &&
121+
notice.type == "restricted" && notice.dismissed_at.nil?
122+
next
123+
end
124+
notice_ids_to_dismiss << notice.id
125+
end
126+
end
127+
128+
next if patient.deceased?
129+
existing_notices.each_value do |notice|
130+
unless notice.patient_id == patient.id && notice.team_id == team_id &&
131+
notice.type == "deceased" && notice.dismissed_at.nil?
132+
next
133+
end
134+
notice_ids_to_dismiss << notice.id
135+
end
136+
end
137+
end
138+
139+
def collect_gillick_no_notify_notices(
140+
patient,
141+
team_id,
142+
notices_to_create,
143+
existing_notices
144+
)
145+
no_notify_vaccination_records =
146+
patient.vaccination_records.select do |record|
147+
record.team&.id == team_id && record.notify_parents == false
148+
end
149+
150+
return if no_notify_vaccination_records.empty?
151+
152+
no_notify_vaccination_records.each do |record|
153+
if notice_exists?(
154+
existing_notices,
155+
patient.id,
156+
:gillick_no_notify,
157+
team_id,
158+
record.id
159+
)
160+
next
161+
end
162+
163+
notices_to_create << ImportantNotice.new(
164+
patient:,
165+
team_id: team_id,
166+
vaccination_record_id: record.id,
167+
type: :gillick_no_notify,
168+
recorded_at: record.performed_at
169+
)
170+
end
171+
end
172+
173+
def notice_key(notice)
174+
[
175+
notice.patient_id,
176+
notice.type,
177+
notice.team_id,
178+
notice.vaccination_record_id
179+
]
180+
end
181+
182+
def notice_exists?(
183+
existing_notices,
184+
patient_id,
185+
type,
186+
team_id,
187+
vaccination_record_id = nil
188+
)
189+
key = [patient_id, type.to_s, team_id, vaccination_record_id]
190+
existing_notices.key?(key)
191+
end
192+
end

app/lib/important_notices.rb

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

0 commit comments

Comments
 (0)