Browse Source

More work on bu validator specs - mostly sales

pull/2509/head
Rachael Booth 2 years ago
parent
commit
0bb6810355
  1. 3
      spec/factories/sales_log.rb
  2. 4
      spec/services/bulk_upload/lettings/validator_spec.rb
  3. 361
      spec/services/bulk_upload/sales/validator_spec.rb
  4. 80
      spec/support/bulk_upload/sales_log_to_csv.rb

3
spec/factories/sales_log.rb

@ -128,8 +128,7 @@ FactoryBot.define do
pregla { 1 } pregla { 1 }
pregother { 1 } pregother { 1 }
pregghb { 1 } pregghb { 1 }
hhregres { 1 } hhregres { 7 }
hhregresstill { 4 }
ppcodenk { 1 } ppcodenk { 1 }
prevten { 1 } prevten { 1 }
previous_la_known { 0 } previous_la_known { 0 }

4
spec/services/bulk_upload/lettings/validator_spec.rb

@ -235,11 +235,11 @@ RSpec.describe BulkUpload::Lettings::Validator do
describe "#create_logs?" do describe "#create_logs?" do
context "when a log has a clearable, non-setup error" do context "when a log has a clearable, non-setup error" do
let(:log_1) { build(:lettings_log, :completed, period: 2, assigned_to: user) } let(:log_1) { build(:lettings_log, :completed, period: 2, assigned_to: user) }
let(:log_2) { build(:lettings_log, :completed, period: 2, assigned_to: user) } let(:log_2) { build(:lettings_log, :completed, period: 2, assigned_to: user, age1: 5) }
before do before do
file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, col_offset: 0).to_csv_row) file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, col_offset: 0).to_csv_row)
file.write(BulkUpload::LettingsLogToCsv.new(log: log_2, col_offset: 0, overrides: { age1: 5 }).to_csv_row) file.write(BulkUpload::LettingsLogToCsv.new(log: log_2, col_offset: 0).to_csv_row)
file.close file.close
end end

361
spec/services/bulk_upload/sales/validator_spec.rb

