From 636e40fc9d714dd88ecf9a0af734aa5ef9d75785 Mon Sep 17 00:00:00 2001 From: Rachael Booth Date: Thu, 18 Jul 2024 15:56:52 +0100 Subject: [PATCH] CLDC-3505: Fix tests for hard year end part 4 (#2509) * Add in past end dates for testing * Temporarily disable test marked to delete at year end * Remove one off reinfer_local_authority task * Update validator_spec * Set 2024 date in form_handler_spec to be during crossover period as needed * Use bulk_upload.year_combo for comparison in request tests to avoid year dependancy * Update BU log creator specs for 2024 * Use year combo function in bulk upload mailer tests * Refactor lettings validator_spec * More fixes * More work on bu validator specs - mostly sales * Remove pre 2023 test * More use of bulk_upload.year_combo in request tests * Fix lint * Tweak bulk upload error row component tests for year changes * Further fixes * Fix 2023 lettings row parser spec * Sales log to csv fix * Refactor BU processor tests * Fix field number row identifier * Fix linting * More years in request spec * fix * Don't use db unnecessarily in financial validations spec * Fix sale date changing 2024 -> 2023 test * Add tests for bulk_upload.year_combo * Update bu factory year specification * Refactoring * Linting * Don't use helper in factory * Remove new 2023 specific test * Remove dummy end dates --- lib/tasks/reinfer_local_authority.rake | 14 - .../bulk_upload_error_row_component_spec.rb | 39 +- spec/factories/bulk_upload.rb | 2 +- spec/factories/sales_log.rb | 3 +- .../lib/tasks/reinfer_local_authority_spec.rb | 88 ---- spec/mailers/bulk_upload_mailer_spec.rb | 4 +- spec/models/bulk_upload_spec.rb | 15 + spec/models/form_handler_spec.rb | 4 +- spec/models/lettings_log_spec.rb | 12 - spec/models/sales_log_spec.rb | 31 -- .../sales/financial_validations_spec.rb | 24 +- ...upload_lettings_results_controller_spec.rb | 4 +- ..._upload_lettings_resume_controller_spec.rb | 6 +- ..._soft_validations_check_controller_spec.rb | 2 +- ...lk_upload_sales_results_controller_spec.rb | 2 +- ...ulk_upload_sales_resume_controller_spec.rb | 6 +- ..._soft_validations_check_controller_spec.rb | 2 +- spec/requests/form_controller_spec.rb | 6 +- .../bulk_upload/lettings/log_creator_spec.rb | 36 +- .../bulk_upload/lettings/validator_spec.rb | 383 +++++++----------- .../lettings/year2023/row_parser_spec.rb | 37 +- spec/services/bulk_upload/processor_spec.rb | 293 ++------------ .../bulk_upload/sales/log_creator_spec.rb | 34 +- .../bulk_upload/sales/validator_spec.rb | 360 ++++++---------- .../csv/sales_log_csv_service_spec.rb | 2 + .../bulk_upload/lettings_log_to_csv.rb | 94 ++++- spec/support/bulk_upload/sales_log_to_csv.rb | 92 ++++- 27 files changed, 560 insertions(+), 1035 deletions(-) delete mode 100644 lib/tasks/reinfer_local_authority.rake delete mode 100644 spec/lib/tasks/reinfer_local_authority_spec.rb diff --git a/lib/tasks/reinfer_local_authority.rake b/lib/tasks/reinfer_local_authority.rake deleted file mode 100644 index a17d7eed6..000000000 --- a/lib/tasks/reinfer_local_authority.rake +++ /dev/null @@ -1,14 +0,0 @@ -desc "Reinfers LA from postcode where it's missing" -task reinfer_local_authority: :environment do - LettingsLog.filter_by_year(2023).where(needstype: 1, la: nil).where.not(postcode_full: nil).find_each do |log| - log.process_postcode_changes! - - Rails.logger.info "Invalid lettings log: #{log.id}" unless log.save - end - - SalesLog.filter_by_year(2023).where(la: nil).where.not(postcode_full: nil).find_each do |log| - log.process_postcode_changes! - - Rails.logger.info "Invalid sales log: #{log.id}" unless log.save - end -end diff --git a/spec/components/bulk_upload_error_row_component_spec.rb b/spec/components/bulk_upload_error_row_component_spec.rb index eb47fa99d..01af041cb 100644 --- a/spec/components/bulk_upload_error_row_component_spec.rb +++ b/spec/components/bulk_upload_error_row_component_spec.rb @@ -6,7 +6,7 @@ RSpec.describe BulkUploadErrorRowComponent, type: :component do let(:tenant_code) { SecureRandom.hex(4) } let(:property_ref) { SecureRandom.hex(4) } let(:purchaser_code) { nil } - let(:field) { :field_134 } + let(:field) { :field_130 } let(:error) { "some error" } let(:bulk_upload) { create(:bulk_upload, :lettings) } let(:bulk_upload_errors) do @@ -45,10 +45,28 @@ RSpec.describe BulkUploadErrorRowComponent, type: :component do expect(result).to have_content(expected) end - it "renders the question for lettings" do - expected = "What do you expect the outstanding amount to be?" - result = render_inline(described_class.new(bulk_upload_errors:)) - expect(result).to have_content(expected) + context "when the bulk upload is for 2024" do + context "with a lettings bulk upload" do + let(:bulk_upload) { build(:bulk_upload, :lettings, year: 2024) } + let(:field) { :field_130 } + + it "renders the expected question" do + expected = "What do you expect the outstanding amount to be?" + result = render_inline(described_class.new(bulk_upload_errors:)) + expect(result).to have_content(expected) + end + end + + context "with a sales bulk upload" do + let(:bulk_upload) { create(:bulk_upload, :sales, year: 2024) } + let(:field) { :field_86 } + + it "renders the expected question" do + expected = "Is this a staircasing transaction?" + result = render_inline(described_class.new(bulk_upload_errors:)) + expect(result).to have_content(expected) + end + end end context "when tenant_code not present" do @@ -78,17 +96,6 @@ RSpec.describe BulkUploadErrorRowComponent, type: :component do end end - context "when a sales bulk upload" do - let(:bulk_upload) { create(:bulk_upload, :sales) } - let(:field) { :field_87 } - - it "renders the question for sales" do - expected = "Is this a staircasing transaction?" - result = render_inline(described_class.new(bulk_upload_errors:)) - expect(result).to have_content(expected) - end - end - it "renders the error" do expected = error result = render_inline(described_class.new(bulk_upload_errors:)) diff --git a/spec/factories/bulk_upload.rb b/spec/factories/bulk_upload.rb index 6ac1a0c91..f7d81ab7a 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 { Time.zone.now.month >= 4 ? Time.zone.now.year : Time.zone.now.year - 1 } identifier { SecureRandom.uuid } sequence(:filename) { |n| "bulk-upload-#{n}.csv" } needstype { 1 } diff --git a/spec/factories/sales_log.rb b/spec/factories/sales_log.rb index 13e401323..b809b9daf 100644 --- a/spec/factories/sales_log.rb +++ b/spec/factories/sales_log.rb @@ -128,8 +128,7 @@ FactoryBot.define do pregla { 1 } pregother { 1 } pregghb { 1 } - hhregres { 1 } - hhregresstill { 4 } + hhregres { 7 } ppcodenk { 1 } prevten { 1 } previous_la_known { 0 } diff --git a/spec/lib/tasks/reinfer_local_authority_spec.rb b/spec/lib/tasks/reinfer_local_authority_spec.rb deleted file mode 100644 index c92d227dc..000000000 --- a/spec/lib/tasks/reinfer_local_authority_spec.rb +++ /dev/null @@ -1,88 +0,0 @@ -require "rails_helper" -require "rake" - -RSpec.describe "reinfer_local_authority" do - describe ":reinfer_local_authority", type: :task do - subject(:task) { Rake::Task["reinfer_local_authority"] } - - before do - Rake.application.rake_require("tasks/reinfer_local_authority") - Rake::Task.define_task(:environment) - task.reenable - end - - context "when the rake task is run" do - context "and there is a general needs type lettings log with postcode and without LA" do - let(:log) { create(:lettings_log, :completed, postcode_full: "AA1 1AA", status: "completed", startdate: Time.zone.local(2023, 4, 1)) } - - it "updates the la if it can be inferred" do - log.la = nil - log.save!(validate: false) - task.invoke - - log.reload - expect(log.la).to eq("E09000033") - expect(log.status).to eq("completed") - end - - it "does not update the la if it cannot be inferred and sets status to in_progress" do - log.la = nil - log.postcode_full = "B11AB" - log.save!(validate: false) - task.invoke - - log.reload - expect(log.la).to be_nil - expect(log.status).to eq("in_progress") - end - end - - context "and the lettings log has a validation error" do - let(:log) { build(:lettings_log, :completed, postcode_full: "some fake postcode", la: nil, status: "completed", startdate: Time.zone.local(2023, 4, 1)) } - - it "logs invalid log ID" do - log.save!(validate: false) - expect(Rails.logger).to receive(:info).with("Invalid lettings log: #{log.id}") - - task.invoke - end - end - - context "and there is a sales log with postcode and without LA" do - let(:log) { create(:sales_log, :completed, postcode_full: "AA1 1AA", status: "completed", saledate: Time.zone.local(2023, 4, 1)) } - - it "updates the la if it can be inferred" do - log.la = nil - log.save!(validate: false) - task.invoke - - log.reload - expect(log.la).to eq("E09000033") - expect(log.status).to eq("completed") - end - - it "does not update the la if it cannot be inferred and sets status to in_progress" do - log.la = nil - log.postcode_full = "B11AB" - log.save!(validate: false) - task.invoke - - log.reload - expect(log.la).to be_nil - expect(log.status).to eq("in_progress") - end - end - - context "and the sales log has a validation error" do - let(:log) { build(:sales_log, :completed, postcode_full: "some fake postcode", la: nil, status: "completed", saledate: Time.zone.local(2023, 4, 1)) } - - it "logs invalid log ID" do - log.save!(validate: false) - expect(Rails.logger).to receive(:info).with("Invalid sales log: #{log.id}") - - task.invoke - end - end - end - end -end diff --git a/spec/mailers/bulk_upload_mailer_spec.rb b/spec/mailers/bulk_upload_mailer_spec.rb index f26da1efb..c3225c937 100644 --- a/spec/mailers/bulk_upload_mailer_spec.rb +++ b/spec/mailers/bulk_upload_mailer_spec.rb @@ -46,7 +46,7 @@ RSpec.describe BulkUploadMailer do filename: bulk_upload.filename, log_type: "lettings", upload_timestamp: bulk_upload.created_at.to_fs(:govuk_date_and_time), - success_description: "The lettings 2023/24 data you uploaded has been checked. The 0 logs you uploaded are now complete.", + success_description: "The lettings #{bulk_upload.year_combo} data you uploaded has been checked. The 0 logs you uploaded are now complete.", logs_link: clear_filters_url(filter_type: "lettings_logs"), }, ) @@ -113,7 +113,7 @@ RSpec.describe BulkUploadMailer do title: "Check your file data", filename: bulk_upload.filename, upload_timestamp: bulk_upload.created_at.to_fs(:govuk_date_and_time), - description: "Some of your 2023/24 lettings data might not be right. Click the link below to review the potential errors, and check your file to see if the data is correct.", + description: "Some of your #{bulk_upload.year_combo} lettings data might not be right. Click the link below to review the potential errors, and check your file to see if the data is correct.", cta_link: bulk_upload_lettings_soft_validations_check_url(bulk_upload, page: "confirm-soft-errors"), }, ) diff --git a/spec/models/bulk_upload_spec.rb b/spec/models/bulk_upload_spec.rb index b99b945fa..e38ea0402 100644 --- a/spec/models/bulk_upload_spec.rb +++ b/spec/models/bulk_upload_spec.rb @@ -36,4 +36,19 @@ RSpec.describe BulkUpload, type: :model do end end end + + describe "year_combo" do + [ + { year: 2023, expected_value: "2023/24" }, + { year: 2024, expected_value: "2024/25" }, + ].each do |test_case| + context "when the bulk upload year is #{test_case[:year]}" do + let(:bulk_upload) { build(:bulk_upload, year: test_case[:year]) } + + it "returns the expected year combination string" do + expect(bulk_upload.year_combo).to eql(test_case[:expected_value]) + end + end + end + end end diff --git a/spec/models/form_handler_spec.rb b/spec/models/form_handler_spec.rb index 3747cf92d..bfa164ee5 100644 --- a/spec/models/form_handler_spec.rb +++ b/spec/models/form_handler_spec.rb @@ -246,8 +246,8 @@ RSpec.describe FormHandler do end end - context "when only archived form form is defined in JSON (current collection start year 2024 onwards)" do # TODO: CLDC-3505 remove this test on year hard end - let(:now) { Time.utc(2024, 9, 20) } + context "when only archived form is defined in JSON (current collection start year 2024 onwards)" do + let(:now) { Time.utc(2024, 5, 20) } it "creates previous_lettings, current_lettings and next_lettings forms from ruby form objects and archived form from json" do expect(form_handler.lettings_forms["archived_lettings"]).to be_present diff --git a/spec/models/lettings_log_spec.rb b/spec/models/lettings_log_spec.rb index 5c40fbe08..2001c0bfa 100644 --- a/spec/models/lettings_log_spec.rb +++ b/spec/models/lettings_log_spec.rb @@ -512,18 +512,6 @@ RSpec.describe LettingsLog do create_list(:location, 2, scheme: new_scheme) end - context "with a 2023 log" do - let(:log) { create(:lettings_log, :completed, :sh, :ignore_validation_errors, startdate: Time.zone.local(2024, 1, 1), owning_organisation:, scheme_id: old_scheme.id, location_id: old_location.id) } - - it "clears the location set on the log" do - expect { log.update!(scheme: new_scheme) }.to change(log, :location_id).from(old_location.id).to(nil) - end - - it "recalculates the log status" do - expect { log.update!(scheme: new_scheme) }.to change(log, :status).from("completed").to("in_progress") - end - end - context "with a current year log" do let(:log) { create(:lettings_log, :completed, :sh, :startdate_today, owning_organisation:, scheme_id: old_scheme.id, location_id: old_location.id) } diff --git a/spec/models/sales_log_spec.rb b/spec/models/sales_log_spec.rb index cb52d85b2..989a8e334 100644 --- a/spec/models/sales_log_spec.rb +++ b/spec/models/sales_log_spec.rb @@ -564,37 +564,6 @@ RSpec.describe SalesLog, type: :model do expect(record_from_db["la"]).to eq("E08000003") end - context "with 23/24 logs" do - let(:address_sales_log_23_24) do - described_class.create({ - owning_organisation:, - assigned_to: assigned_to_user, - ppcodenk: 1, - postcode_full: "CA10 1AA", - saledate: Time.zone.local(2023, 5, 2), - }) - end - - before do - WebMock.stub_request(:get, /api\.postcodes\.io\/postcodes\/CA101AA/) - .to_return(status: 200, body: '{"status":200,"result":{"admin_district":"Eden","codes":{"admin_district":"E07000030"}}}', headers: {}) - end - - it "correctly infers new la" do - record_from_db = described_class.find(address_sales_log_23_24.id) - expect(address_sales_log_23_24.la).to eq("E06000064") - expect(record_from_db["la"]).to eq("E06000064") - end - - it "does not set previous postcode or previous la for discounted sale" do - address_sales_log_23_24.update!(ownershipsch: 2, ppostcode_full: nil, prevloc: nil) - record_from_db = described_class.find(address_sales_log_23_24.id) - expect(address_sales_log_23_24.ppostcode_full).to eq(nil) - expect(record_from_db["ppostcode_full"]).to eq(nil) - expect(record_from_db["prevloc"]).to eq(nil) - end - end - context "with 24/25 logs" do let(:address_sales_log_24_25) do described_class.create({ diff --git a/spec/models/validations/sales/financial_validations_spec.rb b/spec/models/validations/sales/financial_validations_spec.rb index 6ae34c3df..dd71d0b24 100644 --- a/spec/models/validations/sales/financial_validations_spec.rb +++ b/spec/models/validations/sales/financial_validations_spec.rb @@ -10,8 +10,7 @@ RSpec.describe Validations::Sales::FinancialValidations do context "when buying in a non london borough" do before do - record.update!(la: "E08000035") - record.reload + record.la = "E08000035" end it "adds errors if buyer 1 has income over 80,000" do @@ -80,8 +79,7 @@ RSpec.describe Validations::Sales::FinancialValidations do context "when buying in a london borough" do before do - record.update!(la: "E09000030") - record.reload + record.la = "E09000030" end it "adds errors if buyer 1 has income over 90,000" do @@ -311,12 +309,10 @@ RSpec.describe Validations::Sales::FinancialValidations do context "when buyer 2 is not a child" do before do - record.update!(ecstat2: rand(0..8)) - record.reload + record.ecstat2 = rand(0..8) end it "does not add an error if buyer 2 has an income" do - record.ecstat2 = rand(0..8) record.income2 = 40_000 financial_validator.validate_child_income(record) expect(record.errors).to be_empty @@ -324,30 +320,20 @@ RSpec.describe Validations::Sales::FinancialValidations do end context "when buyer 2 is a child" do + let(:record) { build(:sales_log, :saledate_today, ecstat2: 9) } + it "does not add an error if buyer 2 has no income" do - record.saledate = Time.zone.local(2023, 4, 3) - record.ecstat2 = 9 record.income2 = 0 financial_validator.validate_child_income(record) expect(record.errors).to be_empty end it "adds errors if buyer 2 has an income" do - record.saledate = Time.zone.local(2023, 4, 3) - record.ecstat2 = 9 record.income2 = 40_000 financial_validator.validate_child_income(record) expect(record.errors["ecstat2"]).to include(match I18n.t("validations.financial.income.child_has_income")) expect(record.errors["income2"]).to include(match I18n.t("validations.financial.income.child_has_income")) end - - it "does not add an error if the saledate is before the 23/24 collection window" do - record.saledate = Time.zone.local(2022, 4, 3) - record.ecstat2 = 9 - record.income2 = 40_000 - financial_validator.validate_child_income(record) - expect(record.errors).to be_empty - end end end diff --git a/spec/requests/bulk_upload_lettings_results_controller_spec.rb b/spec/requests/bulk_upload_lettings_results_controller_spec.rb index 70a6c1f0a..50f5ecd31 100644 --- a/spec/requests/bulk_upload_lettings_results_controller_spec.rb +++ b/spec/requests/bulk_upload_lettings_results_controller_spec.rb @@ -16,7 +16,7 @@ RSpec.describe BulkUploadLettingsResultsController, type: :request do get "/lettings-logs/bulk-upload-results/#{bulk_upload.id}/summary" expect(response).to be_successful - expect(response.body).to include("Bulk upload for lettings (2023/24)") + expect(response.body).to include("Bulk upload for lettings (#{bulk_upload.year_combo})") end it "renders the bulk upload filename" do @@ -68,7 +68,7 @@ RSpec.describe BulkUploadLettingsResultsController, type: :request do get "/lettings-logs/bulk-upload-results/#{bulk_upload.id}" expect(response).to be_successful - expect(response.body).to include("Bulk upload for lettings (2023/24)") + expect(response.body).to include("Bulk upload for lettings (#{bulk_upload.year_combo})") end it "renders correct number of errors" do diff --git a/spec/requests/bulk_upload_lettings_resume_controller_spec.rb b/spec/requests/bulk_upload_lettings_resume_controller_spec.rb index c91211d5a..d110768f0 100644 --- a/spec/requests/bulk_upload_lettings_resume_controller_spec.rb +++ b/spec/requests/bulk_upload_lettings_resume_controller_spec.rb @@ -41,7 +41,7 @@ RSpec.describe BulkUploadLettingsResumeController, type: :request do expect(response).to be_successful expect(response.body).to include("Bulk upload for lettings") - expect(response.body).to include("2023/24") + expect(response.body).to include(bulk_upload.year_combo) expect(response.body).to include("View the error report") expect(response.body).to include("How would you like to fix the errors?") expect(response.body).to include(bulk_upload.filename) @@ -180,7 +180,7 @@ RSpec.describe BulkUploadLettingsResumeController, type: :request do expect(response).to be_successful expect(response.body).to include("Bulk upload for lettings") - expect(response.body).to include("2023/24") + expect(response.body).to include(bulk_upload.year_combo) expect(response.body).to include("These 2 answers will be deleted if you upload the log") expect(response.body).to include(bulk_upload.filename) expect(response.body).to include("Clear this data and upload the logs") @@ -222,7 +222,7 @@ RSpec.describe BulkUploadLettingsResumeController, type: :request do expect(response).to be_successful expect(response.body).to include("Bulk upload for lettings") - expect(response.body).to include("2023/24") + expect(response.body).to include(bulk_upload.year_combo) expect(response.body).to include("These 2 answers will be deleted if you upload the log") expect(response.body).to include(bulk_upload.filename) expect(response.body).to include("Clear this data and upload the logs") diff --git a/spec/requests/bulk_upload_lettings_soft_validations_check_controller_spec.rb b/spec/requests/bulk_upload_lettings_soft_validations_check_controller_spec.rb index 88640dcb4..e7fc9ed46 100644 --- a/spec/requests/bulk_upload_lettings_soft_validations_check_controller_spec.rb +++ b/spec/requests/bulk_upload_lettings_soft_validations_check_controller_spec.rb @@ -15,7 +15,7 @@ RSpec.describe BulkUploadLettingsSoftValidationsCheckController, type: :request get "/lettings-logs/bulk-upload-soft-validations-check/#{bulk_upload.id}/confirm-soft-errors" expect(response.body).to include("Bulk upload for lettings") - expect(response.body).to include("2023/24") + expect(response.body).to include(bulk_upload.year_combo) expect(response.body).to include("Check these 2 answers") expect(response.body).to include(bulk_upload.filename) expect(response.body).to include("Are these fields correct?") diff --git a/spec/requests/bulk_upload_sales_results_controller_spec.rb b/spec/requests/bulk_upload_sales_results_controller_spec.rb index d0b2ef37b..ac759529a 100644 --- a/spec/requests/bulk_upload_sales_results_controller_spec.rb +++ b/spec/requests/bulk_upload_sales_results_controller_spec.rb @@ -16,7 +16,7 @@ RSpec.describe BulkUploadSalesResultsController, type: :request do get "/sales-logs/bulk-upload-results/#{bulk_upload.id}" expect(response).to be_successful - expect(response.body).to include("Bulk Upload for sales (2023/24)") + expect(response.body).to include("Bulk Upload for sales (#{bulk_upload.year_combo})") end it "renders correct number of errors" do diff --git a/spec/requests/bulk_upload_sales_resume_controller_spec.rb b/spec/requests/bulk_upload_sales_resume_controller_spec.rb index 47acc1ae6..36db459d3 100644 --- a/spec/requests/bulk_upload_sales_resume_controller_spec.rb +++ b/spec/requests/bulk_upload_sales_resume_controller_spec.rb @@ -41,7 +41,7 @@ RSpec.describe BulkUploadSalesResumeController, type: :request do expect(response).to be_successful expect(response.body).to include("Bulk upload for sales") - expect(response.body).to include("2023/24") + expect(response.body).to include(bulk_upload.year_combo) expect(response.body).to include("View the error report") expect(response.body).to include("How would you like to fix the errors?") expect(response.body).to include(bulk_upload.filename) @@ -180,7 +180,7 @@ RSpec.describe BulkUploadSalesResumeController, type: :request do expect(response).to be_successful expect(response.body).to include("Bulk upload for sales") - expect(response.body).to include("2023/24") + expect(response.body).to include(bulk_upload.year_combo) expect(response.body).to include("These 2 answers will be deleted if you upload the log") expect(response.body).to include(bulk_upload.filename) expect(response.body).to include("Clear this data and upload the logs") @@ -222,7 +222,7 @@ RSpec.describe BulkUploadSalesResumeController, type: :request do expect(response).to be_successful expect(response.body).to include("Bulk upload for sales") - expect(response.body).to include("2023/24") + expect(response.body).to include(bulk_upload.year_combo) expect(response.body).to include("These 2 answers will be deleted if you upload the log") expect(response.body).to include(bulk_upload.filename) expect(response.body).to include("Clear this data and upload the logs") diff --git a/spec/requests/bulk_upload_sales_soft_validations_check_controller_spec.rb b/spec/requests/bulk_upload_sales_soft_validations_check_controller_spec.rb index 225c7c734..f22ca0aa2 100644 --- a/spec/requests/bulk_upload_sales_soft_validations_check_controller_spec.rb +++ b/spec/requests/bulk_upload_sales_soft_validations_check_controller_spec.rb @@ -15,7 +15,7 @@ RSpec.describe BulkUploadSalesSoftValidationsCheckController, type: :request do get "/sales-logs/bulk-upload-soft-validations-check/#{bulk_upload.id}/confirm-soft-errors" expect(response.body).to include("Bulk upload for sales") - expect(response.body).to include("2023/24") + expect(response.body).to include(bulk_upload.year_combo) expect(response.body).to include("Check these 2 answers") expect(response.body).to include(bulk_upload.filename) expect(response.body).to include("Are these fields correct?") diff --git a/spec/requests/form_controller_spec.rb b/spec/requests/form_controller_spec.rb index 575058d6d..020dba3a4 100644 --- a/spec/requests/form_controller_spec.rb +++ b/spec/requests/form_controller_spec.rb @@ -1016,7 +1016,7 @@ RSpec.describe FormController, type: :request do end end - context "when the sale date changes from 2024 to 2023" do # TODO: CLDC-3505 remove this test on year hard end + context "when the sale date changes from 2024 to 2023" do let(:sales_log) { create(:sales_log, owning_organisation: organisation, managing_organisation:, assigned_to: user) } let(:params) do { @@ -1034,10 +1034,10 @@ RSpec.describe FormController, type: :request do before do organisation.managing_agents << managing_organisation organisation.reload - sales_log.saledate = Time.zone.local(2024, 12, 1) + sales_log.saledate = Time.zone.local(2024, 5, 1) sales_log.save!(validate: false) sales_log.reload - Timecop.freeze(Time.zone.local(2024, 12, 1)) + Timecop.freeze(Time.zone.local(2024, 5, 1)) Singleton.__init__(FormHandler) end diff --git a/spec/services/bulk_upload/lettings/log_creator_spec.rb b/spec/services/bulk_upload/lettings/log_creator_spec.rb index 85cf310f6..fe8e72127 100644 --- a/spec/services/bulk_upload/lettings/log_creator_spec.rb +++ b/spec/services/bulk_upload/lettings/log_creator_spec.rb @@ -6,13 +6,13 @@ RSpec.describe BulkUpload::Lettings::LogCreator do let(:owning_org) { create(:organisation, old_visible_id: 123, rent_periods: [2]) } let(:user) { create(:user, organisation: owning_org) } - let(:bulk_upload) { create(:bulk_upload, :lettings, user:) } - let(:csv_parser) { instance_double(BulkUpload::Lettings::Year2023::CsvParser) } - let(:row_parser) { instance_double(BulkUpload::Lettings::Year2023::RowParser) } + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, year: 2024) } + let(:csv_parser) { instance_double(BulkUpload::Lettings::Year2024::CsvParser) } + let(:row_parser) { instance_double(BulkUpload::Lettings::Year2024::RowParser) } let(:log) { build(:lettings_log, :completed, assigned_to: user, owning_organisation: owning_org, managing_organisation: owning_org) } before do - allow(BulkUpload::Lettings::Year2023::CsvParser).to receive(:new).and_return(csv_parser) + allow(BulkUpload::Lettings::Year2024::CsvParser).to receive(:new).and_return(csv_parser) allow(csv_parser).to receive(:row_parsers).and_return([row_parser]) allow(row_parser).to receive(:log).and_return(log) allow(row_parser).to receive(:bulk_upload=).and_return(true) @@ -20,23 +20,7 @@ RSpec.describe BulkUpload::Lettings::LogCreator do allow(row_parser).to receive(:blank_row?).and_return(false) end - around do |example| - Timecop.freeze(Time.zone.local(2023, 4, 1)) do - Singleton.__init__(FormHandler) - example.run - end - end - describe "#call" do - before do - Timecop.freeze(Time.zone.local(2023, 11, 10)) - Singleton.__init__(FormHandler) - end - - after do - Timecop.return - end - context "when a valid csv with new log" do it "creates a new log" do expect { service.call }.to change(LettingsLog, :count) @@ -77,17 +61,11 @@ RSpec.describe BulkUpload::Lettings::LogCreator do build( :lettings_log, :completed, - renttype: 3, age1_known: 0, age1: 5, owning_organisation: owning_org, managing_organisation: owning_org, assigned_to: user, - national: 18, - waityear: 9, - joint: 2, - tenancy: 9, - ppcodenk: 1, ) end @@ -148,18 +126,12 @@ RSpec.describe BulkUpload::Lettings::LogCreator do build( :lettings_log, :completed, - renttype: 3, age1: 22, age1_known: 0, ecstat1: 5, owning_organisation: owning_org, managing_organisation: owning_org, assigned_to: user, - national: 18, - waityear: 9, - joint: 2, - tenancy: 9, - ppcodenk: 1, ) end diff --git a/spec/services/bulk_upload/lettings/validator_spec.rb b/spec/services/bulk_upload/lettings/validator_spec.rb index 2a70260e4..88f4801f3 100644 --- a/spec/services/bulk_upload/lettings/validator_spec.rb +++ b/spec/services/bulk_upload/lettings/validator_spec.rb @@ -3,186 +3,110 @@ 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, period: 2, assigned_to: user) } + let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) } + let(:bulk_upload) { create(:bulk_upload, user:, year: log.collection_start_year) } 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(:field_numbers) { log_to_csv.default_field_numbers + %w[invalid_field_number] } + let(:field_values) { log_to_csv.to_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(:field_numbers) { log_to_csv.default_field_numbers } + let(:field_values) { log_to_csv.to_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 "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 + context "and file has too many valid headers" do + let(:seed) { rand } + let(:field_numbers) { log_to_csv.default_field_numbers + %w[23] } + let(:field_values) { log_to_csv.to_row + %w[value] } - 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") } + let(:bulk_upload) { build(:bulk_upload, user:, year: 2024) } - 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(: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) { build(:lettings_log, :completed, startdate: Time.zone.local(2024, 7, 1), period: 2, assigned_to: user) } + + 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 +115,39 @@ 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 } - - around do |example| - FormHandler.instance.use_real_forms! - - example.run + context "with a valid csv" do + before do + file.write(log_to_csv.default_field_numbers_row) + file.write(log_to_csv.to_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) { build(:lettings_log, :completed, startdate: Time.zone.local(2024, 7, 1), period: 2, assigned_to: user) } 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:)) + log.needstype = nil + values = log_to_csv.to_2024_row + 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,59 +158,71 @@ 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 context "when duplicate rows present" do - let(:file) { Tempfile.new } - let(:path) { file.path } - 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(log_to_csv.default_field_numbers_row) + file.write(log_to_csv.to_csv_row) + file.write(log_to_csv.to_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 + 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 + 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 "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) } + + before do + 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 + expect { validator.call }.to change(BulkUploadError, :count) + end + end end end - context "without headers" do - let(:log) { build(:lettings_log, :completed) } - let(:file) { Tempfile.new } - let(:path) { file.path } + context "with a 2024 csv without headers" do + let(:log) { build(:lettings_log, :completed, startdate: Time.zone.local(2024, 7, 1), period: 2, assigned_to: user) } before do - file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row) + file.write(log_to_csv.to_csv_row) file.close end @@ -294,47 +233,29 @@ 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) } + 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_2) { build(:lettings_log, :completed, period: 2, assigned_to: user, age1: 5) } 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, col_offset: 0).to_csv_row) + file.write(BulkUpload::LettingsLogToCsv.new(log: log_2, col_offset: 0).to_csv_row) file.close end it "returns false" do validator.call - expect(validator).not_to be_create_logs + expect(validator).to be_create_logs end end context "when all logs valid?" do - let(:log_1) { build(:lettings_log, :completed, renttype: 1, assigned_to: user) } - let(:log_2) { build(:lettings_log, :completed, renttype: 1, 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) } 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, col_offset: 0).to_csv_row) + file.write(BulkUpload::LettingsLogToCsv.new(log: log_2, col_offset: 0).to_csv_row) file.close end @@ -344,13 +265,13 @@ RSpec.describe BulkUpload::Lettings::Validator do end end - context "when a single log wants to block log creation" do + context "when a log wants to block log creation" do let(:unaffiliated_org) { create(:organisation) } - let(:log_1) { build(:lettings_log, :completed, renttype: 1, assigned_to: user, owning_organisation: unaffiliated_org) } + let(:log) { build(:lettings_log, :completed, 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(log_to_csv.to_csv_row) file.close end @@ -361,10 +282,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, 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(log_to_csv.to_csv_row) file.close end diff --git a/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb b/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb index 1d6d16b5f..a75d928ac 100644 --- a/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb +++ b/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb @@ -3,7 +3,7 @@ require "rails_helper" RSpec.describe BulkUpload::Lettings::Year2023::RowParser do subject(:parser) { described_class.new(attributes) } - let(:now) { Time.zone.now.beginning_of_day } + let(:now) { Time.zone.local(2023, 12, 1) } let(:attributes) { { bulk_upload: } } let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: nil, year: 2023) } @@ -30,7 +30,8 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do end before do - allow(FormHandler.instance).to receive(:lettings_in_crossover_period?).and_return(true) + Timecop.freeze(now) + create(:organisation_relationship, parent_organisation: owning_org, child_organisation: managing_org) LaRentRange.create!( @@ -46,11 +47,7 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do ) end - around do |example| - Timecop.freeze(Date.new(2023, 10, 1)) do - FormHandler.instance.use_real_forms! - example.run - end + after do Timecop.return end @@ -369,7 +366,7 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do end context "when a supported housing log with chcharges already exists in the db" do - let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: 2) } + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: 2, year: 2023) } let(:attributes) do valid_attributes.merge({ field_15: scheme.old_visible_id, field_4: "2", @@ -418,7 +415,7 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do end context "when a supported housing log different chcharges already exists in the db" do - let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: 2) } + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: 2, year: 2023) } let(:attributes) do valid_attributes.merge({ field_15: scheme.old_visible_id, field_4: "2", @@ -513,7 +510,7 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do end context "when a supported housing log with chcharges already exists in the db" do - let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: 2) } + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: 2, year: 2023) } let(:attributes) do valid_attributes.merge({ field_16: "S#{scheme.id}", field_4: "2", @@ -562,7 +559,7 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do end context "when a supported housing log different chcharges already exists in the db" do - let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: 2) } + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: 2, year: 2023) } let(:attributes) do valid_attributes.merge({ field_16: "S#{scheme.id}", field_4: "2", @@ -901,7 +898,7 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do end context "when bulk upload is for supported housing" do - let(:bulk_upload) { create(:bulk_upload, :lettings, user:) } + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, year: 2023) } context "when general needs option selected" do let(:attributes) { { bulk_upload:, field_5: "1", field_4: "2" } } @@ -1374,7 +1371,7 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do end context "when 4 ie referred by LA and is not general needs" do - let(:bulk_upload) { create(:bulk_upload, :lettings, user:) } + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, year: 2023) } let(:attributes) { { bulk_upload:, field_119: "4", field_4: "2" } } it "is permitted" do @@ -1411,9 +1408,9 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do end context "when inside of collection year" do - let(:attributes) { { bulk_upload:, field_7: "1", field_8: "10", field_9: "22" } } + let(:attributes) { { bulk_upload:, field_7: "1", field_8: "10", field_9: "23" } } - let(:bulk_upload) { create(:bulk_upload, :lettings, user:, year: 2022) } + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, year: 2023) } it "does not return errors" do expect(parser.errors[:field_7]).not_to be_present @@ -1423,15 +1420,9 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do end context "when outside of collection year" do - around do |example| - Timecop.freeze(Date.new(2022, 4, 2)) do - example.run - end - end - let(:attributes) { { bulk_upload:, field_7: "1", field_8: "1", field_9: "22" } } - let(:bulk_upload) { create(:bulk_upload, :lettings, user:, year: 2022) } + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, year: 2023) } it "returns setup errors" do expect(parser.errors.where(:field_7, category: :setup)).to be_present @@ -1640,7 +1631,7 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do end context "when neither UPRN nor address fields are given for a supported housing record" do - let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: 2) } + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: 2, year: 2023) } let(:attributes) do { bulk_upload:, field_15: scheme.old_visible_id, diff --git a/spec/services/bulk_upload/processor_spec.rb b/spec/services/bulk_upload/processor_spec.rb index e07b57ccb..08fe7d705 100644 --- a/spec/services/bulk_upload/processor_spec.rb +++ b/spec/services/bulk_upload/processor_spec.rb @@ -6,6 +6,7 @@ RSpec.describe BulkUpload::Processor do let(:bulk_upload) { create(:bulk_upload, :lettings, user:) } let(:user) { create(:user, organisation: owning_org) } let(:owning_org) { create(:organisation, old_visible_id: 123, rent_periods: [2]) } + let(:mock_validator) do instance_double( BulkUpload::Lettings::Validator, @@ -13,20 +14,35 @@ RSpec.describe BulkUpload::Processor do call: nil, total_logs_count: 1, any_setup_errors?: false, - create_logs?: false, + create_logs?: true, + soft_validation_errors_only?: false, + ) + end + let(:mock_downloader) do + instance_double( + BulkUpload::Downloader, + call: nil, + path:, + delete_local_file!: nil, ) end - describe "#call" do - before do - Timecop.freeze(Time.zone.local(2023, 11, 10)) - Singleton.__init__(FormHandler) - end + let(:file) { Tempfile.new } + let(:path) { file.path } - after do - Timecop.return - end + let(:log) { build(:lettings_log, :completed, assigned_to: user) } + before do + allow(BulkUpload::Lettings::Validator).to receive(:new).and_return(mock_validator) + log_to_csv = BulkUpload::LettingsLogToCsv.new(log:) + file.write(log_to_csv.default_field_numbers_row) + file.write(log_to_csv.to_csv_row) + file.rewind + + allow(BulkUpload::Downloader).to receive(:new).with(bulk_upload:).and_return(mock_downloader) + end + + describe "#call" do context "when errors exist from prior job run" do let!(:existing_error) { create(:bulk_upload_error, bulk_upload:) } @@ -38,15 +54,6 @@ RSpec.describe BulkUpload::Processor do end context "when the bulk upload itself is not considered valid" do - let(:mock_downloader) do - instance_double( - BulkUpload::Downloader, - call: nil, - path: file_fixture("2023_24_lettings_bulk_upload.csv"), - delete_local_file!: nil, - ) - end - let(:mock_validator) do instance_double( BulkUpload::Lettings::Validator, @@ -57,11 +64,6 @@ RSpec.describe BulkUpload::Processor do ) end - before do - allow(BulkUpload::Downloader).to receive(:new).with(bulk_upload:).and_return(mock_downloader) - allow(BulkUpload::Lettings::Validator).to receive(:new).and_return(mock_validator) - end - it "sends failure email" do mail_double = instance_double("ActionMailer::MessageDelivery", deliver_later: nil) @@ -88,27 +90,7 @@ RSpec.describe BulkUpload::Processor do end context "when the bulk upload processing throws an error" do - let(:mock_downloader) do - instance_double( - BulkUpload::Downloader, - call: nil, - path: file_fixture("2023_24_lettings_bulk_upload.csv"), - delete_local_file!: nil, - ) - end - - let(:mock_validator) do - instance_double( - BulkUpload::Lettings::Validator, - invalid?: false, - total_logs_count: 1, - ) - end - before do - allow(BulkUpload::Downloader).to receive(:new).with(bulk_upload:).and_return(mock_downloader) - allow(BulkUpload::Lettings::Validator).to receive(:new).and_return(mock_validator) - allow(mock_validator).to receive(:call).and_raise(StandardError) end @@ -132,16 +114,7 @@ RSpec.describe BulkUpload::Processor do end end - context "when a log has an incomplete setup section" do - let(:mock_downloader) do - instance_double( - BulkUpload::Downloader, - call: nil, - path: file_fixture("2023_24_lettings_bulk_upload.csv"), - delete_local_file!: nil, - ) - end - + context "when a log has a setup error" do let(:mock_validator) do instance_double( BulkUpload::Lettings::Validator, @@ -152,11 +125,6 @@ RSpec.describe BulkUpload::Processor do ) end - before do - allow(BulkUpload::Downloader).to receive(:new).with(bulk_upload:).and_return(mock_downloader) - allow(BulkUpload::Lettings::Validator).to receive(:new).and_return(mock_validator) - end - it "sends setup failure email" do mail_double = instance_double("ActionMailer::MessageDelivery", deliver_later: nil) @@ -170,37 +138,6 @@ RSpec.describe BulkUpload::Processor do end context "when processing a bulk with perfect data" do - let(:mock_downloader) do - instance_double( - BulkUpload::Downloader, - call: nil, - path:, - delete_local_file!: nil, - ) - end - - let(:file) { Tempfile.new } - let(:path) { file.path } - - let(:log) do - build( - :lettings_log, - :completed, - owning_organisation: owning_org, - managing_organisation: owning_org, - assigned_to: user, - renttype: 1, - leftreg: 3, - ) - end - - before do - file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2023_csv_row) - file.rewind - - allow(BulkUpload::Downloader).to receive(:new).with(bulk_upload:).and_return(mock_downloader) - end - it "creates logs as not pending" do expect { processor.call }.to change(LettingsLog.completed, :count).by(1) end @@ -217,98 +154,10 @@ RSpec.describe BulkUpload::Processor do end end - context "when processing an empty file" do - let(:mock_downloader) do - instance_double( - BulkUpload::Downloader, - call: nil, - path:, - delete_local_file!: nil, - ) - end - - let(:file) { Tempfile.new } - let(:path) { file.path } - - before do - allow(BulkUpload::Downloader).to receive(:new).with(bulk_upload:).and_return(mock_downloader) - end - - it "sends failure email" do - mail_double = instance_double("ActionMailer::MessageDelivery", deliver_later: nil) - - allow(BulkUploadMailer).to receive(:send_bulk_upload_failed_service_error_mail).and_return(mail_double) - - processor.call - - expect(BulkUploadMailer).to have_received(:send_bulk_upload_failed_service_error_mail).with( - bulk_upload:, - errors: ["Template is blank - The template must be filled in for us to create the logs and check if data is correct."], - ) - expect(mail_double).to have_received(:deliver_later) - end - end - - context "when 2023-24" do - let(:mock_downloader) do - instance_double( - BulkUpload::Downloader, - call: nil, - path: file_fixture("2023_24_lettings_bulk_upload_empty_with_headers.csv"), - delete_local_file!: nil, - ) - end - - before do - allow(BulkUpload::Downloader).to receive(:new).with(bulk_upload:).and_return(mock_downloader) - end - - it "sends failure email" do - mail_double = instance_double("ActionMailer::MessageDelivery", deliver_later: nil) - - allow(BulkUploadMailer).to receive(:send_bulk_upload_failed_service_error_mail).and_return(mail_double) - - processor.call - - expect(BulkUploadMailer).to have_received(:send_bulk_upload_failed_service_error_mail).with( - bulk_upload:, - errors: ["Template is blank - The template must be filled in for us to create the logs and check if data is correct."], - ) - expect(mail_double).to have_received(:deliver_later) - end - end - context "when a bulk upload has an in progress log" do - let(:mock_downloader) do - instance_double( - BulkUpload::Downloader, - call: nil, - path:, - delete_local_file!: nil, - ) - end - - let(:file) { Tempfile.new } - let(:path) { file.path } - - let(:log) do - LettingsLog.new( - lettype: 2, - renttype: 3, - owning_organisation: owning_org, - managing_organisation: owning_org, - startdate: Time.zone.local(2023, 10, 1), - renewal: 2, - declaration: 1, - ) - end + let(:log) { build(:lettings_log, :setup_completed, assigned_to: user) } before do - file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2023_csv_row) - file.rewind - - allow(BulkUpload::Downloader).to receive(:new).with(bulk_upload:).and_return(mock_downloader) - allow(BulkUpload::Lettings::Validator).to receive(:new).and_return(mock_validator) allow(mock_validator).to receive(:create_logs?).and_return(true) allow(mock_validator).to receive(:soft_validation_errors_only?).and_return(false) allow(FeatureToggle).to receive(:bulk_upload_duplicate_log_check_enabled?).and_return(true) @@ -341,58 +190,12 @@ RSpec.describe BulkUpload::Processor do end context "when a bulk upload has logs with only soft validations triggered" do - let(:mock_downloader) do - instance_double( - BulkUpload::Downloader, - call: nil, - path:, - delete_local_file!: nil, - ) - end - - let(:file) { Tempfile.new } - let(:path) { file.path } - - let(:log) do - build( - :lettings_log, - :completed, - renttype: 3, - age1: 20, - ecstat1: 5, - owning_organisation: owning_org, - managing_organisation: owning_org, - assigned_to: nil, - national: 18, - waityear: 9, - joint: 2, - tenancy: 2, - ppcodenk: 1, - voiddate: Date.new(2022, 1, 1), - reason: 40, - leftreg: 3, - mrcdate: nil, - startdate: Date.new(2023, 10, 1), - tenancylength: nil, - ) - end - before do - FormHandler.instance.use_real_forms! - file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2023_csv_row) - file.rewind - - allow(BulkUpload::Downloader).to receive(:new).with(bulk_upload:).and_return(mock_downloader) - allow(BulkUpload::Lettings::Validator).to receive(:new).and_return(mock_validator) allow(mock_validator).to receive(:create_logs?).and_return(true) allow(mock_validator).to receive(:soft_validation_errors_only?).and_return(true) allow(FeatureToggle).to receive(:bulk_upload_duplicate_log_check_enabled?).and_return(true) end - after do - FormHandler.instance.use_fake_forms! - end - it "creates pending log" do expect { processor.call }.to change(LettingsLog.pending, :count).by(1) end @@ -421,42 +224,18 @@ RSpec.describe BulkUpload::Processor do end end - context "when upload has no setup errors something blocks log creation" do - let(:mock_downloader) do + context "when upload has something blocking log creation" do + let(:mock_validator) do instance_double( - BulkUpload::Downloader, + BulkUpload::Lettings::Validator, + invalid?: false, call: nil, - path:, - delete_local_file!: nil, - ) - end - - let(:file) { Tempfile.new } - let(:path) { file.path } - - let(:other_user) { create(:user) } - - let(:log) do - LettingsLog.new( - lettype: 2, - renttype: 3, - owning_organisation: owning_org, - managing_organisation: owning_org, - startdate: Time.zone.local(2023, 10, 1), - renewal: 2, - assigned_to: other_user, # unaffiliated user - declaration: 1, + total_logs_count: 1, + any_setup_errors?: false, + create_logs?: false, ) end - before do - allow(BulkUpload::Lettings::Validator).to receive(:new).and_return(mock_validator) - file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2023_csv_row) - file.rewind - - allow(BulkUpload::Downloader).to receive(:new).with(bulk_upload:).and_return(mock_downloader) - end - it "sends correct_and_upload_again_mail" do mail_double = instance_double("ActionMailer::MessageDelivery", deliver_later: nil) @@ -471,12 +250,12 @@ RSpec.describe BulkUpload::Processor do end describe "#approve" do - let!(:log) { create(:lettings_log, bulk_upload:, status: "pending", skip_update_status: true, status_cache: "not_started") } + let!(:log) { create(:lettings_log, :in_progress, bulk_upload:, status: "pending", skip_update_status: true, status_cache: "in_progress") } it "makes pending logs no longer pending" do expect(log.status).to eql("pending") processor.approve - expect(log.reload.status).to eql("not_started") + expect(log.reload.status).to eql("in_progress") end end end diff --git a/spec/services/bulk_upload/sales/log_creator_spec.rb b/spec/services/bulk_upload/sales/log_creator_spec.rb index 4c3c38bbb..2353a74c6 100644 --- a/spec/services/bulk_upload/sales/log_creator_spec.rb +++ b/spec/services/bulk_upload/sales/log_creator_spec.rb @@ -6,13 +6,13 @@ RSpec.describe BulkUpload::Sales::LogCreator do let(:owning_org) { create(:organisation, old_visible_id: 123) } let(:user) { create(:user, organisation: owning_org) } - let(:bulk_upload) { create(:bulk_upload, :sales, user:) } - let(:csv_parser) { instance_double(BulkUpload::Sales::Year2023::CsvParser) } - let(:row_parser) { instance_double(BulkUpload::Sales::Year2023::RowParser) } + let(:bulk_upload) { create(:bulk_upload, :sales, user:, year: 2024) } + let(:csv_parser) { instance_double(BulkUpload::Sales::Year2024::CsvParser) } + let(:row_parser) { instance_double(BulkUpload::Sales::Year2024::RowParser) } let(:log) { build(:sales_log, :completed, assigned_to: user, owning_organisation: owning_org, managing_organisation: owning_org) } before do - allow(BulkUpload::Sales::Year2023::CsvParser).to receive(:new).and_return(csv_parser) + allow(BulkUpload::Sales::Year2024::CsvParser).to receive(:new).and_return(csv_parser) allow(csv_parser).to receive(:row_parsers).and_return([row_parser]) allow(row_parser).to receive(:log).and_return(log) allow(row_parser).to receive(:bulk_upload=).and_return(true) @@ -21,13 +21,6 @@ RSpec.describe BulkUpload::Sales::LogCreator do end describe "#call" do - around do |example| - Timecop.freeze(Time.zone.local(2023, 4, 22)) do - Singleton.__init__(FormHandler) - example.run - end - end - context "when a valid csv with new log" do it "creates a new log" do expect { service.call }.to change(SalesLog, :count) @@ -92,14 +85,15 @@ RSpec.describe BulkUpload::Sales::LogCreator do build( :sales_log, :completed, - ownershipsch: 2, - pcodenk: 0, - ppcodenk: 0, - postcode_full: "AA11AA", - ppostcode_full: "BB22BB", owning_organisation: owning_org, assigned_to: user, managing_organisation: owning_org, + ownershipsch: 2, + value: 200_000, + deposit: 10_000, + mortgageused: 1, + mortgage: 100_000, + grant: 10_000, ) end @@ -111,10 +105,10 @@ RSpec.describe BulkUpload::Sales::LogCreator do service.call record = SalesLog.last - expect(record.pcodenk).to be_blank - expect(record.postcode_full).to be_blank - expect(record.ppcodenk).to be_blank - expect(record.ppostcode_full).to be_blank + expect(record.value).to be_blank + expect(record.deposit).to be_blank + expect(record.mortgage).to be_blank + expect(record.grant).to be_blank end end diff --git a/spec/services/bulk_upload/sales/validator_spec.rb b/spec/services/bulk_upload/sales/validator_spec.rb index a233dcbc8..c5a35bd56 100644 --- a/spec/services/bulk_upload/sales/validator_spec.rb +++ b/spec/services/bulk_upload/sales/validator_spec.rb @@ -5,7 +5,9 @@ RSpec.describe BulkUpload::Sales::Validator do let(:user) { create(:user, organisation:) } 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(:file) { Tempfile.new } @@ -40,185 +42,90 @@ RSpec.describe BulkUpload::Sales::Validator do 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(:log) { build(:sales_log, :completed, saledate: Time.zone.local(2023, 10, 10), assigned_to: user) } - context "with a valid csv" do - let(:path) { file_fixture("2022_23_sales_bulk_upload.csv") } - - it "is not valid" do - 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 + before do + file.write(log_to_csv.default_2024_field_numbers_row) + file.write(log_to_csv.to_2024_csv_row) + file.rewind end - context "with headers" do - let(:file) { Tempfile.new } - let(:seed) { rand } - 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 + it "is not valid" do + expect(validator).not_to be_valid + expect(validator.errors["base"]).to eql(["Incorrect sale dates, please ensure you have used the correct template"]) end end - context "when trying to upload 2024 year data for 2024 bulk upload" do - let(:bulk_upload) { create(:bulk_upload, user:, year: 2024) } - - context "with headers" do - let(:file) { Tempfile.new } - let(:seed) { rand } - let(:log) { build(:sales_log, :completed, saledate: Time.zone.local(2024, 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 valid" do - expect(validator).to be_valid + [ + { line_ending: "\n", name: "unix" }, + { line_ending: "\r\n", name: "windows" }, + ].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 "is valid" do + expect(validator).to be_valid + end end end end - context "when trying to upload different years data for 2023 bulk upload" do - let(:bulk_upload) { create(:bulk_upload, user:, year: 2023) } + context "with a valid file in an arbitrary order" do + let(:seed) { rand } - context "with a valid csv" do - let(:path) { file_fixture("2022_23_sales_bulk_upload.csv") } - - it "is not valid" do - 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 + before do + file.write(log_to_csv.default_field_numbers_row(seed:)) + file.write(log_to_csv.to_csv_row(seed:)) + file.rewind end - context "with headers" do - let(:file) { Tempfile.new } - 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 + it "is valid" do + expect(validator).to be_valid end end 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 - 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 end it "is not valid" do 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 describe "#call" 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 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 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.error).to eql("You must answer owning organisation") - expect(error.purchaser_code).to eql("23 test BU") - expect(error.row).to eql("9") - expect(error.cell).to eql("B9") + expect(error.purchaser_code).to eql(log.purchaser_code) + expect(error.row).to eql("2") + expect(error.cell).to eql("B2") expect(error.col).to eql("B") end end - context "with unix line endings" do - let(:fixture_path) { file_fixture("2023_24_sales_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 + 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 - string = File.read(fixture_path) - string.gsub!("\r\n", "\n") - file.write(string) - file.rewind - end + before do + 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 - expect { validator.call }.to change(BulkUploadError, :count) + it "creates validation errors" do + expect { validator.call }.to change(BulkUploadError, :count) + end + end end end context "without headers" do - let(:log) { build(:sales_log, :completed) } - let(:file) { Tempfile.new } - let(:path) { file.path } - 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 end @@ -271,13 +192,9 @@ RSpec.describe BulkUpload::Sales::Validator do end context "when duplicate rows present" do - let(:file) { Tempfile.new } - let(:path) { file.path } - let(:log) { build(:sales_log, :completed) } - before do - file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2023_csv_row) - file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2023_csv_row) + file.write(log_to_csv.to_csv_row) + file.write(log_to_csv.to_csv_row) file.close end @@ -288,83 +205,62 @@ RSpec.describe BulkUpload::Sales::Validator do end 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 - 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 - validator.call - expect(validator).to be_create_logs + before do + file.write(BulkUpload::SalesLogToCsv.new(log: log_1).to_csv_row) + file.write(BulkUpload::SalesLogToCsv.new(log: log_2).to_csv_row) 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 - expect(validator).not_to be_create_logs + expect(validator).to be_create_logs 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_2) { build(:sales_log, :completed, assigned_to: user) } + let(:log_2) { build(:sales_log, :completed, assigned_to: user, age1: 5) } 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_2, line_ending: "\r\n", col_offset: 0, overrides: { organisation_id: "random" }).to_2023_csv_row) - file.close - end - - it "returns false" do - validator.call - expect(validator).not_to be_create_logs + file.write(BulkUpload::SalesLogToCsv.new(log: log_1).to_csv_row) + file.write(BulkUpload::SalesLogToCsv.new(log: log_2).to_csv_row) 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 expect(validator).to be_create_logs end end - context "when a single log wants to block log creation" do - let(:unaffiliated_org) { create(:organisation) } - - let(:log_1) { build(:sales_log, :completed, assigned_to: user, owning_organisation: unaffiliated_org) } + context "when a log has an incomplete setup section" do + let(:log_1) { build(:sales_log, :completed, assigned_to: user) } + let(:log_2) { build(:sales_log, :completed, assigned_to: user, privacynotice: nil) } 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 end - it "will not create logs" do + it "returns false" do validator.call expect(validator).not_to be_create_logs end end - context "when a log has incomplete setup secion" do - let(:log) { build(:sales_log, assigned_to: user, saledate: Time.zone.local(2022, 5, 1)) } + context "when a single log wants to block log creation" do + let(:unaffiliated_org) { create(:organisation) } + let(:log) { build(:sales_log, :completed, assigned_to: user, owning_organisation: unaffiliated_org) } 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 end - it "returns false" do + it "will not create logs" do validator.call expect(validator).not_to be_create_logs end @@ -372,28 +268,20 @@ RSpec.describe BulkUpload::Sales::Validator do end 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 - 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 - target_array = File.open(target_path).readlines - target_array[0..118].each do |line| - file.write line - end + file.write(log_to_csv.default_field_numbers_row) + file.write(log_to_csv.to_csv_row) + file.write(BulkUpload::SalesLogToCsv.new(log: log_2).to_csv_row) + file.write(BulkUpload::SalesLogToCsv.new(log: log_3).to_csv_row) file.rewind end 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 diff --git a/spec/services/csv/sales_log_csv_service_spec.rb b/spec/services/csv/sales_log_csv_service_spec.rb index aee659ae5..f238db53c 100644 --- a/spec/services/csv/sales_log_csv_service_spec.rb +++ b/spec/services/csv/sales_log_csv_service_spec.rb @@ -30,6 +30,8 @@ RSpec.describe Csv::SalesLogCsvService do county_as_entered: "county as entered", postcode_full_as_entered: "AB1 2CD", la_as_entered: "la as entered", + hhregres: 1, + hhregresstill: 4, ) end let(:service) { described_class.new(user:, export_type: "labels", year:) } diff --git a/spec/support/bulk_upload/lettings_log_to_csv.rb b/spec/support/bulk_upload/lettings_log_to_csv.rb index 0b6b6348e..18c367ffc 100644 --- a/spec/support/bulk_upload/lettings_log_to_csv.rb +++ b/spec/support/bulk_upload/lettings_log_to_csv.rb @@ -12,6 +12,62 @@ class BulkUpload::LettingsLogToCsv [nil] * col_offset 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(seed: nil) if seed row = to_2022_row.shuffle(random: Random.new(seed)) @@ -27,9 +83,9 @@ class BulkUpload::LettingsLogToCsv def default_2022_field_numbers_row(seed: nil) if seed - ["Bulk upload field number"] + default_2022_field_numbers.shuffle(random: Random.new(seed)) + ["Field number"] + default_2022_field_numbers.shuffle(random: Random.new(seed)) else - ["Bulk upload field number"] + default_2022_field_numbers + ["Field number"] + default_2022_field_numbers end.flatten.join(",") + line_ending end @@ -65,17 +121,17 @@ class BulkUpload::LettingsLogToCsv def default_2023_field_numbers_row(seed: nil) 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 - ["Bulk upload field number"] + default_2023_field_numbers + ["Field number"] + default_2023_field_numbers end.flatten.join(",") + line_ending end def default_2024_field_numbers_row(seed: nil) 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 - ["Bulk upload field number"] + default_2024_field_numbers + ["Field number"] + default_2024_field_numbers end.flatten.join(",") + line_ending end @@ -93,14 +149,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 +193,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 +270,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, @@ -385,16 +441,14 @@ class BulkUpload::LettingsLogToCsv def custom_field_numbers_row(seed: nil, field_numbers: nil) if seed - ["Bulk upload field number"] + field_numbers.shuffle(random: Random.new(seed)) + ["Field number"] + field_numbers.shuffle(random: Random.new(seed)) else - ["Bulk upload field number"] + field_numbers + ["Field number"] + field_numbers end.flatten.join(",") + line_ending 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 +476,10 @@ private end end + def rent_type + LettingsLog::RENTTYPE_DETAIL_MAPPING[log.rent_type] + end + def leftreg case log.leftreg when 3 @@ -471,6 +529,10 @@ private checkbox_value(log.cap) end + def accessible_register + checkbox_value(log.accessible_register) + end + def checkbox_value(field) case field when 0 diff --git a/spec/support/bulk_upload/sales_log_to_csv.rb b/spec/support/bulk_upload/sales_log_to_csv.rb index a45227436..8e2f1be0c 100644 --- a/spec/support/bulk_upload/sales_log_to_csv.rb +++ b/spec/support/bulk_upload/sales_log_to_csv.rb @@ -12,6 +12,62 @@ class BulkUpload::SalesLogToCsv [nil] * col_offset 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 (row_prefix + to_2022_row).flatten.join(",") + line_ending end @@ -40,25 +96,25 @@ class BulkUpload::SalesLogToCsv def default_2022_field_numbers_row(seed: nil) if seed - ["Bulk upload field number"] + default_2022_field_numbers.shuffle(random: Random.new(seed)) + ["Field number"] + default_2022_field_numbers.shuffle(random: Random.new(seed)) else - ["Bulk upload field number"] + default_2022_field_numbers + ["Field number"] + default_2022_field_numbers end.flatten.join(",") + line_ending end def default_2023_field_numbers_row(seed: nil) 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 - ["Bulk upload field number"] + default_2023_field_numbers + ["Field number"] + default_2023_field_numbers end.flatten.join(",") + line_ending end def default_2024_field_numbers_row(seed: nil) 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 - ["Bulk upload field number"] + default_2024_field_numbers + ["Field number"] + default_2024_field_numbers end.flatten.join(",") + line_ending end @@ -239,10 +295,10 @@ class BulkUpload::SalesLogToCsv log.saledate&.strftime("%y"), log.purchid, log.ownershipsch, - 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 == 1 ? log.type : "", # field_9: "What is the type of shared 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.companybuy, log.buylivein, @@ -267,7 +323,7 @@ class BulkUpload::SalesLogToCsv log.age1, log.sex1, log.ethnic, - log.national, + log.nationality_all_group, log.ecstat1, log.buy1livein, log.relat2, @@ -275,7 +331,7 @@ class BulkUpload::SalesLogToCsv log.sex2, log.ethnic_group2, # 40 - log.nationalbuy2, + log.nationality_all_buyer2_group, log.ecstat2, log.buy2livein, log.hholdcount, @@ -309,7 +365,7 @@ class BulkUpload::SalesLogToCsv log.buy2living, # 70 log.prevtenbuy2, - hhregres, + log.hhregres, log.hhregresstill, log.armedforcesspouse, log.disabled, @@ -320,7 +376,7 @@ class BulkUpload::SalesLogToCsv log.inc2mort, # 80 log.hb, - log.savings, + log.savings.present? || "R", log.prevown, log.prevshared, log.proplen, @@ -357,7 +413,7 @@ class BulkUpload::SalesLogToCsv log.proplen, log.value, log.grant, - log.discount, + log.discount || 0, log.mortgageused, log.mortgage, log.mortgagelender, @@ -383,16 +439,14 @@ class BulkUpload::SalesLogToCsv def custom_field_numbers_row(seed: nil, field_numbers: nil) if seed - ["Bulk upload field number"] + field_numbers.shuffle(random: Random.new(seed)) + ["Field number"] + field_numbers.shuffle(random: Random.new(seed)) else - ["Bulk upload field number"] + field_numbers + ["Field number"] + field_numbers end.flatten.join(",") + line_ending 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