Skip to content

Commit 30c7085

Browse files
authored
Merge pull request #5807 from nhsuk/add-location-to-programme-status
Track location on programme status
2 parents 430c5eb + da1395f commit 30c7085

8 files changed

Lines changed: 84 additions & 28 deletions

File tree

app/lib/status_generator/programme.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ def date
116116
vaccination_generator.latest_date
117117
end
118118

119+
def location_id
120+
vaccination_generator.latest_location_id
121+
end
122+
119123
private
120124

121125
attr_reader :programme,

app/lib/status_updater.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,12 @@ def update_programme_statuses!
7373
conflict_target: [:id],
7474
columns: %i[
7575
date
76+
disease_types
7677
dose_sequence
78+
location_id
7779
status
7880
vaccine_methods
7981
without_gelatine
80-
disease_types
8182
]
8283
}
8384
)

app/models/patient/programme_status.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
# status :integer default("not_eligible"), not null
1414
# vaccine_methods :integer is an Array
1515
# without_gelatine :boolean
16+
# location_id :bigint
1617
# patient_id :bigint not null
1718
#
1819
# Indexes
1920
#
2021
# idx_on_academic_year_patient_id_3d5bf8d2c8 (academic_year,patient_id)
2122
# idx_on_patient_id_academic_year_programme_type_75e0e0c471 (patient_id,academic_year,programme_type) UNIQUE
23+
# index_patient_programme_statuses_on_location_id (location_id)
2224
# index_patient_programme_statuses_on_patient_id (patient_id)
2325
# index_patient_programme_statuses_on_status (status)
2426
#
@@ -31,6 +33,7 @@ class Patient::ProgrammeStatus < ApplicationRecord
3133
include HasVaccineMethods
3234

3335
belongs_to :patient
36+
belongs_to :location, optional: true
3437

3538
has_many :patient_locations,
3639
-> { includes(location: :location_programme_year_groups) },
@@ -134,11 +137,12 @@ def group = GROUPS.find { status.starts_with?(it) }
134137

135138
def assign
136139
self.date = generator.date
140+
self.disease_types = generator.disease_types
137141
self.dose_sequence = generator.dose_sequence
142+
self.location_id = generator.location_id
138143
self.status = generator.status
139144
self.vaccine_methods = generator.vaccine_methods
140145
self.without_gelatine = generator.without_gelatine
141-
self.disease_types = generator.disease_types
142146
end
143147

144148
def vaccine_criteria = VaccineCriteria.from_programme_status(self)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# frozen_string_literal: true
2+
3+
class AddLocationToPatientProgrammeStatuses < ActiveRecord::Migration[8.1]
4+
def change
5+
add_reference :patient_programme_statuses, :location
6+
end
7+
end

db/schema.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema[8.1].define(version: 2026_01_15_090835) do
13+
ActiveRecord::Schema[8.1].define(version: 2026_01_19_161311) do
1414
# These are extensions that must be enabled in order to support this database
1515
enable_extension "pg_catalog.plpgsql"
1616
enable_extension "pg_trgm"
@@ -621,12 +621,14 @@
621621
t.date "date"
622622
t.enum "disease_types", array: true, enum_type: "disease_type"
623623
t.integer "dose_sequence"
624+
t.bigint "location_id"
624625
t.bigint "patient_id", null: false
625626
t.enum "programme_type", null: false, enum_type: "programme_type"
626627
t.integer "status", default: 0, null: false
627628
t.integer "vaccine_methods", array: true
628629
t.boolean "without_gelatine"
629630
t.index ["academic_year", "patient_id"], name: "idx_on_academic_year_patient_id_3d5bf8d2c8"
631+
t.index ["location_id"], name: "index_patient_programme_statuses_on_location_id"
630632
t.index ["patient_id", "academic_year", "programme_type"], name: "idx_on_patient_id_academic_year_programme_type_75e0e0c471", unique: true
631633
t.index ["patient_id"], name: "index_patient_programme_statuses_on_patient_id"
632634
t.index ["status"], name: "index_patient_programme_statuses_on_status"