@ -5,7 +5,9 @@ RSpec.describe BulkUpload::Sales::Validator do
let(:user) { create(:user, organisation:) } let(:user) { create(:user, organisation:) }
let(:organisation) { create(:organisation, old_visible_id: "123") } let(:organisation) { create(:organisation, old_visible_id: "123") }
let(:bulk_upload) { create(:bulk_upload, user:) } let(:log) { build(:sales_log, :completed, assigned_to: user) }
let(:log_to_csv) { BulkUpload::SalesLogToCsv.new(log:) }
let(:bulk_upload) { create(:bulk_upload, user:, year: log.collection_start_year) }
let(:path) { file.path } let(:path) { file.path }
let(:file) { Tempfile.new } let(:file) { Tempfile.new }
@ -40,185 +42,90 @@ RSpec.describe BulkUpload::Sales::Validator do
end end
end end
context "when trying to upload different year data for 2024 bulk upload" do context "when trying to upload 2023 logs for 2024 bulk upload" do
let(:bulk_upload) { create(:bulk_upload, user:, year: 2024) } let(:bulk_upload) { create(:bulk_upload, user:, year: 2024) }
let(:log) { build(:sales_log, :completed, saledate: Time.zone.local(2023, 10, 10), assigned_to: user) }
context "with a valid csv" do before do
let(:path) { file_fixture("2022_23_sales_bulk_upload.csv") } file.write(log_to_csv.default_2024_field_numbers_row)
file.write(log_to_csv.to_2024_csv_row)
it "is not valid" do file.rewind
expect(validator).not_to be_valid
end
end
context "with unix line endings" do
let(:fixture_path) { file_fixture("2022_23_sales_bulk_upload.csv") }
let(:file) { Tempfile.new }
let(:path) { file.path }
before do
string = File.read(fixture_path)
string.gsub!("\r\n", "\n")
file.write(string)
file.rewind
end
it "is not valid" do
expect(validator).not_to be_valid
end
end
context "without headers" do
let(:log) { build(:sales_log, :completed) }
let(:file) { Tempfile.new }
let(:path) { file.path }
before do
Timecop.freeze(Time.utc(2023, 10, 3))
file.write(BulkUpload::SalesLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2024_csv_row)
file.close
end
after do
Timecop.unfreeze
end
it "is not valid" do
expect(validator).not_to be_valid
end
end end
context "with headers" do it "is not valid" do
let(:file) { Tempfile.new } expect(validator).not_to be_valid
let(:seed) { rand } expect(validator.errors["base"]).to eql(["Incorrect sale dates, please ensure you have used the correct template"])
let(:log) { build(:sales_log, :completed, saledate: Time.zone.local(2023, 10, 10)) }
let(:log_to_csv) { BulkUpload::SalesLogToCsv.new(log:) }
let(:field_numbers) { log_to_csv.default_2024_field_numbers }
let(:field_values) { log_to_csv.to_2024_row }
before do
file.write(log_to_csv.custom_field_numbers_row(seed:, field_numbers:))
file.write(log_to_csv.to_custom_csv_row(seed:, field_values:))
file.rewind
end
it "is not valid" do
expect(validator).not_to be_valid
end
end end
end end
context "when trying to upload 2024 year data for 2024 bulk upload" do [
let(:bulk_upload) { create(:bulk_upload, user:, year: 2024) } { line_ending: "\n", name: "unix" },
{ line_ending: "\r\n", name: "windows" },
context "with headers" do ].each do |test_case|
let(:file) { Tempfile.new } context "with #{test_case[:name]} line endings" do
let(:seed) { rand } let(:log_to_csv) { BulkUpload::SalesLogToCsv.new(log:, line_ending: test_case[:line_ending]) }
let(:log) { build(:sales_log, :completed, saledate: Time.zone.local(2024, 10, 10)) }
let(:log_to_csv) { BulkUpload::SalesLogToCsv.new(log:) } context "with a valid file" do
let(:field_numbers) { log_to_csv.default_2024_field_numbers } before do
let(:field_values) { log_to_csv.to_2024_row } file.write(log_to_csv.default_field_numbers_row)
file.write(log_to_csv.to_csv_row)
before do file.rewind
file.write(log_to_csv.custom_field_numbers_row(seed:, field_numbers:)) end
file.write(log_to_csv.to_custom_csv_row(seed:, field_values:))
file.rewind it "is valid" do
end expect(validator).to be_valid
end
it "is valid" do
expect(validator).to be_valid
end end
end end
end end
context "when trying to upload different years data for 2023 bulk upload" do context "with a valid file in an arbitrary order" do
let(:bulk_upload) { create(:bulk_upload, user:, year: 2023) } let(:seed) { rand }
context "with a valid csv" do before do
let(:path) { file_fixture("2022_23_sales_bulk_upload.csv") } file.write(log_to_csv.default_field_numbers_row(seed:))
file.write(log_to_csv.to_csv_row(seed:))
it "is not valid" do file.rewind
expect(validator).not_to be_valid
end
end
context "with unix line endings" do
let(:fixture_path) { file_fixture("2022_23_sales_bulk_upload.csv") }
let(:file) { Tempfile.new }
let(:path) { file.path }
before do
string = File.read(fixture_path)
string.gsub!("\r\n", "\n")
file.write(string)
file.rewind
end
it "is not valid" do
expect(validator).not_to be_valid
end
end
context "without headers" do
let(:log) { build(:sales_log, :completed) }
let(:file) { Tempfile.new }
let(:path) { file.path }
before do
Timecop.freeze(Time.utc(2022, 10, 3))
file.write(BulkUpload::SalesLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row)
file.close
end
after do
Timecop.unfreeze
end
it "is not valid" do
expect(validator).not_to be_valid
end
end end
context "with headers" do it "is valid" do
let(:file) { Tempfile.new } expect(validator).to be_valid
let(:seed) { rand }
let(:log) { build(:sales_log, :completed, saledate: Time.zone.local(2022, 10, 10)) }
let(:log_to_csv) { BulkUpload::SalesLogToCsv.new(log:) }
let(:field_numbers) { log_to_csv.default_2023_field_numbers }
let(:field_values) { log_to_csv.to_2023_row }
before do
file.write(log_to_csv.custom_field_numbers_row(seed:, field_numbers:))
file.write(log_to_csv.to_custom_csv_row(seed:, field_values:))
file.rewind
end
it "is not valid" do
expect(validator).not_to be_valid
end
end end
end end
context "when file is missing required headers" do context "when file is missing required headers" do
let(:bulk_upload) { create(:bulk_upload, user:, year: 2024) }
let(:log) { build(:sales_log, :completed, saledate: Time.zone.local(2024, 5, 5)) }
let(:file) { Tempfile.new }
let(:path) { file.path }
before do before do
file.write(BulkUpload::SalesLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2024_csv_row) file.write(log_to_csv.to_csv_row)
file.close file.close
end end
it "is not valid" do it "is not valid" do
expect(validator).not_to be_valid expect(validator).not_to be_valid
expect(validator.errors["base"]).to include(match("Your file does not contain the required header rows."))
end end
end end
end end
describe "#call" do describe "#call" do
context "when a valid csv" do context "when a valid csv" do
let(:path) { file_fixture("2023_24_sales_bulk_upload_invalid.csv") } before do
file.write(log_to_csv.default_field_numbers_row)
file.write(log_to_csv.to_csv_row)
file.rewind
end
it "does not create validation errors" do
expect { validator.call }.not_to change(BulkUploadError, :count)
end
end
context "with an invalid 2024 csv" do
before do
log.owning_organisation = nil
file.write(log_to_csv.default_field_numbers_row)
file.write(log_to_csv.to_csv_row)
file.rewind
end
it "creates validation errors" do it "creates validation errors" do
expect { validator.call }.to change(BulkUploadError, :count) expect { validator.call }.to change(BulkUploadError, :count)
@ -227,41 +134,55 @@ RSpec.describe BulkUpload::Sales::Validator do
it "create validation error with correct values" do it "create validation error with correct values" do
validator.call validator.call
error = BulkUploadError.find_by(row: "9", field: "field_1", category: "setup") error = BulkUploadError.find_by(row: "2", field: "field_1", category: "setup")
expect(error.field).to eql("field_1") expect(error.field).to eql("field_1")
expect(error.error).to eql("You must answer owning organisation") expect(error.error).to eql("You must answer owning organisation")
expect(error.purchaser_code).to eql("23 test BU") expect(error.purchaser_code).to eql(log.purchaser_code)
expect(error.row).to eql("9") expect(error.row).to eql("2")
expect(error.cell).to eql("B9") expect(error.cell).to eql("B2")
expect(error.col).to eql("B") expect(error.col).to eql("B")
end end
end end
context "with unix line endings" do [
let(:fixture_path) { file_fixture("2023_24_sales_bulk_upload.csv") } { line_ending: "\n", name: "unix" },
let(:file) { Tempfile.new } { line_ending: "\r\n", name: "windows" },
let(:path) { file.path } ].each do |test_case|
context "with #{test_case[:name]} line endings" do
let(:log_to_csv) { BulkUpload::SalesLogToCsv.new(log:, line_ending: test_case[:line_ending]) }
context "with a valid file" do
before do
file.write(log_to_csv.default_field_numbers_row)
file.write(log_to_csv.to_csv_row)
file.rewind
end
it "does not create validation errors" do
expect { validator.call }.not_to change(BulkUploadError, :count)
end
end
context "with an invalid file" do
let(:log) { build(:sales_log, :completed, assigned_to: user, privacynotice: nil) }
before do before do
string = File.read(fixture_path) file.write(log_to_csv.default_field_numbers_row)
string.gsub!("\r\n", "\n") file.write(log_to_csv.to_csv_row)
file.write(string) file.rewind
file.rewind end
end
it "creates validation errors" do it "creates validation errors" do
expect { validator.call }.to change(BulkUploadError, :count) expect { validator.call }.to change(BulkUploadError, :count)
end
end
end end
end end
context "without headers" do context "without headers" do
let(:log) { build(:sales_log, :completed) }
let(:file) { Tempfile.new }
let(:path) { file.path }
before do before do
file.write(BulkUpload::SalesLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) file.write(log_to_csv.to_csv_row)
file.close file.close
end end
@ -271,13 +192,9 @@ RSpec.describe BulkUpload::Sales::Validator do
end end
context "when duplicate rows present" do context "when duplicate rows present" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed) }
before do before do
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2023_csv_row) file.write(log_to_csv.to_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2023_csv_row) file.write(log_to_csv.to_csv_row)
file.close file.close
end end
@ -288,83 +205,62 @@ RSpec.describe BulkUpload::Sales::Validator do
end end
describe "#create_logs?" do describe "#create_logs?" do
around do |example|
Timecop.freeze(Time.zone.local(2023, 10, 22)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
context "when all logs are valid" do context "when all logs are valid" do
let(:target_path) { file_fixture("2023_24_sales_bulk_upload.csv") } let(:log_1) { build(:sales_log, :completed, assigned_to: user) }
let(:log_2) { build(:sales_log, :completed, assigned_to: user) }
it "returns truthy" do before do
validator.call file.write(BulkUpload::SalesLogToCsv.new(log: log_1).to_csv_row)
expect(validator).to be_create_logs file.write(BulkUpload::SalesLogToCsv.new(log: log_2).to_csv_row)
end end
end
context "when there is an invalid log" do
let(:path) { file_fixture("2023_24_sales_bulk_upload_invalid.csv") }
it "returns falsey" do it "returns truthy" do
validator.call validator.call
expect(validator).not_to be_create_logs expect(validator).to be_create_logs
end end
end end
context "when a log is not valid?" do context "when a log has a clearable non-setup error" do
let(:log_1) { build(:sales_log, :completed, assigned_to: user) } let(:log_1) { build(:sales_log, :completed, assigned_to: user) }
let(:log_2) { build(:sales_log, :completed, assigned_to: user) } let(:log_2) { build(:sales_log, :completed, assigned_to: user, age1: 5) }
before do before do
file.write(BulkUpload::SalesLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) file.write(BulkUpload::SalesLogToCsv.new(log: log_1).to_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log: log_2, line_ending: "\r\n", col_offset: 0, overrides: { organisation_id: "random" }).to_2023_csv_row) file.write(BulkUpload::SalesLogToCsv.new(log: log_2).to_csv_row)
file.close
end
it "returns false" do
validator.call
expect(validator).not_to be_create_logs
end end
end
context "when all logs valid?" do
let(:path) { file_fixture("2023_24_sales_bulk_upload.csv") }
it "returns true" do it "returns truthy" do
validator.call validator.call
expect(validator).to be_create_logs expect(validator).to be_create_logs
end end
end end
context "when a single log wants to block log creation" do context "when a log has an incomplete setup section" do
let(:unaffiliated_org) { create(:organisation) } let(:log_1) { build(:sales_log, :completed, assigned_to: user) }
let(:log_2) { build(:sales_log, :completed, assigned_to: user, privacynotice: nil) }
let(:log_1) { build(:sales_log, :completed, assigned_to: user, owning_organisation: unaffiliated_org) }
before do before do
file.write(BulkUpload::SalesLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) file.write(BulkUpload::SalesLogToCsv.new(log: log_1).to_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log: log_2).to_csv_row)
file.close file.close
end end
it "will not create logs" do it "returns false" do
validator.call validator.call
expect(validator).not_to be_create_logs expect(validator).not_to be_create_logs
end end
end end
context "when a log has incomplete setup secion" do context "when a single log wants to block log creation" do
let(:log) { build(:sales_log, assigned_to: user, saledate: Time.zone.local(2022, 5, 1)) } let(:unaffiliated_org) { create(:organisation) }
let(:log) { build(:sales_log, :completed, assigned_to: user, owning_organisation: unaffiliated_org) }
before do before do
file.write(BulkUpload::SalesLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) file.write(log_to_csv.to_csv_row)
file.close file.close
end end
it "returns false" do it "will not create logs" do
validator.call validator.call
expect(validator).not_to be_create_logs expect(validator).not_to be_create_logs
end end
@ -372,28 +268,21 @@ RSpec.describe BulkUpload::Sales::Validator do
end end
describe "#total_logs_count?" do describe "#total_logs_count?" do
around do |example|
Timecop.freeze(Time.zone.local(2023, 10, 22)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
context "when all logs are valid" do context "when all logs are valid" do
let(:target_path) { file_fixture("2023_24_sales_bulk_upload.csv") } let(:log_2) { build(:sales_log, :completed, assigned_to: user) }
let(:log_3) { build(:sales_log, :completed, assigned_to: user) }
before do before do
target_array = File.open(target_path).readlines file.write(log_to_csv.to_custom_csv_row(field_values: %w[other header row]))
target_array[0..118].each do |line| file.write(log_to_csv.default_field_numbers_row)
file.write line file.write(log_to_csv.to_csv_row)
end file.write(BulkUpload::SalesLogToCsv.new(log: log_2).to_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log: log_3).to_csv_row)
file.rewind file.rewind
end end
it "returns correct total logs count" do it "returns correct total logs count" do
expect(validator.total_logs_count).to be(1) expect(validator.total_logs_count).to be(3)
end end
end end
end end

