Skip to content

Commit d7ea6b3

Browse files
committed
Add new scope to automated careplus reports
* Include records for patients that gained an nhs number in the last day * Only include these records if they were created after the careplus integration was enabled Jira-Issue: MAV-XXX
1 parent 3f333a5 commit d7ea6b3

5 files changed

Lines changed: 196 additions & 31 deletions

File tree

app/lib/reports/automated_careplus_exporter.rb

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,41 @@ def self.vaccination_records_scope(
3737
start_date:,
3838
end_date:
3939
)
40-
Reports::CareplusExporter.vaccination_records_scope(
41-
team:,
42-
programmes: team.programmes,
43-
academic_year:,
44-
start_date:,
45-
end_date:,
46-
include_missing_nhs_number: false
47-
)
40+
base_scope =
41+
Reports::CareplusExporter.vaccination_records_scope(
42+
team:,
43+
programmes: team.programmes,
44+
academic_year:,
45+
start_date: nil,
46+
end_date: nil,
47+
include_missing_nhs_number: false
48+
)
49+
daily_scope = base_scope.created_or_updated_between(start_date, end_date)
50+
51+
return daily_scope if team.careplus_integration_enabled_at.blank?
52+
53+
nhs_number_first_added_scope =
54+
base_scope
55+
.created_or_updated_on_or_after(team.careplus_integration_enabled_at)
56+
.where.not(patients: { nhs_number_first_added_at: nil })
57+
58+
if start_date.present?
59+
nhs_number_first_added_scope =
60+
nhs_number_first_added_scope.where(
61+
"patients.nhs_number_first_added_at >= ?",
62+
start_date.beginning_of_day
63+
)
64+
end
65+
66+
if end_date.present?
67+
nhs_number_first_added_scope =
68+
nhs_number_first_added_scope.where(
69+
"patients.nhs_number_first_added_at <= ?",
70+
end_date.end_of_day
71+
)
72+
end
73+
74+
daily_scope.or(nhs_number_first_added_scope).distinct
4875
end
4976

5077
def self.shared_args(team:, academic_year:)

app/lib/reports/careplus_exporter.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,13 @@ def gender_row_value(patient)
187187
end
188188

189189
def consents
190+
patient_ids = vaccination_records.unscope(:order).reselect(:patient_id)
191+
190192
@consents ||=
191193
Consent
192194
.select("DISTINCT ON (patient_id) consents.*")
193195
.for_programmes(programmes)
194-
.where(patient: vaccination_records.select(:patient_id), academic_year:)
196+
.where(patient: patient_ids, academic_year:)
195197
.not_invalidated
196198
.response_given
197199
.order(:patient_id, created_at: :desc)

app/models/vaccination_record.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,13 @@ class VaccinationRecord < ApplicationRecord
196196
scope
197197
end
198198

199+
scope :created_or_updated_on_or_after,
200+
->(timestamp) do
201+
where("vaccination_records.created_at >= ?", timestamp).or(
202+
where("vaccination_records.updated_at >= ?", timestamp)
203+
)
204+
end
205+
199206
enum :protocol, { pgd: 0, psd: 1, national: 2 }, validate: { allow_nil: true }
200207

201208
enum :delivery_method,

spec/lib/careplus/automated_report_sender_spec.rb

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
subject(:call) { described_class.call(team_id: team.id) }
55