spec/factories/patient_programme_statuses.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
# status :integer default("not_eligible"), not null
1414
# vaccine_methods :integer is an Array
1515
# without_gelatine :boolean
16+
# location_id :bigint
1617
# patient_id :bigint not null
1718
#
1819
# Indexes
1920
#
2021
# idx_on_academic_year_patient_id_3d5bf8d2c8 (academic_year,patient_id)
2122
# idx_on_patient_id_academic_year_programme_type_75e0e0c471 (patient_id,academic_year,programme_type) UNIQUE
23+
# index_patient_programme_statuses_on_location_id (location_id)
2224
# index_patient_programme_statuses_on_patient_id (patient_id)
2325
# index_patient_programme_statuses_on_status (status)
2426
#

spec/lib/status_generator/programme_spec.rb

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,20 @@
2121
let(:programme) { Programme.sample }
2222
let(:session) { create(:session, programmes: [programme]) }
2323
let(:patient) { create(:patient, session:) }
24+
let(:location) { create(:school) }
2425

2526
context "when already vaccinated" do
2627
let(:programme) { Programme.hpv }
2728

2829
let!(:vaccination_record) do
29-
create(:vaccination_record, :already_had, patient:, programme:)
30+
create(:vaccination_record, :already_had, patient:, programme:, location:)
3031
end
3132

32-
its(:status) { should be(:vaccinated_already) }
3333
its(:date) { should eq(vaccination_record.performed_at.to_date) }
3434
its(:disease_types) { should eq(%w[human_papillomavirus]) }
3535
its(:dose_sequence) { should be_nil }
36+
its(:location_id) { should eq(location.id) }
37+
its(:status) { should be(:vaccinated_already) }
3638
its(:vaccine_methods) { should be_empty }
3739
its(:without_gelatine) { should be_nil }
3840
end
@@ -41,13 +43,14 @@
4143
let(:programme) { Programme.hpv }
4244

4345
let!(:vaccination_record) do
44-
create(:vaccination_record, patient:, programme:)
46+
create(:vaccination_record, patient:, programme:, location:)
4547
end
4648

47-
its(:status) { should be(:vaccinated_fully) }
4849
its(:date) { should eq(vaccination_record.performed_at.to_date) }
4950
its(:disease_types) { should eq(%w[human_papillomavirus]) }
5051
its(:dose_sequence) { should be_nil }
52+
its(:location_id) { should eq(location.id) }
53+
its(:status) { should be(:vaccinated_fully) }
5154
its(:vaccine_methods) { should be_empty }
5255
its(:without_gelatine) { should be_nil }
5356
end
@@ -56,13 +59,14 @@
5659
let(:programme) { Programme.mmr }
5760

5861
let!(:vaccination_record) do
59-
create(:vaccination_record, patient:, programme:)
62+
create(:vaccination_record, patient:, programme:, location:)
6063
end
6164

62-
its(:status) { should be(:needs_consent_no_response) }
6365
its(:date) { should eq(vaccination_record.performed_at.to_date) }
6466
its(:disease_types) { should be_nil }
6567
its(:dose_sequence) { should be_nil }
68+
its(:location_id) { should be_nil }
69+
its(:status) { should be(:needs_consent_no_response) }
6670
its(:vaccine_methods) { should be_nil }
6771
its(:without_gelatine) { should be_nil }
6872

@@ -81,35 +85,45 @@
8185
before { create(:consent, :given, patient:, programme:) }
8286

8387
let!(:vaccination_record) do
84-
create(:vaccination_record, :unwell, patient:, programme:)
88+
create(:vaccination_record, :unwell, patient:, programme:, location:)
8589
end
8690

87-
its(:status) { should be(:cannot_vaccinate_unwell) }
8891
its(:date) { should eq(vaccination_record.performed_at.to_date) }
8992
its(:disease_types) { should eq(programme.disease_types) }
93+
its(:location_id) { should be_nil }
94+
its(:status) { should be(:cannot_vaccinate_unwell) }
9095
its(:vaccine_methods) { should contain_exactly("injection") }
9196
its(:without_gelatine) { should be(false) }
9297