80
spec/support/bulk_upload/sales_log_to_csv.rb

@ -12,6 +12,62 @@ class BulkUpload::SalesLogToCsv
[nil] * col_offset [nil] * col_offset
end end
def to_csv_row(seed: nil)
year = log.collection_start_year
case year
when 2022
to_2022_csv_row(seed:)
when 2023
to_2023_csv_row(seed:)
when 2024
to_2024_csv_row(seed:)
else
raise NotImplementedError "No mapping function implemented for year #{year}"
end
end
def to_row
year = log.collection_start_year
case year
when 2022
to_2022_row
when 2023
to_2023_row
when 2024
to_2024_row
else
raise NotImplementedError "No mapping function implemented for year #{year}"
end
end
def default_field_numbers_row(seed: nil)
year = log.collection_start_year
case year
when 2022
default_2022_field_numbers_row(seed:)
when 2023
default_2023_field_numbers_row(seed:)
when 2024
default_2024_field_numbers_row(seed:)
else
raise NotImplementedError "No mapping function implemented for year #{year}"
end
end
def default_field_numbers
year = log.collection_start_year
case year
when 2022
default_2022_field_numbers
when 2023
default_2023_field_numbers
when 2024
default_2024_field_numbers
else
raise NotImplementedError "No mapping function implemented for year #{year}"
end
end
def to_2022_csv_row def to_2022_csv_row
(row_prefix + to_2022_row).flatten.join(",") + line_ending (row_prefix + to_2022_row).flatten.join(",") + line_ending
end end
@ -48,17 +104,17 @@ class BulkUpload::SalesLogToCsv
def default_2023_field_numbers_row(seed: nil) def default_2023_field_numbers_row(seed: nil)
if seed if seed
["Bulk upload field number"] + default_2023_field_numbers.shuffle(random: Random.new(seed)) ["Field number"] + default_2023_field_numbers.shuffle(random: Random.new(seed))
else else
["Bulk upload field number"] + default_2023_field_numbers ["Field number"] + default_2023_field_numbers
end.flatten.join(",") + line_ending end.flatten.join(",") + line_ending
end end
def default_2024_field_numbers_row(seed: nil) def default_2024_field_numbers_row(seed: nil)
if seed if seed
["Bulk upload field number"] + default_2024_field_numbers.shuffle(random: Random.new(seed)) ["Field number"] + default_2024_field_numbers.shuffle(random: Random.new(seed))
else else
["Bulk upload field number"] + default_2024_field_numbers ["Field number"] + default_2024_field_numbers
end.flatten.join(",") + line_ending end.flatten.join(",") + line_ending
end end
@ -239,10 +295,10 @@ class BulkUpload::SalesLogToCsv
log.saledate&.strftime("%y"), log.saledate&.strftime("%y"),
log.purchid, log.purchid,
log.ownershipsch, log.ownershipsch,
log.type, # field_9: "What is the type of shared ownership sale?", log.ownershipsch == 1 ? log.type : "", # field_9: "What is the type of shared ownership sale?",
log.type, # field_10: "What is the type of discounted ownership sale?", log.ownershipsch == 2 ? log.type : "", # field_10: "What is the type of discounted ownership sale?",
log.type, # field_11: "What is the type of outright sale?", log.ownershipsch == 3 ? log.type : "", # field_11: "What is the type of outright sale?",
log.othtype, log.othtype,
log.companybuy, log.companybuy,
log.buylivein, log.buylivein,
@ -267,7 +323,7 @@ class BulkUpload::SalesLogToCsv
log.age1, log.age1,
log.sex1, log.sex1,
log.ethnic, log.ethnic,
log.national, log.nationality_all_group,
log.ecstat1, log.ecstat1,
log.buy1livein, log.buy1livein,
log.relat2, log.relat2,
@ -275,7 +331,7 @@ class BulkUpload::SalesLogToCsv
log.sex2, log.sex2,
log.ethnic_group2, # 40 log.ethnic_group2, # 40
log.nationalbuy2, log.nationality_all_buyer2_group,
log.ecstat2, log.ecstat2,
log.buy2livein, log.buy2livein,
log.hholdcount, log.hholdcount,
@ -309,7 +365,7 @@ class BulkUpload::SalesLogToCsv
log.buy2living, # 70 log.buy2living, # 70
log.prevtenbuy2, log.prevtenbuy2,
hhregres, log.hhregres,
log.hhregresstill, log.hhregresstill,
log.armedforcesspouse, log.armedforcesspouse,
log.disabled, log.disabled,
@ -320,7 +376,7 @@ class BulkUpload::SalesLogToCsv
log.inc2mort, # 80 log.inc2mort, # 80
log.hb, log.hb,
log.savings, log.savings.present? ? log.savings : "R",
log.prevown, log.prevown,
log.prevshared, log.prevshared,
log.proplen, log.proplen,
@ -357,7 +413,7 @@ class BulkUpload::SalesLogToCsv
log.proplen, log.proplen,
log.value, log.value,
log.grant, log.grant,
log.discount, log.discount || 0,
log.mortgageused, log.mortgageused,
log.mortgage, log.mortgage,
log.mortgagelender, log.mortgagelender,

Loading…
Cancel
Save