Skip to content

Commit 716cabe

Browse files
Merge pull request #6008 from nhsuk/alistair/fix-performed-at-time
Allow `performed_at_time` to be optional for national reporting users
2 parents 4c8c83d + adc4298 commit 716cabe

7 files changed

Lines changed: 296 additions & 5 deletions

File tree

app/controllers/draft_vaccination_records_controller.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ def update
7070

7171
def validate_params
7272
if current_step == :date_and_time
73+
TimeParamsNormalizer.call!(
74+
params: params[:draft_vaccination_record],
75+
field_name: :performed_at_time
76+
)
77+
7378
date_validator =
7479
DateParamsValidator.new(
7580
field_name: :performed_at_date,

app/lib/time_params_normalizer.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# frozen_string_literal: true
2+
3+
class TimeParamsNormalizer
4+
def initialize(params:, field_name:)
5+
@params = params
6+
@field_name = field_name
7+
end
8+
9+
HOUR_SUFFIX = "(4i)"
10+
MINUTE_SUFFIX = "(5i)"
11+
SECOND_SUFFIX = "(6i)"
12+
13+
def call!
14+
if hour_blank? && minute_blank? && seconds_present?
15+
@params["#{@field_name}#{SECOND_SUFFIX}"] = ""
16+
end
17+
@params
18+
end
19+
20+
def self.call!(...) = new(...).call!
21+
22+
private_class_method :new
23+
24+
private
25+
26+
def hour_blank?
27+
@params["#{@field_name}#{HOUR_SUFFIX}"].blank?
28+
end
29+
30+
def minute_blank?
31+
@params["#{@field_name}#{MINUTE_SUFFIX}"].blank?
32+
end
33+
34+
def seconds_present?
35+
@params.key?("#{@field_name}#{SECOND_SUFFIX}")
36+
end
37+
end

app/lib/time_params_validator.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ def time_params_valid?
2222
time = time_params_as_struct
2323

2424
return true if [time.hour, time.minute, time.second].all?(&:blank?)
25+
# If `omit_second` is set on the field, then the seconds field defaults to "0"
26+
return true if time.hour.blank? && time.minute.blank? && time.second == "0"
2527

2628
if time.second.blank?
2729
object.errors.add(field_name, :missing_second)

app/models/draft_vaccination_record.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ def wizard_steps
7777
end
7878

7979
on_wizard_step :date_and_time, exact: true do
80-
validates :performed_at_date, :performed_at_time, presence: true
80+
validates :performed_at_date, presence: true
81+
validates :performed_at_time,
82+
presence: true,
83+
unless: :national_reporting_user_and_record?
8184
validate :performed_at_date_within_range
8285
end
8386

@@ -159,9 +162,11 @@ def wizard_steps
159162
validates :delivery_method,
160163
:delivery_site,
161164
:performed_at_date,
162-
:performed_at_time,
163165
:protocol,
164166
presence: true
167+
validates :performed_at_time,
168+
presence: true,
169+
unless: :national_reporting_user_and_record?
165170
validates :batch_number,
166171
:batch_expiry,
167172
presence: true,

config/locales/en.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,9 @@ en:
157157
performed_at_time:
158158
blank: Enter a date time
159159
invalid: Enter a valid time
160-
missing_hour: Enter a day
161-
missing_minute: Enter a month
162-
missing_second: Enter a year
160+
missing_hour: Enter an hour
161+
missing_minute: Enter a minute
162+
missing_second: Enter a second
163163
performed_by_given_name:
164164
blank: First name can't be blank
165165
performed_by_family_name:

spec/features/edit_vaccination_record_spec.rb

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,38 @@
398398
then_i_should_see_the_vaccination_record
399399
end
400400

401+
scenario "Edits the date and time with or without time" do
402+
given_i_am_signed_in
403+
and_a_national_reporting_vaccination_record_exists
404+
405+
when_i_navigate_to_the_edit_vaccination_record_page
406+
407+
when_i_click_on_change_date
408+
then_i_should_see_the_date_time_form
409+
410+
when_i_fill_in_a_valid_date_with_time
411+
then_i_see_the_edit_vaccination_record_page
412+
and_i_should_see_the_updated_date_with_time
413+
414+
when_i_click_on_save_changes
415+
then_i_should_see_the_vaccination_record
416+
and_the_vaccination_record_should_have_the_time
417+
418+
when_i_click_on_edit_vaccination_record
419+
then_i_see_the_edit_vaccination_record_page
420+
421+
when_i_click_on_change_date
422+
then_i_should_see_the_date_time_form
423+
424+
when_i_fill_in_a_valid_date_without_time
425+
then_i_see_the_edit_vaccination_record_page
426+
and_i_should_see_the_updated_date_without_time
427+
428+
when_i_click_on_save_changes
429+
then_i_should_see_the_vaccination_record
430+
and_the_vaccination_record_should_have_no_time
431+
end
432+
401433
scenario "Parent details are not visible when viewing vaccination records" do
402434
given_i_am_signed_in
403435
and_a_national_reporting_vaccination_record_exists
@@ -1099,4 +1131,60 @@ def then_i_should_see_a_success_message
10991131
text: "Vaccination outcome recorded for flu"
11001132
)
11011133
end
1134+
1135+
def when_i_fill_in_a_valid_date_with_time
1136+
@valid_date = Date.current - 1.day
1137+
@valid_time_hour = "14"
1138+
@valid_time_minute = "30"
1139+
1140+
fill_in "Year", with: @valid_date.year.to_s
1141+
fill_in "Month", with: @valid_date.month.to_s
1142+
fill_in "Day", with: @valid_date.day.to_s
1143+
1144+
fill_in "Hour", with: @valid_time_hour
1145+
fill_in "Minute", with: @valid_time_minute
1146+
1147+
click_on "Continue"
1148+
end
1149+
1150+
def and_i_should_see_the_updated_date_with_time
1151+
formatted_date = @valid_date.strftime("%-d %B %Y")
1152+
1153+
expect(page).to have_content("Date#{formatted_date}")
1154+
expect(page).to have_content("Time2:30pm")
1155+
end
1156+
1157+
def and_the_vaccination_record_should_have_the_time
1158+
@vaccination_record.reload
1159+
expect(@vaccination_record.performed_at_time).not_to be_nil
1160+
expect(@vaccination_record.performed_at_time.hour).to eq(14)
1161+
expect(@vaccination_record.performed_at_time.min).to eq(30)
1162+
expect(@vaccination_record.performed_at_date).to eq(@valid_date)
1163+
end
1164+
1165+
def when_i_fill_in_a_valid_date_without_time
1166+
@valid_date = Date.current - 1.day
1167+
1168+
fill_in "Year", with: @valid_date.year.to_s
1169+
fill_in "Month", with: @valid_date.month.to_s
1170+
fill_in "Day", with: @valid_date.day.to_s
1171+
1172+
fill_in "Hour", with: ""
1173+
fill_in "Minute", with: ""
1174+
1175+
click_on "Continue"
1176+
end
1177+
1178+
def and_i_should_see_the_updated_date_without_time
1179+
formatted_date = @valid_date.strftime("%-d %B %Y")
1180+
1181+
expect(page).to have_content("Date#{formatted_date}")
1182+
expect(page).not_to have_content(/Time\d/)
1183+
end
1184+
1185+
def and_the_vaccination_record_should_have_no_time
1186+
@vaccination_record.reload
1187+
expect(@vaccination_record.performed_at_time).to be_nil
1188+
expect(@vaccination_record.performed_at_date).to eq(@valid_date)
1189+
end
11021190
end
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# frozen_string_literal: true
2+
3+
describe TimeParamsNormalizer do
4+
describe ".call" do
5+
subject(:call_normalizer) { described_class.call!(params:, field_name:) }
6+
7+
let(:field_name) { :performed_at_time }
8+
9+
context "when hour and minute are blank but seconds is present" do
10+
let(:params) do
11+
{
12+
"performed_at_time(4i)" => "",
13+
"performed_at_time(5i)" => "",
14+
"performed_at_time(6i)" => "0"
15+
}
16+
end
17+
18+
it "blanks the seconds field" do
19+
call_normalizer
20+
expect(params["performed_at_time(6i)"]).to eq("")
21+
end
22+
23+
it "returns the params hash" do
24+
expect(call_normalizer).to eq(params)
25+
end
26+
end
27+
28+
context "when hour and minute are nil but seconds is present" do
29+
let(:params) do
30+
{
31+
"performed_at_time(4i)" => nil,
32+
"performed_at_time(5i)" => nil,
33+
"performed_at_time(6i)" => "0"
34+
}
35+
end
36+
37+
it "blanks the seconds field" do
38+
call_normalizer
39+
expect(params["performed_at_time(6i)"]).to eq("")
40+
end
41+
end
42+
43+
context "when all time fields are blank" do
44+
let(:params) do
45+
{
46+
"performed_at_time(4i)" => "",
47+
"performed_at_time(5i)" => "",
48+
"performed_at_time(6i)" => ""
49+
}
50+
end
51+
52+
it "leaves seconds blank" do
53+
call_normalizer
54+
expect(params["performed_at_time(6i)"]).to eq("")
55+
end
56+
end
57+
58+
context "when hour and minute are blank and seconds is not present" do
59+
let(:params) do
60+
{ "performed_at_time(4i)" => "", "performed_at_time(5i)" => "" }
61+
end
62+
63+
it "does not add a seconds field" do
64+
call_normalizer
65+
expect(params).not_to have_key("performed_at_time(6i)")
66+
end
67+
end
68+
69+
context "when hour is present but minute is blank" do
70+
let(:params) do
71+
{
72+
"performed_at_time(4i)" => "12",
73+
"performed_at_time(5i)" => "",
74+
"performed_at_time(6i)" => "0"
75+
}
76+
end
77+
78+
it "does not modify seconds" do
79+
call_normalizer
80+
expect(params["performed_at_time(6i)"]).to eq("0")
81+
end
82+
end
83+
84+
context "when minute is present but hour is blank" do
85+
let(:params) do
86+
{
87+
"performed_at_time(4i)" => "",
88+
"performed_at_time(5i)" => "30",
89+
"performed_at_time(6i)" => "0"
90+
}
91+
end
92+
93+
it "does not modify seconds" do
94+
call_normalizer
95+
expect(params["performed_at_time(6i)"]).to eq("0")
96+
end
97+
end
98+
99+
context "when hour and minute are both present" do
100+
let(:params) do
101+
{
102+
"performed_at_time(4i)" => "12",
103+
"performed_at_time(5i)" => "30",
104+
"performed_at_time(6i)" => "0"
105+
}
106+
end
107+
108+
it "does not modify seconds" do
109+
call_normalizer
110+
expect(params["performed_at_time(6i)"]).to eq("0")
111+
end
112+
end
113+
114+
context "with a different field name" do
115+
let(:field_name) { :another_time }
116+
117+
let(:params) do
118+
{
119+
"another_time(4i)" => "",
120+
"another_time(5i)" => "",
121+
"another_time(6i)" => "0"
122+
}
123+
end
124+
125+
it "normalizes the correct field" do
126+
call_normalizer
127+
expect(params["another_time(6i)"]).to eq("")
128+
end
129+
end
130+
131+
context "when params contain other fields" do
132+
let(:params) do
133+
{
134+
"performed_at_date(1i)" => "2025",
135+
"performed_at_date(2i)" => "7",
136+
"performed_at_date(3i)" => "31",
137+
"performed_at_time(4i)" => "",
138+
"performed_at_time(5i)" => "",
139+
"performed_at_time(6i)" => "0",
140+
"notes" => "Some notes"
141+
}
142+
end
143+
144+
it "only modifies the time seconds field" do
145+
call_normalizer
146+
expect(params["performed_at_date(1i)"]).to eq("2025")
147+
expect(params["performed_at_date(2i)"]).to eq("7")
148+
expect(params["performed_at_date(3i)"]).to eq("31")
149+
expect(params["performed_at_time(6i)"]).to eq("")
150+
expect(params["notes"]).to eq("Some notes")
151+
end
152+
end
153+
end
154+
end

0 commit comments

Comments
 (0)