66
let(:team) do
7-
create(:team, :with_careplus_enabled, programmes: Programme.all)
7+
create(
8+
:team,
9+
:with_careplus_enabled,
10+
programmes: Programme.all,
11+
careplus_integration_enabled_at: Time.zone.local(2025, 8, 28, 10)
12+
)
813
end
914
let(:programme) { Programme.hpv }
1015
let(:session) { create(:session, team:, programmes: [programme]) }
@@ -167,4 +172,87 @@
167172
expect { call }.not_to change(CareplusReport, :count)
168173
end
169174
end
175+
176+
context "when a patient gains an NHS number yesterday" do
177+
it "includes records created after the integration was enabled" do
178+
patient =
179+
create(
180+
:patient,
181+
session:,
182+
nhs_number_first_added_at: Time.zone.local(2025, 8, 31, 9)
183+
)
184+
record =
185+
create(
186+
:vaccination_record,
187+
patient:,
188+
session:,
189+
programme:,
190+
performed_at: Date.new(2025, 8, 29),
191+
created_at: Time.zone.local(2025, 8, 29, 12),
192+
updated_at: Time.zone.local(2025, 8, 29, 12)
193+
)
194+
195+
expect { call }.to change(CareplusReport, :count).by(1)
196+
197+
expect(CareplusReport.last.vaccination_records).to contain_exactly(record)
198+
end
199+
200+
it "does not include records created before the integration was enabled" do
201+
team.update!(
202+
careplus_integration_enabled_at: Time.zone.local(2025, 8, 30, 10)
203+
)
204+
205+
patient =
206+
create(
207+
:patient,
208+
session:,
209+
nhs_number_first_added_at: Time.zone.local(2025, 8, 31, 9)
210+
)
211+
create(
212+
:vaccination_record,
213+
patient:,
214+
session:,
215+
programme:,
216+
performed_at: Date.new(2025, 8, 29),
217+
created_at: Time.zone.local(2025, 8, 29, 12),
218+
updated_at: Time.zone.local(2025, 8, 29, 12)
219+
)
220+
221+
expect { call }.not_to change(CareplusReport, :count)
222+
end
223+
224+
it "deduplicates records that also changed yesterday" do
225+
patient =
226+
create(
227+
:patient,
228+
session:,
229+
nhs_number_first_added_at: Time.zone.local(2025, 8, 31, 9)
230+
)
231+
record =
232+
create(
233+
:vaccination_record,
234+
patient:,
235+
session:,
236+
programme:,
237+
performed_at: yesterday,
238+
created_at: Time.zone.local(2025, 8, 29, 12),
239+
updated_at: Time.zone.local(2025, 8, 31, 12)
240+
)
241+
242+
expect { call }.to change(CareplusReport, :count).by(1).and(
243+
change(CareplusReportVaccinationRecord, :count).by(1)
244+
)
245+
246+
expect(CareplusReport.last.vaccination_records).to contain_exactly(record)
247+
expect(WebMock).to have_requested(:post, endpoint).once
248+
end
249+
end
250+
251+
context "when CarePlus is configured but not manually enabled" do
252+
before { team.update!(careplus_integration_enabled_at: nil) }
253+
254+
it "does nothing" do
255+
expect { call }.not_to change(CareplusReport, :count)
256+
end
257+
end
170258
end

spec/lib/reports/automated_careplus_exporter_spec.rb

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,70 @@
2828
described_class.call(team:, academic_year:, start_date:, end_date:)
2929
end
3030

31-
it "delegates vaccination_records_scope to CareplusExporter with the correct parameters" do
32-
team = create(:team)
33-
academic_year = AcademicYear.current
34-
start_date = 1.month.ago.to_date
35-
end_date = Date.current
31+
describe ".vaccination_records_scope" do
32+
let(:programme) { Programme.hpv }
33+
let(:export_date) { Date.new(2025, 8, 31) }
34+
let(:team) do
35+
create(
36+
:team,
37+
:with_careplus_enabled,
38+
programmes: [programme],
39+
careplus_integration_enabled_at: Time.zone.local(2025, 8, 28, 10)
40+
)
41+
end
42+
let(:session) { create(:session, team:, programmes: [programme]) }
3643

37-
expect(Reports::CareplusExporter).to receive(
38-
:vaccination_records_scope
39-
).with(
40-
team:,
41-
programmes: team.programmes,
42-
academic_year:,
43-
start_date:,
44-
end_date:,
45-
include_missing_nhs_number: false
46-
)
44+
it "includes records changed in the export window" do
45+
included_record =
46+
create(
47+
:vaccination_record,
48+
patient: create(:patient, session:),
49+
session:,
50+
programme:,
51+
performed_at: export_date,
52+
created_at: export_date,
53+
updated_at: export_date
54+
)
4755

48-
described_class.vaccination_records_scope(
49-
team:,
50-
academic_year:,
51-
start_date:,
52-
end_date:
53-
)
56+
scope =
57+
described_class.vaccination_records_scope(
58+
team:,
59+
academic_year: export_date.academic_year,
60+
start_date: export_date,
61+
end_date: export_date
62+
)
63+
64+
expect(scope).to include(included_record)
65+
end
66+
67+
it "includes older records for patients who first had an NHS number added in the export window" do
68+
patient =
69+
create(
70+
:patient,
71+
session:,
72+
nhs_number_first_added_at: Time.zone.local(2025, 8, 31, 9)
73+
)
74+
included_record =
75+
create(
76+
:vaccination_record,
77+
patient:,
78+
session:,
79+
programme:,
80+
performed_at: Date.new(2025, 8, 29),
81+
created_at: Time.zone.local(2025, 8, 29, 12),
82+
updated_at: Time.zone.local(2025, 8, 29, 12)
83+
)
84+
85+
scope =
86+
described_class.vaccination_records_scope(
87+
team:,
88+
academic_year: export_date.academic_year,
89+
start_date: export_date,
90+
end_date: export_date
91+
)
92+
93+
expect(scope).to include(included_record)
94+
end
5495
end
5596

5697
it "passes the correct parameters to CareplusExporter.from_records" do

0 commit comments

Comments
 (0)