Skip to content

Commit c0a912f

Browse files
authored
Merge pull request #5529 from nhsuk/mavis-cli-generate-fixes
Fixes to Mavis CLI generate consents and vaccination-records commands
2 parents 538b867 + 7294262 commit c0a912f

6 files changed

Lines changed: 306 additions & 100 deletions

File tree

app/lib/generate/consents.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ def patients
4343
else
4444
team
4545
.sessions
46-
.eager_load(:location)
46+
.eager_load(
47+
:location,
48+
:session_programme_year_groups,
49+
:team_location
50+
)
4751
.merge(Location.school)
4852
.has_all_programmes_of([programme])
4953
end
@@ -72,7 +76,9 @@ def session_for(patient)
7276
@session ||
7377
patient
7478
.sessions
75-
.eager_load(:location)
79+
.joins(
80+
"INNER JOIN locations ON locations.id = team_locations.location_id"
81+
)
7682
.merge(Location.school)
7783
.has_all_programmes_of([programme])
7884
.sample
@@ -116,7 +122,9 @@ def validate_programme_and_session(programme, session)
116122
if session.programmes.exclude?(programme)
117123
raise "Session does not support programme #{programme.type}"
118124
end
119-
elsif programme.sessions.none? { it.location.school? }
125+
elsif Session
126+
.has_any_programmes_of([programme])
127+
.none? { it.location.school? }
120128
raise "Programme #{programme.type} does not have a school session"
121129
end
122130
end

app/lib/generate/vaccination_records.rb

Lines changed: 89 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -12,84 +12,120 @@ def call = create_vaccinations
1212

1313
def self.call(...) = new(...).call
1414

15+
class NotEnoughAvailablePatients < StandardError
16+
end
17+
18+
class SessionHasNoDates < StandardError
19+
end
20+
21+
class NoSessionsWithDates < StandardError
22+
end
23+
24+
class NoSessionsWithPatients < StandardError
25+
end
26+
1527
private
1628

1729
attr_reader :config, :team, :programme, :session, :administered
1830

1931
def create_vaccinations
20-
attendance_records = []
21-
vaccination_records = []
22-
23-
sessions.each do |session|
24-
location = session.location
25-
26-
random_patients_for(session:).each do |patient|
27-
unless AttendanceRecord.exists?(patient:, location:)
28-
attendance_records << FactoryBot.build(
29-
:attendance_record,
30-
:present,
31-
patient:,
32-
session:
33-
)
34-
end
35-
36-
location_name = location.name if session.clinic?
37-
38-
vaccination_records << FactoryBot.build(
39-
:vaccination_record,
40-
:administered,
41-
patient:,
42-
programme:,
43-
team:,
44-
performed_by:,
45-
session:,
46-
vaccine:,
47-
batch:,
48-
location_name:
49-
)
50-
end
32+
attendances = []
33+
vaccinations = []
34+
35+
check_sessions_have_enough_patients
36+
37+
each_random_patient_ready_for_vaccination(
38+
administered
39+
) do |session, patient|
40+
attendance, vaccination =
41+
create_administered_vaccination(session, patient)
42+
43+
attendances << attendance if attendance.present?
44+
vaccinations << vaccination
5145
end
5246

53-
AttendanceRecord.import!(attendance_records)
54-
imported_ids = VaccinationRecord.import!(vaccination_records).ids
47+
AttendanceRecord.import!(attendances)
48+
imported_ids = VaccinationRecord.import!(vaccinations).ids
5549
SyncPatientTeamJob.perform_later(VaccinationRecord, imported_ids)
5650

57-
StatusUpdater.call(patient: vaccination_records.map(&:patient))
51+
StatusUpdater.call(patient: vaccinations.map(&:patient))
5852
end
5953

60-
def random_patients_for(session:)
61-
if administered&.positive?
62-
patients_for(session:)
63-
.sample(administered)
64-
.tap do |selected|
65-
if selected.size < administered
66-
info =
67-
"#{selected.size} (patient_locations) < #{administered} (administered)"
68-
raise "Not enough patients to generate vaccinations: #{info}"
69-
end
70-
end
71-
else
72-
patients_for(session:)
54+
def check_sessions_have_enough_patients
55+
available_patients = sessions.sum { patients_for(session: it).count }
56+
if available_patients < administered
57+
info =
58+
"#{available_patients} (available patients) < #{administered} (administered)"
59+
raise NotEnoughAvailablePatients, info
7360
end
7461
end
7562

63+
def each_random_patient_ready_for_vaccination(count)
64+
count.times do
65+
session = sessions.sample
66+
patients = patients_for(session:)
67+
68+
patient = patients.sample
69+
70+
yield session, patient
71+
72+
patients.delete(patient)
73+
sessions.delete(session) if patients.empty?
74+
end
75+
end
76+
77+
def create_administered_vaccination(session, patient)
78+
location = session.location
79+
80+
attendance = nil
81+
82+
unless AttendanceRecord.exists?(patient:, location:)
83+
attendance =
84+
FactoryBot.build(:attendance_record, :present, patient:, session:)
85+
end
86+
87+
location_name = location.name if session.clinic?
88+
89+
vaccination =
90+
FactoryBot.build(
91+
:vaccination_record,
92+
:administered,
93+
patient:,
94+
programme:,
95+
team:,
96+
performed_by:,
97+
session:,
98+
vaccine:,
99+
batch:,
100+
location_name:
101+
)
102+
103+
[attendance, vaccination]
104+
end
105+
76106
def sessions
77107
@sessions ||=
78108
if session
109+
raise SessionHasNoDates, session.id if session.dates.empty?
79110
[session]
80111
else
81-
team.sessions.includes(
82-
:location,
83-
:session_programme_year_groups,
84-
:team_location
85-
)
112+
team
113+
.sessions
114+
.where.not(dates: [])
115+
.tap { raise NoSessionsWithDates if it.empty? }
116+
.includes(:location, :session_programme_year_groups, :team_location)
117+
.select { patients_for(session: it).any? }
118+
.tap { raise NoSessionsWithPatients if it.empty? }
86119
end
87120
end
88121