9398
context "on a different day" do
9499
let!(:vaccination_record) do
95-
create(:vaccination_record, :unwell, :yesterday, patient:, programme:)
100+
create(
101+
:vaccination_record,
102+
:unwell,
103+
:yesterday,
104+
patient:,
105+
programme:,
106+
location:
107+
)
96108
end
97109

98-
its(:status) { should be(:due) }
99110
its(:date) { should eq(vaccination_record.performed_at.to_date) }
111+
its(:location_id) { should be_nil }
112+
its(:status) { should be(:due) }
100113
end
101114
end
102115

103116
context "when the child refused" do
104117
before { create(:consent, :given, patient:, programme:) }
105118

106119
let!(:vaccination_record) do
107-
create(:vaccination_record, :refused, patient:, programme:)
120+
create(:vaccination_record, :refused, patient:, programme:, location:)
108121
end
109122

110-
its(:status) { should be(:cannot_vaccinate_refused) }
111123
its(:date) { should eq(vaccination_record.performed_at.to_date) }
112124
its(:disease_types) { should eq(programme.disease_types) }
125+
its(:location_id) { should be_nil }
126+
its(:status) { should be(:cannot_vaccinate_refused) }
113127
its(:vaccine_methods) { should contain_exactly("injection") }
114128
its(:without_gelatine) { should be(false) }
115129

@@ -118,21 +132,29 @@
118132
create(:vaccination_record, :unwell, :yesterday, patient:, programme:)
119133
end
120134

121-
its(:status) { should be(:due) }
122135
its(:date) { should eq(vaccination_record.performed_at.to_date) }
136+
its(:location_id) { should be_nil }
137+
its(:status) { should be(:due) }
123138
end
124139
end
125140

126141
context "when contraindicated" do
127142
before { create(:consent, :given, patient:, programme:) }
128143

129144
let!(:vaccination_record) do
130-
create(:vaccination_record, :contraindicated, patient:, programme:)
145+
create(
146+
:vaccination_record,
147+
:contraindicated,
148+
patient:,
149+
programme:,
150+
location:
151+
)
131152
end
132153

133-
its(:status) { should be(:cannot_vaccinate_contraindicated) }
134154
its(:date) { should eq(vaccination_record.performed_at.to_date) }
135155
its(:disease_types) { should eq(programme.disease_types) }
156+
its(:location_id) { should be_nil }
157+
its(:status) { should be(:cannot_vaccinate_contraindicated) }
136158
its(:vaccine_methods) { should contain_exactly("injection") }
137159
its(:without_gelatine) { should be(false) }
138160

@@ -141,8 +163,9 @@
141163
create(:vaccination_record, :unwell, :yesterday, patient:, programme:)
142164
end
143165

144-
its(:status) { should be(:due) }
145166
its(:date) { should eq(vaccination_record.performed_at.to_date) }
167+
its(:location_id) { should be_nil }
168+
its(:status) { should be(:due) }
146169
end
147170
end
148171

@@ -153,9 +176,10 @@
153176
create(:attendance_record, :absent, patient:, session:)
154177
end
155178

156-
its(:status) { should be(:cannot_vaccinate_absent) }
157179
its(:date) { should eq(attendance_record.date) }
158180
its(:disease_types) { should eq(programme.disease_types) }
181+
its(:location_id) { should be_nil }
182+
its(:status) { should be(:cannot_vaccinate_absent) }
159183
its(:vaccine_methods) { should contain_exactly("injection") }
160184
its(:without_gelatine) { should be(false) }
161185

@@ -181,10 +205,11 @@
181205
)
182206
end
183207

184-
its(:status) { should be(:cannot_vaccinate_delay_vaccination) }
185208
its(:date) { should eq(Date.tomorrow) }
186209
its(:disease_types) { should eq(programme.disease_types) }
187210
its(:dose_sequence) { should be_nil }
211+
its(:location_id) { should be_nil }
212+
its(:status) { should be(:cannot_vaccinate_delay_vaccination) }
188213
its(:vaccine_methods) { should contain_exactly("injection") }
189214
its(:without_gelatine) { should be(false) }
190215
end
@@ -195,10 +220,11 @@
195220
create(:triage, :invite_to_clinic, patient:, programme:)
196221
end
197222

