Skip to content

Commit e9290c8

Browse files
committed
Fix race condition allowing vaccination records when patient marked absent
Adds validation to prevent creating vaccination records for patients marked as not attending a session. Previously, a race condition existed where a vaccination could be confirmed after a patient was marked absent in another tab or by another user. The validation now checks attendance status at the confirmation step and displays an error message prompting users to mark the patient as attending before proceeding. Jira-Issue: MAV-1212
1 parent 1366106 commit e9290c8

5 files changed

Lines changed: 65 additions & 1 deletion

app/models/draft_vaccination_record.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ def wizard_steps
134134
on_wizard_step :confirm, exact: true do
135135
validates :outcome, presence: true
136136
validates :notes, length: { maximum: 1000 }
137+
validate :validate_patient_attendance
137138
end
138139

139140
on_wizard_step :vaccinator, exact: true do
@@ -507,4 +508,23 @@ def delivery_site_matches_delivery_method
507508
errors.add(:delivery_site, :inclusion)
508509
end
509510
end
511+
512+
def validate_patient_attendance
513+
return unless new_record?
514+
return unless session&.today?
515+
return if patient.blank?
516+
517+
attendance_record =
518+
patient.attendance_records.find_by(
519+
location: session.location,
520+
date: session.dates.find(&:today?)
521+
)
522+
523+
return if attendance_record&.attending?
524+
525+
errors.add(
526+
:base,
527+
"Child is marked as not attending this session. Mark them as attending to record a vaccination."
528+
)
529+
end
510530
end

spec/features/flu_vaccination_hca_national_protocol_spec.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,21 @@ def and_patients_exist
9797
@patient_nasal_only =
9898
create(
9999
:patient,
100+
:in_attendance,
100101
:consent_given_nasal_only_triage_not_needed,
101102
session: @session
102103
)
103104
@patient_nasal_and_injection =
104105
create(
105106
:patient,
107+
:in_attendance,
106108
:consent_given_nasal_or_injection_triage_not_needed,
107109
session: @session
108110
)
109111
@patient_injection_only =
110112
create(
111113
:patient,
114+
:in_attendance,
112115
:consent_given_injection_only_triage_not_needed,
113116
session: @session
114117
)

spec/features/flu_vaccination_hca_pgd_supply_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,21 @@ def and_patients_exist
7373
@patient_nasal_only =
7474
create(
7575
:patient,
76+
:in_attendance,
7677
:consent_given_nasal_only_triage_not_needed,
7778
session: @session
7879
)
7980
@patient_nasal_and_injection =
8081
create(
8182
:patient,
83+
:in_attendance,
8284
:consent_given_nasal_or_injection_triage_not_needed,
8385
session: @session
8486
)
8587
@patient_injection_only =
8688
create(
8789
:patient,
90+
:in_attendance,
8891
:consent_given_injection_only_triage_not_needed,
8992
session: @session
9093
)
@@ -103,6 +106,7 @@ def and_a_nasal_patient_exists_with_health_issues_marked_safe_vaccinate_with_nas
103106
@patient_nasal_only =
104107
create(
105108
:patient,
109+
:in_attendance,
106110
:consent_given_nasal_triage_safe_to_vaccinate_nasal,
107111
session: @session
108112
)

spec/features/flu_vaccination_hca_psd_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ def and_patients_exist
118118
create(
119119
:patient,
120120
:consent_given_nasal_only_triage_not_needed,
121+
:in_attendance,
121122
session: @session
122123
)
123124
@patient_injection_only =

spec/models/draft_vaccination_record_spec.rb

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
let(:programme) { Programme.hpv }
1414
let(:session) { create(:session, team:, programmes: [programme]) }
15-
let(:patient) { create(:patient, session:) }
15+
let(:patient) { create(:patient, :in_attendance, session:) }
1616
let(:vaccine) { programme.vaccines.first }
1717
let(:batch) { create(:batch, team:, vaccine:, expiry: Date.new(2026, 11, 1)) }
1818

@@ -128,6 +128,42 @@
128128
it { should validate_length_of(:notes).is_at_most(1000).on(:update) }
129129
end
130130

131+
context "when the patient is marked not attending" do
132+
let(:attributes) { valid_administered_attributes }
133+
let(:patient) { create(:patient, session:) }
134+
135+
before do
136+
draft_vaccination_record.wizard_step = :confirm
137+
create(:attendance_record, :today, :absent, patient:, session:)
138+
end
139+
140+
it "raises an error when attempting to save the record" do
141+
expect(draft_vaccination_record.save(context: :update)).to be(false)
142+
expect(draft_vaccination_record.errors[:base]).to include(
143+
"Child is marked as not attending this session. Mark them as attending to record a vaccination."
144+
)
145+
end
146+
147+
context "when editing an existing vaccination record" do
148+
let(:existing_vaccination_record) do
149+
create(:vaccination_record, patient:, session:)
150+
end
151+
152+
let(:attributes) do
153+
valid_administered_attributes.merge(
154+
editing_id: existing_vaccination_record.id
155+
)
156+
end
157+
158+
it "does not raise an attendance error" do
159+
expect(draft_vaccination_record.save(context: :update)).to be(true)
160+
expect(draft_vaccination_record.errors[:base]).not_to include(
161+
"Child is marked as not attending this session. Mark them as attending to record a vaccination."
162+
)
163+
end
164+
end
165+
end
166+
131167
context "on delivery step" do
132168
let(:attributes) { valid_administered_attributes }
133169

0 commit comments

Comments
 (0)