89122
def patients_for(session:)
123+
@patients_for ||= {}
124+
return @patients_for[session.id] if @patients_for.key?(session.id)
125+
90126
academic_year = session.academic_year
91127

92-
session
128+
@patients_for[session.id] = session
93129
.patients
94130
.includes_statuses
95131
.appear_in_programmes([programme], academic_year:)

app/lib/mavis_cli/generate/vaccination_records.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ class VaccinationRecords < Dry::CLI::Command
77
option :team_workgroup,
88
aliases: ["-w"],
99
default: "A9A5A",
10-
desc: "Workgroup of team to generate consents for"
10+
desc: "Workgroup of team to generate vaccinations for"
1111
option :programme_type,
1212
aliases: ["-p"],
1313
default: "hpv",
1414
desc:
15-
"Programme type to generate consents for (hpv, menacwy, td_ipv, etc)"
15+
"Programme type to generate vaccinations for (hpv, menacwy, td_ipv, etc)"
1616
option :session_id,
1717
aliases: ["-s"],
1818
desc:
19-
"Generate consents for patients in a session, instead of" \
19+
"Generate vaccinations for patients in a session, instead of" \
2020
" across the entire team"
2121
option :administered,
2222
default: 0,

spec/features/cli_generate_consents_spec.rb

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,21 @@
33
require_relative "../../app/lib/mavis_cli"
44

55
describe "mavis generate consents" do
6-
it "generates consents" do
7-
given_an_team_exists
6+
scenario "generating consents for a specific session" do
7+
given_a_team_exists
88
and_there_are_three_patients_in_a_session
9-
when_i_run_the_generate_consents_command
10-
then_consents_are_created_with_the_given_statuses
9+
when_i_run_the_generate_consents_command_for_that_session
10+
then_consents_are_created_within_the_session
1111
end
1212

13-
def given_an_team_exists
13+
scenario "generating consents for any session" do
14+
given_a_team_exists
15+
and_there_are_two_sessions_with_two_patients
16+
when_i_generate_one_of_each_consents_across_all_sessions
17+
then_one_of_each_consent_is_created_across_sessions
18+
end
19+
20+
def given_a_team_exists
1421
@team = create(:team)
1522
@programme = Programme.hpv
1623
end
@@ -28,7 +35,22 @@ def and_there_are_three_patients_in_a_session
2835
)
2936
end
3037

31-
def when_i_run_the_generate_consents_command
38+
def and_there_are_two_sessions_with_two_patients
39+
2.times.map do
40+
session = create(:session, team: @team, programmes: [@programme])
41+
parent = create(:parent)
42+
create_list(
43+
:patient,
44+
2,
45+
team: @team,
46+
session:,
47+
programmes: [@programme],
48+
parents: [parent]
49+
)
50+
end
51+
end
52+
53+
def when_i_run_the_generate_consents_command_for_that_session
3254
@consent_count_before = @team.consents.count
3355

3456
Dry::CLI.new(MavisCLI).call(
@@ -51,8 +73,33 @@ def when_i_run_the_generate_consents_command
5173
)
5274
end
5375

54-
def then_consents_are_created_with_the_given_statuses
55-
expect(@team.consents.count).to eq @consent_count_before + 3
76+
def when_i_generate_one_of_each_consents_across_all_sessions
77+
Dry::CLI.new(MavisCLI).call(
78+
arguments: [
79+
"generate",
80+
"consents",
81+
"-w",
82+
@team.workgroup,
83+
"-p",
84+
@programme.type,
85+
"-g",
86+
"1",
87+
"-N",
88+
"1",
89+
"-r",
90+
"1"
91+
]
92+
)
93+
end
94+
95+
def then_consents_are_created_within_the_session
96+
expect(
97+
@session.patients.flat_map(&:consents).count
98+
).to eq @consent_count_before + 3
99+
end
100+
101+
def then_one_of_each_consent_is_created_across_sessions
102+
expect(@team.consents.count).to eq 3
56103

57104
expect(
58105
@team
@@ -69,5 +116,30 @@ def then_consents_are_created_with_the_given_statuses
69116
)
70117
.count
71118
).to eq 1
119+
expect(
120+
@team
121+
.patients
122+
.has_consent_status(
123+
:given,
124+
programme: @programme,
125+
academic_year: AcademicYear.current
126+
)
127+
.has_triage_status(
128+
:required,
129+
programme: @programme,
130+
academic_year: AcademicYear.current
131+
)
132+
.count
133+
).to eq 1
134+
expect(
135+
@team
136+
.patients
137+
.has_consent_status(
138+
:refused,
139+
programme: @programme,
140+
academic_year: AcademicYear.current
141+
)
142+
.count
143+
).to eq 1
72144
end
73145
end

0 commit comments

Comments
 (0)