198-
its(:status) { should be(:needs_triage) }
199223
its(:date) { should be_nil }
200224
its(:disease_types) { should eq(programme.disease_types) }
201225
its(:dose_sequence) { should be_nil }
226+
its(:location_id) { should be_nil }
227+
its(:status) { should be(:needs_triage) }
202228
its(:vaccine_methods) { should be_nil }
203229
its(:without_gelatine) { should be_nil }
204230
end
@@ -209,32 +235,35 @@
209235
create(:triage, :do_not_vaccinate, patient:, programme:)
210236
end
211237

212-
its(:status) { should be(:cannot_vaccinate_do_not_vaccinate) }
213238
its(:date) { should be_nil }
214239
its(:disease_types) { should eq(programme.disease_types) }
215240
its(:dose_sequence) { should be_nil }
241+
its(:location_id) { should be_nil }
242+
its(:status) { should be(:cannot_vaccinate_do_not_vaccinate) }
216243
its(:vaccine_methods) { should be_nil }
217244
its(:without_gelatine) { should be_nil }
218245
end
219246

220247
context "when needs triage" do
221248
before { create(:consent, :given, :needing_triage, patient:, programme:) }
222249

223-
its(:status) { should be(:needs_triage) }
224250
its(:date) { should be_nil }
225251
its(:disease_types) { should eq(programme.disease_types) }
226252
its(:dose_sequence) { should be_nil }
253+
its(:location_id) { should be_nil }
254+
its(:status) { should be(:needs_triage) }
227255
its(:vaccine_methods) { should be_nil }
228256
its(:without_gelatine) { should be_nil }
229257
end
230258

231259
context "when consent is refused" do
232260
before { create(:consent, :refused, patient:, programme:) }
233261

234-
its(:status) { should be(:has_refusal_consent_refused) }
235262
its(:date) { should be_nil }
236263
its(:disease_types) { should be_empty }
237264
its(:dose_sequence) { should be_nil }
265+
its(:location_id) { should be_nil }
266+
its(:status) { should be(:has_refusal_consent_refused) }
238267
its(:vaccine_methods) { should be_nil }
239268
its(:without_gelatine) { should be_nil }
240269
end
@@ -245,30 +274,33 @@
245274
create(:consent, :given, patient:, programme:, parent: create(:parent))
246275
end
247276

248-
its(:status) { should be(:has_refusal_consent_conflicts) }
249277
its(:date) { should be_nil }
250278
its(:disease_types) { should be_empty }
251279
its(:dose_sequence) { should be_nil }
280+
its(:location_id) { should be_nil }
281+
its(:status) { should be(:has_refusal_consent_conflicts) }
252282
its(:vaccine_methods) { should be_nil }
253283
its(:without_gelatine) { should be_nil }
254284
end
255285

256286
context "when consent is needed" do
257-
its(:status) { should be(:needs_consent_no_response) }
258287
its(:date) { should be_nil }
259288
its(:disease_types) { should be_nil }
260289
its(:dose_sequence) { should be_nil }
290+
its(:location_id) { should be_nil }
291+
its(:status) { should be(:needs_consent_no_response) }
261292
its(:vaccine_methods) { should be_nil }
262293
its(:without_gelatine) { should be_nil }
263294
end
264295

265296
context "when not eligible" do
266297
let(:patient) { create(:patient, year_group: 20) }
267298

268-
its(:status) { should be(:not_eligible) }
269299
its(:date) { should be_nil }
270300
its(:disease_types) { should be_nil }
271301
its(:dose_sequence) { should be_nil }
302+
its(:location_id) { should be_nil }
303+
its(:status) { should be(:not_eligible) }
272304
its(:vaccine_methods) { should be_nil }
273305
its(:without_gelatine) { should be_nil }
274306
end

0 commit comments

Comments
 (0)