diff --git a/spec/factories/bulk_upload.rb b/spec/factories/bulk_upload.rb index 6ac1a0c91..1e58a0422 100644 --- a/spec/factories/bulk_upload.rb +++ b/spec/factories/bulk_upload.rb @@ -4,7 +4,7 @@ FactoryBot.define do factory :bulk_upload do user log_type { BulkUpload.log_types.values.sample } - year { 2023 } + year { 2024 } identifier { SecureRandom.uuid } sequence(:filename) { |n| "bulk-upload-#{n}.csv" } needstype { 1 } diff --git a/spec/services/bulk_upload/lettings/validator_spec.rb b/spec/services/bulk_upload/lettings/validator_spec.rb index 2a70260e4..57c2a3dbd 100644 --- a/spec/services/bulk_upload/lettings/validator_spec.rb +++ b/spec/services/bulk_upload/lettings/validator_spec.rb @@ -3,186 +3,112 @@ require "rails_helper" RSpec.describe BulkUpload::Lettings::Validator do subject(:validator) { described_class.new(bulk_upload:, path:) } - let(:organisation) { create(:organisation, old_visible_id: "3") } + let(:organisation) { create(:organisation, old_visible_id: "3", rent_periods: [2]) } let(:user) { create(:user, organisation:) } - let(:log) { build(:lettings_log, :completed, startdate: Time.zone.local(2024, 3, 3)) } - let(:bulk_upload) { create(:bulk_upload, user:) } + let(:log) { build(:lettings_log, :completed, renttype: 1, period: 2, assigned_to: user, owning_organisation: organisation, managing_organisation: organisation) } + let(:bulk_upload) { create(:bulk_upload, user:, year: 2024) } let(:path) { file.path } let(:file) { Tempfile.new } describe "validations" do - context "when 2023" do - let(:bulk_upload) { create(:bulk_upload, user:, year: 2023) } - - context "when file has no headers" do - context "and too many columns" do - before do - file.write(("a" * 143).chars.join(",")) - file.write("\n") - file.rewind - end - - it "is not valid" do - expect(validator).not_to be_valid - expect(validator.errors["base"]).to eql(["Too many columns, please ensure you have used the correct template"]) - end - end - - context "and is empty" do - it "is not valid" do - expect(validator).not_to be_valid - expect(validator.errors["base"]).to eql(["Template is blank - The template must be filled in for us to create the logs and check if data is correct."]) - end - end - - context "and doesn't have too many columns" do - before do - file.write(("a" * 142).chars.join(",")) - file.write("\n") - file.rewind - end - - it "is valid" do - expect(validator).to be_valid - end + context "when file has headers" do + context "and is empty" do + it "is not valid" do + expect(validator).not_to be_valid + expect(validator.errors["base"]).to eql(["Template is blank - The template must be filled in for us to create the logs and check if data is correct."]) end end - context "when file has headers" do - context "and is empty" do - it "is not valid" do - expect(validator).not_to be_valid - expect(validator.errors["base"]).to eql(["Template is blank - The template must be filled in for us to create the logs and check if data is correct."]) - end - end + context "and file has extra invalid headers" do + let(:seed) { rand } + let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) } + let(:field_numbers) { log_to_csv.default_2024_field_numbers + %w[invalid_field_number] } + let(:field_values) { log_to_csv.to_2024_row + %w[value_for_invalid_field_number] } - context "and file has extra invalid headers" do - let(:seed) { rand } - let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) } - let(:field_numbers) { log_to_csv.default_2023_field_numbers + %w[invalid_field_number] } - let(:field_values) { log_to_csv.to_2023_row + %w[value_for_invalid_field_number] } - - 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 valid" do - expect(validator).to be_valid - end + 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 - context "and file has too few valid headers" do - let(:seed) { rand } - let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) } - let(:field_numbers) { log_to_csv.default_2023_field_numbers } - let(:field_values) { log_to_csv.to_2023_row } - - before do - field_numbers.delete_at(20) - field_values.delete_at(20) - 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 - expect(validator.errors["base"]).to eql(["Incorrect number of fields, please ensure you have used the correct template"]) - end + it "is valid" do + expect(validator).to be_valid end + end - context "and file has too many valid headers" do - let(:seed) { rand } - let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) } - let(:field_numbers) { log_to_csv.default_2023_field_numbers + %w[23] } - let(:field_values) { log_to_csv.to_2023_row + %w[value] } - - 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 + context "and file has too few valid headers" do + let(:seed) { rand } + let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) } + let(:field_numbers) { log_to_csv.default_2024_field_numbers } + let(:field_values) { log_to_csv.to_2024_row } + + before do + field_numbers.delete_at(20) + field_values.delete_at(20) + 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 - expect(validator.errors["base"]).to eql(["Incorrect number of fields, please ensure you have used the correct template"]) - end + it "is not valid" do + expect(validator).not_to be_valid + expect(validator.errors["base"]).to eql(["Incorrect number of fields, please ensure you have used the correct template"]) end end - context "when uploading a 2022 logs for 2023 bulk upload" do - let(:bulk_upload) { create(:bulk_upload, user:, year: 2023) } - let(:log) { build(:lettings_log, :completed, startdate: Time.zone.local(2022, 5, 6), tenancycode: "5") } + context "and file has too many valid headers" do + let(:seed) { rand } + let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) } + let(:field_numbers) { log_to_csv.default_2024_field_numbers + %w[23] } + let(:field_values) { log_to_csv.to_2024_row + %w[value] } - context "with no headers" do - before do - file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) - file.close - end - - it "is not valid" do - expect(validator).not_to be_valid - end + 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 - context "with headers" do - let(:seed) { rand } - let(:log_to_csv) { BulkUpload::LettingsLogToCsv.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 + it "is not valid" do + expect(validator).not_to be_valid + expect(validator.errors["base"]).to eql(["Incorrect number of fields, please ensure you have used the correct template"]) end end + end - context "when uploading a 2023 logs for 2024 bulk upload" do - let(:bulk_upload) { create(:bulk_upload, user:, year: 2024) } - let(:log) { build(:lettings_log, :completed, startdate: Time.zone.local(2023, 5, 6), tenancycode: "5234234234234") } + context "when uploading a 2023 logs for 2024 bulk upload" do + let(:log) { build(:lettings_log, :completed, startdate: Time.zone.local(2023, 5, 6), tenancycode: "5234234234234") } - context "with no headers" do - before do - file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2024_csv_row) - file.close - end + context "with headers" do + let(:seed) { rand } + let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) } + let(:field_numbers) { log_to_csv.default_2024_field_numbers } + let(:field_values) { log_to_csv.to_2024_row } - it "is not valid" do - expect(validator).not_to be_valid - end + 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 - context "with headers" do - let(:seed) { rand } - let(:log_to_csv) { BulkUpload::LettingsLogToCsv.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 + it "is not valid" do + expect(validator).not_to be_valid + expect(validator.errors["base"]).to eql(["Incorrect start dates, please ensure you have used the correct template"]) end end end end describe "#call" do - context "when a valid csv" do - let(:path) { file_fixture("2023_24_lettings_bulk_upload_invalid.csv") } + context "with an invalid 2024 csv" do + let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) } + + before do + values = log_to_csv.to_2024_row + values[7] = nil + file.write(log_to_csv.default_2024_field_numbers_row) + file.write(log_to_csv.to_custom_csv_row(seed: nil, field_values: values)) + file.rewind + end it "creates validation errors" do expect { validator.call }.to change(BulkUploadError, :count) @@ -191,36 +117,41 @@ RSpec.describe BulkUpload::Lettings::Validator do it "create validation error with correct values" do validator.call - error = BulkUploadError.find_by(row: "9", field: "field_7", category: "setup") + error = BulkUploadError.find_by(row: "2", field: "field_8", category: "setup") - expect(error.field).to eql("field_7") + expect(error.field).to eql("field_8") expect(error.error).to eql("You must answer tenancy start date (day)") - expect(error.tenant_code).to eql("123") - expect(error.property_ref).to be_nil - expect(error.row).to eql("9") - expect(error.cell).to eql("H9") - expect(error.col).to eql("H") + expect(error.tenant_code).to eql(log.tenancycode) + expect(error.property_ref).to eql(log.propcode) + expect(error.row).to eql("2") + expect(error.cell).to eql("I2") + expect(error.col).to eql("I") end end - context "with arbitrary ordered 23/24 csv" do - let(:bulk_upload) { create(:bulk_upload, user:, year: 2023) } - let(:log) { build(:lettings_log, :completed) } - let(:file) { Tempfile.new } - let(:path) { file.path } - let(:seed) { 321 } + context "with a valid 2024 csv" do + let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) } - around do |example| - FormHandler.instance.use_real_forms! - - example.run + before do + file.write(log_to_csv.default_2024_field_numbers_row) + file.write(log_to_csv.to_2024_csv_row) + file.rewind + end - FormHandler.instance.use_fake_forms! + it "does not create validation errors" do + expect { validator.call }.not_to change(BulkUploadError, :count) end + end + + context "with arbitrary ordered invalid csv" do + let(:seed) { 321 } + let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) } before do - file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n").default_2023_field_numbers_row(seed:)) - file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n").to_2023_csv_row(seed:)) + values = log_to_csv.to_2024_row + values[3] = nil + file.write(log_to_csv.default_2024_field_numbers_row(seed:)) + file.write(log_to_csv.to_custom_csv_row(seed:, field_values: values)) file.close end @@ -231,15 +162,15 @@ RSpec.describe BulkUpload::Lettings::Validator do it "create validation error with correct values" do validator.call - error = BulkUploadError.find_by(field: "field_5") + error = BulkUploadError.find_by(field: "field_4") - expect(error.field).to eql("field_5") - expect(error.error).to eql("You must answer letting type") + expect(error.field).to eql("field_4") + expect(error.error).to eql("You must answer needs type") expect(error.tenant_code).to eql(log.tenancycode) expect(error.property_ref).to eql(log.propcode) expect(error.row).to eql("2") - expect(error.cell).to eql("DD2") - expect(error.col).to eql("DD") + expect(error.cell).to eql("CY2") + expect(error.col).to eql("CY") end end @@ -249,31 +180,50 @@ RSpec.describe BulkUpload::Lettings::Validator do let(:log) { build(:lettings_log, :completed) } before do - file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n").default_2023_field_numbers_row) - file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n").to_2023_csv_row) - file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n").to_2023_csv_row) + file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n").default_2024_field_numbers_row) + file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n").to_2024_csv_row) + file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n").to_2024_csv_row) file.close end it "creates errors" do - expect { validator.call }.to change(BulkUploadError.where(category: :setup, error: "This is a duplicate of a log in your file"), :count).by(22) + expect { validator.call }.to change(BulkUploadError.where(category: :setup, error: "This is a duplicate of a log in your file"), :count) end end - context "with unix line endings" do - let(:fixture_path) { file_fixture("2023_24_lettings_bulk_upload.csv") } - let(:file) { Tempfile.new } - let(:path) { file.path } + [ + { line_ending: "\n", name: "unix" }, + { line_ending: "\r\n", name: "windows" }, + ].each do |test_case| + context "with #{test_case[:name]} line endings" do + context "with a valid file" do + let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:, line_ending: test_case[:line_ending]) } - before do - string = File.read(fixture_path) - string.gsub!("\r\n", "\n") - file.write(string) - file.rewind - end + before do + file.write(log_to_csv.default_2024_field_numbers_row) + file.write(log_to_csv.to_2024_csv_row) + file.rewind + end - it "creates validation errors" do - expect { validator.call }.to change(BulkUploadError, :count) + 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(:lettings_log, :completed, assigned_to: user, owning_organisation: organisation, managing_organisation: organisation, declaration: nil) } + let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:, line_ending: test_case[:line_ending]) } + + before do + file.write(log_to_csv.default_2024_field_numbers_row) + file.write(log_to_csv.to_2024_csv_row) + file.rewind + end + + it "creates validation errors" do + expect { validator.call }.to change(BulkUploadError, :count) + end + end end end @@ -283,7 +233,7 @@ RSpec.describe BulkUpload::Lettings::Validator do let(:path) { file.path } before do - file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) + file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2024_csv_row) file.close end @@ -294,31 +244,13 @@ RSpec.describe BulkUpload::Lettings::Validator do end describe "#create_logs?" do - context "when all logs are valid" do - let(:target_path) { file_fixture("2023_24_lettings_bulk_upload.csv") } - - it "returns truthy" do - validator.call - expect(validator).to be_create_logs - end - end - - context "when there is an invalid log" do - let(:path) { file_fixture("2023_24_lettings_bulk_upload_invalid.csv") } - - it "returns falsey" do - validator.call - expect(validator).not_to be_create_logs - end - end - context "when a log is not valid?" do let(:log_1) { build(:lettings_log, :completed, assigned_to: user) } let(:log_2) { build(:lettings_log, :completed, assigned_to: user) } before do - file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) - file.write(BulkUpload::LettingsLogToCsv.new(log: log_2, line_ending: "\r\n", col_offset: 0, overrides: { illness: 100 }).to_2023_csv_row) + file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2024_csv_row) + file.write(BulkUpload::LettingsLogToCsv.new(log: log_2, line_ending: "\r\n", col_offset: 0, overrides: { illness: 100 }).to_2024_csv_row) file.close end @@ -333,8 +265,8 @@ RSpec.describe BulkUpload::Lettings::Validator do let(:log_2) { build(:lettings_log, :completed, renttype: 1, assigned_to: user) } before do - file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) - file.write(BulkUpload::LettingsLogToCsv.new(log: log_2, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) + file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2024_csv_row) + file.write(BulkUpload::LettingsLogToCsv.new(log: log_2, line_ending: "\r\n", col_offset: 0).to_2024_csv_row) file.close end @@ -350,7 +282,7 @@ RSpec.describe BulkUpload::Lettings::Validator do let(:log_1) { build(:lettings_log, :completed, renttype: 1, assigned_to: user, owning_organisation: unaffiliated_org) } before do - file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) + file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2024_csv_row) file.close end @@ -361,10 +293,10 @@ RSpec.describe BulkUpload::Lettings::Validator do end context "when a log has incomplete setup section" do - let(:log) { build(:lettings_log, :in_progress, assigned_to: user, startdate: Time.zone.local(2022, 5, 1)) } + let(:log) { build(:lettings_log, :completed, renttype: 1, declaration: nil, assigned_to: user) } before do - file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) + file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2024_csv_row) file.close end diff --git a/spec/support/bulk_upload/lettings_log_to_csv.rb b/spec/support/bulk_upload/lettings_log_to_csv.rb index 0b6b6348e..3af5731ce 100644 --- a/spec/support/bulk_upload/lettings_log_to_csv.rb +++ b/spec/support/bulk_upload/lettings_log_to_csv.rb @@ -93,14 +93,14 @@ class BulkUpload::LettingsLogToCsv log.managing_organisation&.old_visible_id, log.assigned_to&.email, log.needstype, - "S#{log.scheme&.id}", + log.scheme&.id ? "S#{log.scheme&.id}" : "", log.location&.id, renewal, log.startdate&.day, log.startdate&.month, log.startdate&.strftime("%y"), # 10 - london_affordable_rent, + rent_type, log.irproduct_other, log.tenancycode, log.propcode, @@ -137,7 +137,7 @@ class BulkUpload::LettingsLogToCsv log.age1 || overrides[:age1], log.sex1, log.ethnic, - log.national, + log.nationality_all_group, log.ecstat1, log.relat2, log.age2 || overrides[:age2], @@ -214,11 +214,11 @@ class BulkUpload::LettingsLogToCsv cbl, chr, cap, - nil, # accessible register + accessible_register, log.referral, net_income_known, - log.earnings, log.incfreq, + log.earnings, log.hb, # 120 log.benefits, @@ -392,9 +392,7 @@ class BulkUpload::LettingsLogToCsv end def to_custom_csv_row(seed: nil, field_values: nil) - if seed - row = field_values.shuffle(random: Random.new(seed)) - end + row = seed ? field_values.shuffle(random: Random.new(seed)) : field_values (row_prefix + row).flatten.join(",") + line_ending end @@ -422,6 +420,23 @@ private end end + def rent_type + case log.renttype + when LettingsLog::RENT_TYPE[:social_rent] + 1 + when LettingsLog::RENT_TYPE[:affordable_rent] + 2 + when LettingsLog::RENT_TYPE[:london_affordable_rent] + 3 + when LettingsLog::RENT_TYPE[:rent_to_buy] + 4 + when LettingsLog::RENT_TYPE[:london_living_rent] + 5 + when LettingsLog::RENT_TYPE[:other_intermediate_rent_product] + 6 + end + end + def leftreg case log.leftreg when 3 @@ -471,6 +486,10 @@ private checkbox_value(log.cap) end + def accessible_register + checkbox_value(log.accessible_register) + end + def checkbox_value(field) case field when 0