Skip to content

Commit 9913f07

Browse files
committed
Add CSVImportable#process!
This extracts the `process!` method from `ImmunisationImport` and `CohortImport` to the common concern used by both of them to ensure that the behaviour is the same across both import models.
1 parent 2569234 commit 9913f07

File tree

5 files changed

+93
-79
lines changed

5 files changed

+93
-79
lines changed

app/models/cohort_import.rb

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,6 @@
2727
class CohortImport < ApplicationRecord
2828
include CSVImportable
2929

30-
def process!
31-
parse_rows! if rows.nil?
32-
return if invalid?
33-
34-
ActiveRecord::Base.transaction do
35-
save!
36-
37-
rows.each do |row|
38-
location = Location.find_by(urn: row.school_urn)
39-
patient =
40-
location.patients.new(
41-
row.to_patient.merge(parent: Parent.new(row.to_parent))
42-
)
43-
patient.save!
44-
end
45-
end
46-
end
47-
4830
private
4931

5032
def required_headers
@@ -67,6 +49,10 @@ def required_headers
6749
]
6850
end
6951

52+
def count_columns
53+
%i[new_record_count exact_duplicate_record_count]
54+
end
55+
7056
def parse_row(row_data)
7157
CohortImportRow.new(
7258
row_data
@@ -75,4 +61,14 @@ def parse_row(row_data)
7561
.transform_keys { _1.downcase.to_sym }
7662
)
7763
end
64+
65+
def process_row(row)
66+
location = Location.find_by(urn: row.school_urn)
67+
68+
location.patients.create!(
69+
row.to_patient.merge(parent: Parent.new(row.to_parent))
70+
)
71+
72+
:new_record_count
73+
end
7874
end

app/models/concerns/csv_importable.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ module CSVImportable
2929
validate :csv_has_records
3030
validate :headers_are_valid
3131
validate :rows_are_valid
32+
33+
before_save :ensure_processed_with_count_statistics
3234
end
3335

3436
def csv=(file)
@@ -60,6 +62,30 @@ def parse_rows!
6062
self.rows = data.map { |row_data| parse_row(row_data) }
6163
end
6264

65+
def processed?
66+
processed_at != nil
67+
end
68+
69+
def process!
70+
return if processed?
71+
72+
parse_rows! if rows.nil?
73+
return if invalid?
74+
75+
counts = count_columns.index_with(0)
76+
77+
ActiveRecord::Base.transaction do
78+
save!
79+
80+
rows.each do |row|
81+
count_column_to_increment = process_row(row)
82+
counts[count_column_to_increment] += 1
83+
end
84+
85+
update!(processed_at: Time.zone.now, **counts)
86+
end
87+
end
88+
6389
def remove!
6490
return if csv_removed?
6591
update!(csv_data: nil, csv_removed_at: Time.zone.now)
@@ -93,4 +119,12 @@ def rows_are_valid
93119
end
94120
end
95121
end
122+
123+
def ensure_processed_with_count_statistics
124+
if processed? && count_columns.any? { |column| send(column).nil? }
125+
raise "Count statistics must be set for a processed import."
126+
elsif !processed? && count_columns.any? { |column| !send(column).nil? }
127+
raise "Count statistics must not be set for a non-processed import."
128+
end
129+
end
96130
end

app/models/immunisation_import.rb

Lines changed: 18 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -42,46 +42,6 @@ class ImmunisationImport < ApplicationRecord
4242
has_many :patients
4343
end
4444

45-
before_save :ensure_processed_with_count_statistics
46-
47-
COUNT_COLUMNS = %i[
48-
exact_duplicate_record_count
49-
new_record_count
50-
not_administered_record_count
51-
].freeze
52-
53-
def processed?
54-
processed_at != nil
55-
end
56-
57-
def process!
58-
return if processed?
59-
60-
parse_rows! if rows.nil?
61-
return if invalid?
62-
63-
stats = COUNT_COLUMNS.index_with { |_column| 0 }
64-
65-
ActiveRecord::Base.transaction do
66-
save!
67-
68-
rows.each do |row|
69-
if (vaccination_record = row.to_vaccination_record)
70-
if vaccination_record.new_record?
71-
vaccination_record.save!
72-
stats[:new_record_count] += 1
73-
else
74-
stats[:exact_duplicate_record_count] += 1
75-
end
76-
else
77-
stats[:not_administered_record_count] += 1
78-
end
79-
end
80-
81-
update!(processed_at: Time.zone.now, **stats)
82-
end
83-
end
84-
8545
def record!
8646
return if recorded?
8747

@@ -127,6 +87,14 @@ def required_headers
12787
]
12888
end
12989

90+
def count_columns
91+
%i[
92+
exact_duplicate_record_count
93+
new_record_count
94+
not_administered_record_count
95+
]
96+
end
97+
13098
def parse_row(row_data)
13199
ImmunisationImportRow.new(
132100
data: row_data,
@@ -136,11 +104,16 @@ def parse_row(row_data)
136104
)
137105
end
138106

139-
def ensure_processed_with_count_statistics
140-
if processed? && COUNT_COLUMNS.any? { |column| send(column).nil? }
141-
raise "Count statistics must be set for a processed import."
142-
elsif !processed? && COUNT_COLUMNS.any? { |column| !send(column).nil? }
143-
raise "Count statistics must not be set for a non-processed import."
107+
def process_row(row)
108+
if (vaccination_record = row.to_vaccination_record)
109+
if vaccination_record.new_record?
110+
vaccination_record.save!
111+
:new_record_count
112+
else
113+
:exact_duplicate_record_count
114+
end
115+
else
116+
:not_administered_record_count
144117
end
145118
end
146119
end

spec/models/immunisation_import_spec.rb

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,6 @@
4949

5050
it_behaves_like "a CSVImportable model"
5151

52-
it "raises if processed without updating the statistics" do
53-
expect {
54-
immunisation_import.update!(processed_at: Time.zone.now)
55-
}.to raise_error(/Count statistics must be set/)
56-
end
57-
58-
describe "#csv=" do
59-
it "sets the data" do
60-
expect(immunisation_import.csv_data).not_to be_empty
61-
end
62-
63-
it "sets the filename" do
64-
expect(immunisation_import.csv_filename).to eq("valid_flu.csv")
65-
end
66-
end
67-
6852
describe "#load_data!" do
6953
before { immunisation_import.load_data! }
7054

spec/support/a_csv_importable_model.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,22 @@
1414

1515
it { should be_invalid }
1616
end
17+
18+
it "raises if processed without updating the statistics" do
19+
expect { subject.update!(processed_at: Time.zone.now) }.to raise_error(
20+
/Count statistics must be set/
21+
)
22+
end
23+
end
24+
25+
describe "#csv=" do
26+
it "sets the data" do
27+
expect(subject.csv_data).not_to be_empty
28+
end
29+
30+
it "sets the filename" do
31+
expect(subject.csv_filename).not_to be_empty
32+
end
1733
end
1834

1935
describe "#csv_removed?" do
@@ -30,6 +46,17 @@
3046
end
3147
end
3248

49+
describe "#process!" do
50+
let(:today) { Time.zone.local(2025, 1, 1) }
51+
52+
it "sets processed_at" do
53+
expect { travel_to(today) { subject.process! } }.to change(
54+
subject,
55+
:processed_at
56+
).from(nil).to(today)
57+
end
58+
end
59+
3360
describe "#remove!" do
3461
let(:today) { Time.zone.local(2020, 1, 1) }
3562

0 commit comments

Comments
 (0)