Browse Source

CLDC-2442 Remove 2022/23 BU code (#2153)

* Remove 2022/23 BU code

* Add empty lines to csvs

* Update feature tests

* More tests

* Remove forms and update a test

* rebase tests
pull/2170/head
kosiakkatrina 11 months ago committed by GitHub
parent
commit
52a0b27611
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      app/controllers/bulk_upload_sales_logs_controller.rb
  2. 48
      app/controllers/start_controller.rb
  3. 16
      app/models/forms/bulk_upload_lettings/prepare_your_file.rb
  4. 15
      app/models/forms/bulk_upload_sales/prepare_your_file.rb
  5. 2
      app/services/bulk_upload/lettings/log_creator.rb
  6. 2
      app/services/bulk_upload/lettings/validator.rb
  7. 109
      app/services/bulk_upload/lettings/year2022/csv_parser.rb
  8. 1476
      app/services/bulk_upload/lettings/year2022/row_parser.rb
  9. 2
      app/services/bulk_upload/sales/log_creator.rb
  10. 2
      app/services/bulk_upload/sales/validator.rb
  11. 83
      app/services/bulk_upload/sales/year2022/csv_parser.rb
  12. 1156
      app/services/bulk_upload/sales/year2022/row_parser.rb
  13. 41
      app/views/bulk_upload_lettings_logs/forms/prepare_your_file_2022.html.erb
  14. 34
      app/views/bulk_upload_sales_logs/forms/prepare_your_file_2022.html.erb
  15. 8
      config/routes.rb
  16. BIN
      public/files/2022_23_lettings_paper_form.pdf
  17. BIN
      public/files/2022_23_sales_paper_form.pdf
  18. BIN
      public/files/bulk-upload-lettings-specification-2022-23.xlsx
  19. BIN
      public/files/bulk-upload-lettings-template-2022-23.xlsx
  20. BIN
      public/files/bulk-upload-sales-specification-2022-23.xlsx
  21. BIN
      public/files/bulk-upload-sales-template-2022-23.xlsx
  22. 4
      spec/components/bulk_upload_error_row_component_spec.rb
  23. 2
      spec/factories/bulk_upload.rb
  24. 28
      spec/features/bulk_upload_lettings_logs_spec.rb
  25. 12
      spec/features/bulk_upload_sales_logs_spec.rb
  26. 20
      spec/fixtures/files/2021_22_lettings_bulk_upload.csv
  27. BIN
      spec/fixtures/files/2021_22_lettings_bulk_upload.xlsx
  28. BIN
      spec/fixtures/files/2021_22_lettings_bulk_upload_empty.xlsx
  29. 74
      spec/fixtures/files/2022_23_lettings_bulk_upload.csv
  30. 50
      spec/fixtures/files/2023_24_lettings_bulk_upload.csv
  31. BIN
      spec/fixtures/files/2023_24_lettings_bulk_upload.xlsx
  32. 1
      spec/fixtures/files/2023_24_lettings_bulk_upload_invalid.csv
  33. 12
      spec/fixtures/files/2023_24_sales_bulk_upload.csv
  34. 12
      spec/fixtures/files/2023_24_sales_bulk_upload_invalid.csv
  35. 119
      spec/fixtures/files/completed_2022_23_sales_bulk_upload.csv
  36. 4
      spec/mailers/bulk_upload_mailer_spec.rb
  37. 4
      spec/requests/bulk_upload_lettings_results_controller_spec.rb
  38. 4
      spec/requests/bulk_upload_lettings_resume_controller_spec.rb
  39. 2
      spec/requests/bulk_upload_lettings_soft_validations_check_controller_spec.rb
  40. 2
      spec/requests/bulk_upload_sales_results_controller_spec.rb
  41. 4
      spec/requests/bulk_upload_sales_resume_controller_spec.rb
  42. 2
      spec/requests/bulk_upload_sales_soft_validations_check_controller_spec.rb
  43. 53
      spec/services/bulk_upload/lettings/log_creator_spec.rb
  44. 179
      spec/services/bulk_upload/lettings/validator_spec.rb
  45. 218
      spec/services/bulk_upload/lettings/year2022/csv_parser_spec.rb
  46. 2181
      spec/services/bulk_upload/lettings/year2022/row_parser_spec.rb
  47. 88
      spec/services/bulk_upload/processor_spec.rb
  48. 55
      spec/services/bulk_upload/sales/log_creator_spec.rb
  49. 61
      spec/services/bulk_upload/sales/validator_spec.rb
  50. 150
      spec/services/bulk_upload/sales/year2022/csv_parser_spec.rb
  51. 921
      spec/services/bulk_upload/sales/year2022/row_parser_spec.rb

2
app/controllers/bulk_upload_sales_logs_controller.rb

@ -35,6 +35,8 @@ private
end
def in_crossover_period?
return true if FeatureToggle.force_crossover?
FormHandler.instance.sales_in_crossover_period?
end

48
app/controllers/start_controller.rb

@ -21,14 +21,6 @@ class StartController < ApplicationController
)
end
def download_22_23_sales_form
send_file(
Rails.root.join("public/files/2022_23_sales_paper_form.pdf"),
filename: "2022-23 Sales paper form.pdf",
type: "application/pdf",
)
end
def download_24_25_lettings_form
send_file(
Rails.root.join("public/files/2024_25_lettings_paper_form.pdf"),
@ -45,14 +37,6 @@ class StartController < ApplicationController
)
end
def download_22_23_lettings_form
send_file(
Rails.root.join("public/files/2022_23_lettings_paper_form.pdf"),
filename: "2022-23 Lettings paper form.pdf",
type: "application/pdf",
)
end
def download_24_25_lettings_bulk_upload_template
send_file(
Rails.root.join("public/files/bulk-upload-lettings-template-2024-25.xlsx"),
@ -132,36 +116,4 @@ class StartController < ApplicationController
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
end
def download_22_23_lettings_bulk_upload_template
send_file(
Rails.root.join("public/files/bulk-upload-lettings-template-2022-23.xlsx"),
filename: "2022-23-lettings-bulk-upload-template.xlsx",
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
end
def download_22_23_lettings_bulk_upload_specification
send_file(
Rails.root.join("public/files/bulk-upload-lettings-specification-2022-23.xlsx"),
filename: "2022-23-lettings-bulk-upload-specification.xlsx",
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
end
def download_22_23_sales_bulk_upload_template
send_file(
Rails.root.join("public/files/bulk-upload-sales-template-2022-23.xlsx"),
filename: "2022-23-sales-bulk-upload-template.xlsx",
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
end
def download_22_23_sales_bulk_upload_specification
send_file(
Rails.root.join("public/files/bulk-upload-sales-specification-2022-23.xlsx"),
filename: "2022-23-sales-bulk-upload-specification.xlsx",
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
end
end

16
app/models/forms/bulk_upload_lettings/prepare_your_file.rb

@ -10,9 +10,7 @@ module Forms
def view_path
case year
when 2022
"bulk_upload_lettings_logs/forms/prepare_your_file_2022"
else
when 2023
"bulk_upload_lettings_logs/forms/prepare_your_file_2023"
end
end
@ -32,27 +30,21 @@ module Forms
def legacy_template_path
case year
when 2022
"/files/bulk-upload-lettings-template-2022-23.xlsx"
else
when 2023
"/files/bulk-upload-lettings-legacy-template-2023-24.xlsx"
end
end
def template_path
case year
when 2022
"/files/bulk-upload-lettings-template-2022-23.xlsx"
else
when 2023
"/files/bulk-upload-lettings-template-2023-24.xlsx"
end
end
def specification_path
case year
when 2022
"/files/bulk-upload-lettings-specification-2022-23.xlsx"
else
when 2023
"/files/bulk-upload-lettings-specification-2023-24.xlsx"
end
end

15
app/models/forms/bulk_upload_sales/prepare_your_file.rb

@ -9,9 +9,7 @@ module Forms
def view_path
case year
when 2022
"bulk_upload_sales_logs/forms/prepare_your_file_2022"
else
when 2023
"bulk_upload_sales_logs/forms/prepare_your_file_2023"
end
end
@ -30,17 +28,13 @@ module Forms
def legacy_template_path
case year
when 2022
"/files/bulk-upload-sales-template-2022-23.xlsx"
else
when 2023
"/files/bulk-upload-sales-legacy-template-2023-24.xlsx"
end
end
def template_path
case year
when 2022
"/files/bulk-upload-sales-template-2022-23.xlsx"
when 2023
"/files/bulk-upload-sales-template-2023-24.xlsx"
end
@ -48,8 +42,7 @@ module Forms
def specification_path
case year
when 2022
"/files/bulk-upload-sales-specification-2022-23.xlsx"
when 2023
"/files/bulk-upload-sales-specification-2023-24.xlsx"
end
@ -66,6 +59,8 @@ module Forms
private
def in_crossover_period?
return true if FeatureToggle.force_crossover?
FormHandler.instance.sales_in_crossover_period?
end
end

2
app/services/bulk_upload/lettings/log_creator.rb

@ -31,8 +31,6 @@ private
def csv_parser
@csv_parser ||= case bulk_upload.year
when 2022
BulkUpload::Lettings::Year2022::CsvParser.new(path:)
when 2023
BulkUpload::Lettings::Year2023::CsvParser.new(path:)
else

2
app/services/bulk_upload/lettings/validator.rb

@ -98,8 +98,6 @@ private
def csv_parser
@csv_parser ||= case bulk_upload.year
when 2022
BulkUpload::Lettings::Year2022::CsvParser.new(path:)
when 2023
BulkUpload::Lettings::Year2023::CsvParser.new(path:)
else

109
app/services/bulk_upload/lettings/year2022/csv_parser.rb

@ -1,109 +0,0 @@
require "csv"
class BulkUpload::Lettings::Year2022::CsvParser
FIELDS = 134
MAX_COLUMNS = 135
FORM_YEAR = 2022
attr_reader :path
def initialize(path:)
@path = path
end
def row_offset
if with_headers?
rows.find_index { |row| row[0].match(/field number/i) } + 1
else
0
end
end
def col_offset
with_headers? ? 1 : 0
end
def cols
@cols ||= ("A".."EE").to_a
end
def row_parsers
@row_parsers ||= body_rows.map do |row|
stripped_row = row[col_offset..]
hash = Hash[field_numbers.zip(stripped_row)]
BulkUpload::Lettings::Year2022::RowParser.new(hash)
end
end
def body_rows
rows[row_offset..]
end
def rows
@rows ||= CSV.parse(normalised_string, row_sep:)
end
def column_for_field(field)
cols[field_numbers.find_index(field) + col_offset]
end
def correct_field_count?
valid_field_numbers_count = field_numbers.count { |f| f != "field_blank" }
valid_field_numbers_count == FIELDS
end
def too_many_columns?
return if with_headers?
max_columns_count = body_rows.map(&:size).max - col_offset
max_columns_count > MAX_COLUMNS
end
def wrong_template_for_year?
!(first_record_start_date >= form.start_date && first_record_start_date <= form.new_logs_end_date)
end
private
def form
@form ||= FormHandler.instance.lettings_form_for_start_year(FORM_YEAR)
end
def first_record_start_date
@first_record_start_date ||= row_parsers.first.startdate || Date.new
end
def default_field_numbers
("field_1".."field_#{FIELDS}").to_a
end
def field_numbers
@field_numbers ||= if with_headers?
rows[row_offset - 1][col_offset..].map { |h| h.present? && h.match?(/^[0-9]+$/) ? "field_#{h}" : "field_blank" }
else
default_field_numbers
end
end
def with_headers?
rows.map { |r| r[0] }.any? { |cell| cell&.match?(/field number/i) }
end
def row_sep
"\n"
end
def normalised_string
return @normalised_string if @normalised_string
@normalised_string = File.read(path, encoding: "bom|utf-8")
@normalised_string.gsub!("\r\n", "\n")
@normalised_string.scrub!("")
@normalised_string.tr!("\r", "\n")
@normalised_string
end
end

1476
app/services/bulk_upload/lettings/year2022/row_parser.rb

File diff suppressed because it is too large Load Diff

2
app/services/bulk_upload/sales/log_creator.rb

@ -31,8 +31,6 @@ private
def csv_parser
@csv_parser ||= case bulk_upload.year
when 2022
BulkUpload::Sales::Year2022::CsvParser.new(path:)
when 2023
BulkUpload::Sales::Year2023::CsvParser.new(path:)
else

2
app/services/bulk_upload/sales/validator.rb

@ -92,8 +92,6 @@ private
def csv_parser
@csv_parser ||= case bulk_upload.year
when 2022
BulkUpload::Sales::Year2022::CsvParser.new(path:)
when 2023
BulkUpload::Sales::Year2023::CsvParser.new(path:)
else

83
app/services/bulk_upload/sales/year2022/csv_parser.rb

@ -1,83 +0,0 @@
require "csv"
class BulkUpload::Sales::Year2022::CsvParser
MAX_COLUMNS = 126
FORM_YEAR = 2022
attr_reader :path
def initialize(path:)
@path = path
end
def row_offset
with_headers? ? 5 : 0
end
def col_offset
with_headers? ? 1 : 0
end
def cols
@cols ||= ("A".."DV").to_a
end
def row_parsers
@row_parsers ||= body_rows.map do |row|
stripped_row = row[col_offset..]
headers = ("field_1".."field_125").to_a
hash = Hash[headers.zip(stripped_row)]
BulkUpload::Sales::Year2022::RowParser.new(hash)
end
end
def body_rows
rows[row_offset..]
end
def rows
@rows ||= CSV.parse(normalised_string, row_sep:)
end
def column_for_field(field)
cols[headers.find_index(field) + col_offset]
end
def wrong_template_for_year?
!(first_record_sale_date >= form.start_date && first_record_sale_date <= form.new_logs_end_date)
end
private
def form
@form ||= FormHandler.instance.sales_form_for_start_year(FORM_YEAR)
end
def first_record_sale_date
@first_record_sale_date ||= row_parsers.first.saledate || Date.new
end
def headers
@headers ||= ("field_1".."field_125").to_a
end
def with_headers?
rows.map { |r| r[0] }.any? { |cell| cell&.match?(/field number/i) }
end
def row_sep
"\n"
end
def normalised_string
return @normalised_string if @normalised_string
@normalised_string = File.read(path, encoding: "bom|utf-8")
@normalised_string.gsub!("\r\n", "\n")
@normalised_string.scrub!("")
@normalised_string.tr!("\r", "\n")
@normalised_string
end
end

1156
app/services/bulk_upload/sales/year2022/row_parser.rb

File diff suppressed because it is too large Load Diff

41
app/views/bulk_upload_lettings_logs/forms/prepare_your_file_2022.html.erb

@ -1,41 +0,0 @@
<% content_for :before_content do %>
<%= govuk_back_link href: @form.back_path %>
<% end %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<%= form_with model: @form, scope: :form, url: bulk_upload_lettings_log_path(id: "prepare-your-file"), method: :patch do |f| %>
<%= f.hidden_field :year %>
<span class="govuk-caption-l">Upload lettings logs in bulk (<%= @form.year_combo %>)</span>
<h1 class="govuk-heading-l">Prepare your file</h1>
<h2 class="govuk-heading-s">Download template</h2>
<ul class="govuk-list govuk-list--bullet">
<li>
Download and use <%= govuk_link_to "this template", @form.template_path %>.
</li>
</ul>
<h2 class="govuk-heading-s">Create your file</h2>
<ul class="govuk-list govuk-list--bullet">
<li>Fill in the template with CORE data from your housing management system according to the <%= govuk_link_to "Lettings #{@form.year_combo} Bulk Upload Specification", @form.specification_path %>.</li>
<li><strong>Username field:</strong> To assign a log to someone else, enter the email address they use to log into CORE.</li>
<li>If you have to manually enter large volumes of data into the bulk upload template, we recommend creating logs directly in the service instead. <%= govuk_link_to "Find out more about exporting your data", bulk_upload_lettings_log_path(id: "guidance", form: { year: @form.year }) %>.</li>
</ul>
<%= govuk_inset_text(text: "Upload separate files for general needs and supported housing logs for 2022/23 data.") %>
<h2 class="govuk-heading-s">Save your file</h2>
<ul class="govuk-list govuk-list--bullet">
<li>Save your file as a CSV.</li>
<li>Your file should now be ready to upload.</li>
</ul>
<%= f.govuk_submit class: "govuk-!-margin-top-7" %>
<% end %>
</div>
</div>

34
app/views/bulk_upload_sales_logs/forms/prepare_your_file_2022.html.erb

@ -1,34 +0,0 @@
<% content_for :before_content do %>
<%= govuk_back_link href: @form.back_path %>
<% end %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<%= form_with model: @form, scope: :form, url: bulk_upload_sales_log_path(id: "prepare-your-file"), method: :patch do |f| %>
<%= f.hidden_field :year %>
<span class="govuk-caption-l">Upload sales logs in bulk (<%= @form.year_combo %>)</span>
<h1 class="govuk-heading-l">Prepare your file</h1>
<h2 class="govuk-heading-s">Download template</h2>
<ul class="govuk-list govuk-list--bullet">
<li>Download and use <%= govuk_link_to "this template", @form.legacy_template_path %>.</li>
</ul>
<h2 class="govuk-heading-s">Create your file</h2>
<ul class="govuk-list govuk-list--bullet">
<li>Fill in the template with CORE data from your housing management system according to the <%= govuk_link_to "Sales #{@form.year_combo} Bulk Upload Specification", @form.specification_path %>.</li>
<li><strong>Username field:</strong> To assign a log to someone else, enter the email address they use to log into CORE.</li>
<li>If you have to manually enter large volumes of data into the bulk upload template, we recommend creating logs directly in the service instead. <%= govuk_link_to "Find out more about exporting your data", bulk_upload_sales_log_path(id: "guidance", form: { year: @form.year }) %>.</li>
</ul>
<h2 class="govuk-heading-s">Save your file</h2>
<ul class="govuk-list govuk-list--bullet">
<li>Save your file as a CSV.</li>
<li>Your file should now be ready to upload.</li>
</ul>
<%= f.govuk_submit %>
<% end %>
</div>
</div>

8
config/routes.rb

@ -39,14 +39,6 @@ Rails.application.routes.draw do
get "/service-moved", to: "maintenance#service_moved"
get "/service-unavailable", to: "maintenance#service_unavailable"
get "/download-22-23-lettings-form", to: "start#download_22_23_lettings_form"
get "/download-22-23-lettings-bulk-upload-template", to: "start#download_22_23_lettings_bulk_upload_template"
get "/download-22-23-lettings-bulk-upload-specification", to: "start#download_22_23_lettings_bulk_upload_specification"
get "/download-22-23-sales-form", to: "start#download_22_23_sales_form"
get "/download-22-23-sales-bulk-upload-template", to: "start#download_22_23_sales_bulk_upload_template"
get "/download-22-23-sales-bulk-upload-specification", to: "start#download_22_23_sales_bulk_upload_specification"
get "/download-23-24-lettings-form", to: "start#download_23_24_lettings_form"
get "/download-23-24-lettings-bulk-upload-template", to: "start#download_23_24_lettings_bulk_upload_template"
get "/download-23-24-lettings-bulk-upload-legacy-template", to: "start#download_23_24_lettings_bulk_upload_legacy_template"

BIN
public/files/2022_23_lettings_paper_form.pdf

Binary file not shown.

BIN
public/files/2022_23_sales_paper_form.pdf

Binary file not shown.

BIN
public/files/bulk-upload-lettings-specification-2022-23.xlsx

Binary file not shown.

BIN
public/files/bulk-upload-lettings-template-2022-23.xlsx

Binary file not shown.

BIN
public/files/bulk-upload-sales-specification-2022-23.xlsx

Binary file not shown.

BIN
public/files/bulk-upload-sales-template-2022-23.xlsx

Binary file not shown.

4
spec/components/bulk_upload_error_row_component_spec.rb

@ -46,7 +46,7 @@ RSpec.describe BulkUploadErrorRowComponent, type: :component do
end
it "renders the question for lettings" do
expected = "Is this letting a renewal?"
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
@ -83,7 +83,7 @@ RSpec.describe BulkUploadErrorRowComponent, type: :component do
let(:field) { :field_87 }
it "renders the question for sales" do
expected = "What is the full purchase price?"
expected = "Is this a staircasing transaction?"
result = render_inline(described_class.new(bulk_upload_errors:))
expect(result).to have_content(expected)
end

2
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 { 2022 }
year { 2023 }
identifier { SecureRandom.uuid }
sequence(:filename) { |n| "bulk-upload-#{n}.csv" }
needstype { 1 }

28
spec/features/bulk_upload_lettings_logs_spec.rb

@ -21,8 +21,12 @@ RSpec.describe "Bulk upload lettings log" do
# rubocop:disable RSpec/AnyInstance
context "when during crossover period" do
before do
allow(FeatureToggle).to receive(:force_crossover?).and_return(true)
end
it "shows journey with year option" do
Timecop.freeze(2022, 6, 1) do
Timecop.freeze(2023, 6, 1) do
visit("/lettings-logs")
expect(page).to have_link("Upload lettings logs in bulk")
click_link("Upload lettings logs in bulk")
@ -31,37 +35,27 @@ RSpec.describe "Bulk upload lettings log" do
click_button("Continue")
expect(page).to have_content("You must select a collection period to upload for")
choose("2022/2023")
choose("2023/2024")
click_button("Continue")
click_link("Back")
expect(page.find_field("form-year-2022-field")).to be_checked
click_button("Continue")
expect(page).to have_content("Upload lettings logs in bulk (2022/23)")
click_button("Continue")
expect(page).to have_content("What is the needs type?")
expect(page.find_field("form-year-2023-field")).to be_checked
click_button("Continue")
expect(page).to have_content("You must answer needs type")
choose("General needs")
expect(page).to have_content("Upload lettings logs in bulk (2023/24)")
click_button("Continue")
click_link("Back")
expect(page.find_field("form-needstype-1-field")).to be_checked
click_button("Continue")
expect(page).not_to have_content("What is the needs type?")
expect(page).to have_content("Upload lettings logs in bulk (2022/23)")
expect(page).to have_content("Upload lettings logs in bulk (2023/24)")
expect(page).to have_content("Upload your file")
click_button("Upload")
allow_any_instance_of(Forms::BulkUploadLettings::UploadYourFile).to receive(:`).and_return("not a csv")
expect(page).to have_content("Select which file to upload")
attach_file "file", file_fixture("2021_22_lettings_bulk_upload.xlsx")
attach_file "file", file_fixture("2023_24_lettings_bulk_upload.xlsx")
click_button("Upload")
allow_any_instance_of(Forms::BulkUploadLettings::UploadYourFile).to receive(:`).and_return("text/csv")

12
spec/features/bulk_upload_sales_logs_spec.rb

@ -21,6 +21,10 @@ RSpec.describe "Bulk upload sales log" do
# rubocop:disable RSpec/AnyInstance
context "when during crossover period" do
before do
allow(FeatureToggle).to receive(:force_crossover?).and_return(true)
end
it "shows journey with year option" do
Timecop.freeze(2023, 5, 1) do
visit("/sales-logs")
@ -31,15 +35,15 @@ RSpec.describe "Bulk upload sales log" do
click_button("Continue")
expect(page).to have_content("You must select a collection period to upload for")
choose("2022/2023")
choose("2023/2024")
click_button("Continue")
click_link("Back")
expect(page.find_field("form-year-2022-field")).to be_checked
expect(page.find_field("form-year-2023-field")).to be_checked
click_button("Continue")
expect(page).to have_content("Upload sales logs in bulk (2022/23)")
expect(page).to have_content("Upload sales logs in bulk (2023/24)")
click_button("Continue")
expect(page).to have_content("Upload your file")
@ -48,7 +52,7 @@ RSpec.describe "Bulk upload sales log" do
allow_any_instance_of(Forms::BulkUploadSales::UploadYourFile).to receive(:`).and_return("not a csv")
expect(page).to have_content("Select which file to upload")
attach_file "file", file_fixture("2021_22_lettings_bulk_upload.xlsx")
attach_file "file", file_fixture("2023_24_lettings_bulk_upload.xlsx")
click_button("Upload")
allow_any_instance_of(Forms::BulkUploadSales::UploadYourFile).to receive(:`).and_return("text/csv")

20
spec/fixtures/files/2021_22_lettings_bulk_upload.csv vendored

File diff suppressed because one or more lines are too long

BIN
spec/fixtures/files/2021_22_lettings_bulk_upload.xlsx vendored

Binary file not shown.

BIN
spec/fixtures/files/2021_22_lettings_bulk_upload_empty.xlsx vendored

Binary file not shown.

74
spec/fixtures/files/2022_23_lettings_bulk_upload.csv vendored

@ -1,74 +0,0 @@
Question,What is the letting type?,[BLANK],[BLANK],"Management group code
If supported housing","Scheme code
If supported housing",[BLANK],"What is the tenant code?
This is how you usually refer to this tenancy on your own systems",Is this a starter tenancy? ,What is the tenancy type? ,If 'Other' what is the tenancy type?,"What is the length of the fixed-term tenancy to the nearest year?
If fixed-term tenancy",Age of Person 1,Age of Person 2,Age of Person 3,Age of Person 4,Age of Person 5,Age of Person 6,Age of Person 7,Age of Person 8,Gender identity of Person 1,Gender identity of Person 2,Gender identity of Person 3,Gender identity of Person 4,Gender identity of Person 5,Gender identity of Person 6,Gender identity of Person 7,Gender identity of Person 8,Person 2's relationship to lead tenant,Person 3's relationship to lead tenant,Person 4's relationship to lead tenant,Person 5's relationship to lead tenant,Person 6's relationship to lead tenant,Person 7's relationship to lead tenant,Person 8's relationship to lead tenant,Working situation of Person 1,Working situation of Person 2,Working situation of Person 3,Working situation of Person 4,Working situation of Person 5,Working situation of Person 6,Working situation of Person 7,Working situation of Person 8,What is the lead tenant’s ethnic group? ,What is the lead tenant’s nationality? ,Does anybody in the household have links to the UK armed forces? ,Was the person seriously injured or ill as a result of serving in the UK armed forces? ,Is anybody in the household pregnant? ,Is the tenant likely to be receiving benefits related to housing? ,"How much of the household's income is from Universal Credit, state pensions or benefits? ","How much income does the household have in total?
Include any income after tax from employment, pensions, and Universal Credit
Don't include National Insurance (NI) contributions and tax, housing benefit, child benefit, or council tax support ",Do you know the household's income?,What is the tenant's main reason for the household leaving their last settled home? ,"If 'other', what was the main reason for leaving their last settled home?",[BLANK],"Disabled access needs
a) Fully wheelchair-accessible housing ","Disabled access needs
b) Wheelchair access to essential rooms ","Disabled access needs
c) Level access housing ","Disabled access needs
f) Other disabled access needs ","Disabled access needs
g) No disabled access needs ","Disabled access needs
h) Don’t know",Where was the household immediately before this letting? ,What is the local authority of the household's last settled home?,Part 1 of postcode of last settled home,Part 2 of postcode of last settled home ,Do you know the postcode of the last settled home?,How long has the household continuously lived in the local authority area of the new letting? ,How long has the household been on the local authority waiting list for the new letting? ,Was the tenant homeless directly before this tenancy?,Was the household given 'reasonable preference' by the local authority? ,"Reasonable Preference
They were homeless or about to lose their home (within 56 days) ","Reasonable Preference
They were living in unsanitary, overcrowded or unsatisfactory housing ","Reasonable Preference
They needed to move due to medical and welfare reasons (including disability) ","Reasonable Preference
They needed to move to avoid hardship to themselves or others ","Reasonable Preference
Don't know ",Was the letting made under Choice-Based Lettings (CBL)? ,Was the letting made under the Common Housing Register (CHR)? ,Was the letting made under the Common Allocation Policy (CAP)? ,What was the source of referral for this letting? ,How often does the household pay rent and other charges? ,What is the basic rent? ,What is the service charge? ,What is the personal service charge? ,What is the support charge? ,Total charge,"
If this is a care home,
how much does the household pay every [time period]?","Does the household pay rent or other charges for the accommodation?
If supported housing ","After the household has received any housing-related benefits, will they still need to pay basic rent and other charges? ",What do you expect the outstanding amount to be? ,What is the void or renewal day? - DD,What is the void or renewal month? - MM,What is the void or renewal year? - YYYY,What day were Major Repairs completed on? - DD,What month were Major Repairs completed on? - MM,What year were Major Repairs completed on? - YY,[BLANK],What day did the tenancy start? - DD,What month did the tenancy start? - MM,What year did the tenancy start? - YY,"Since becoming available, how many times has the property been previously offered? ","What is the property reference?
This is how you usually refer to this property on your own systems","How many bedrooms does the property have?
If general needs","What type of unit is the property?
If general needs","Which type of building is the property?
If general needs","Is the property built or adapted to wheelchair-user standards?
If general needs","What type was the property most recently let as?
If re-let",What is the reason for the property being vacant? ,"What is the local authority of the property?
If general needs","Part 1 of postcode of property
If general needs","Part 2 of postcode of property
If general needs",[BLANK],"Which organisation owns this property?
Organisation's CORE ID",Username Field,"Which organisation manages this property? 
Organisation's CORE ID",Is the person still serving in the UK armed forces? ,[BLANK],How often does the household receive income? ,"Is this letting in sheltered accommodation?
If supported housing",Does anybody in the household have a physical or mental health condition (or other illness) expected to last 12 months or more? ,"Vision, for example blindness or partial sight","Hearing, for example deatness or partial hearing","Mobility, for example walking short distances or climbing stairs","Dexterity, for example lifting and carrying objects, using a keyboard",Learning or understanding or concentrating,Memory,"Mental health, for example depression or anxiety",Stamina or breathing or fatigue,"Socially or behaviourally (e.g. associated with autism spectrum disorder (ASD) which includes Aspergers', or attention deficit hyperactivity disorder (ADHD))",Other illness or condition,Is this letting a London Affordable Rent letting?,Which type of Intermediate Rent is this letting?,Which 'Other' type of Intermediate Rent is this letting?,Has the tenant seen the DLUHC privacy notice? ,Is this a joint tenancy? ,Is this a renewal to the same tenant in the same property?,
Values,1 - 12,,,1 - 999,,,max 13 digits,1 - 2,2 - 7,Text ,1 - 99,15 - 120 or R,1 - 120 or R,,,,,,,"M, F, X or R",,,,,,,,"P,C,X or R",,,,,,,0 - 11,,,,,,,,1 - 19,"12 - 13, 17 - 19",1 - 6,1 - 3,,"1, 3, 6, 9",1 - 4,0 - 99999,1 - 4,"1 - 2, 4, 7 - 14, 16 - 20, 28 - 31 or 34 - 47",Text,,1 or null ,,,,,,"3- 4, 6 - 7, 9 - 10, 13 - 14, 18 - 19, 21 or 23 - 35",ONS CODE - E + 8 Digits,XXX(X),XXX,1 - 2,1 - 2 or 5 - 10,2 or 5 - 11,1 or 12,1 - 3,1 or null,,,,,1 or 2,,,"1 - 4, 7 - 10, 12 - 17",1 - 9,xxxx.xx,,,,,,1 or null,1 - 3,0 - 9999,1 - 31,1 - 12,19 - 23,1 - 31,1 - 12,13 - 23,,1 - 31,1 - 12,22-23,0+,12 Digits,1 - 7,"1, 2, 4 or 6 - 10",1 or 2,,1 - 4,"5, 6, 8 - 14, ",ONS CODE E + 9 digits,XXX(X),XXX,,Up to 7 digits,Username of CORE account this letting log should be assigned to,Up to 7 digits,3 - 6,,1 - 3,1 - 4,1 - 3,1 or null,,,,,,,,,,1 - 3,,Text,1,1 - 3,1 - 2,
Can be null?,No,,,"only if field 1 = 1, 3, 5, 7, 9 or 11",,,No,,,"Yes, if 9 is not 3","Yes, if 9 = 2, 3, 5 or 7",No,"Yes, if field 21, 28 and 36 are null","Yes, if 22, 29 and 37 are null","Yes, if 23, 30 and 38 are null","Yes, if 24, 31 and 39 are null","Yes, if 25, 32 and 40 are null","Yes, if 26, 33 and 41 are null","Yes, if 27, 34 and 42 are null", No,"Yes, if 13, 28 and 36 are null","Yes, if 14, 29 and 37 are null","Yes, if 15, 30 and 38 are null","Yes, if 16, 31 and 39 are null","Yes, if 17, 32 and 40 are null","Yes, if 18, 33 and 41 are null","Yes, if 19, 34 and 42 are null","Yes, if 13, 21 and 36 are null","Yes, if 14, 22 and 37 are null","Yes, if 15, 23 and 38 are null","Yes, if 16, 24 and 39 are null","Yes, if 17, 25 and 40 are null","Yes, if 18, 26 and 41 are null","Yes, if 19, 27 and 42 are null",No,"Yes, if 13, 21 and 28 are null","Yes, if 14, 22 and 29 are null","Yes, if 15, 23 and 30 are null","Yes, if 16, 24 and 31 are null","Yes, if 17, 25 and 32 are null","Yes, if 18, 26 and 33 are null","Yes, if 19, 27 and 34 are null",No,,,"Yes, must be null if 45 = 2 or 3;
no, if 45 = 1, 4 or 5",No,,,If 51 = 4,No,No,"Yes, if 52 is not 20",,"Selections are ((A or B or C)) - ((A, or B or C and F)) - ((F)) - ((G)) - ((H))",,,,,,No,,"Yes, if 65 = 1",,"Yes, if 63 and 64 contain full and valid entries",No,,,," If 69 = 1, select at least one of the 5 categories;
If 69 = 2 or 3, then Null.",,,,,No,,,,,Only if 85 or 86 = 1,Yes,,,Only if 85 or 86 = 1,Only if fields 80 - 84 and 86 are not null,Only if fields 80 - 85 are not null,Only if field 48 = 3 or 9 ,"If 87 = 2 or 3;
if 87 = 1, then a value must be entered",No,,,Yes,,,,No,,,"If the property is being let for the first time, enter 0.","Only if 1 = 2, 4, 6, 8, 10 or 12",,,,No,"Only if 1 = 2, 4, 6, 8, 10 or 12;
or 106 = 15 - 17",No,"Only if 1 = 2, 4, 6, 8, 10 or 12",,,,No,,No,"Yes, if 45 = 2, 3 or 6",,"Yes, if 50 = 1","Only if 1 = 1, 3, 5, 7, 9 or 11",No,Yes,,,,,,,,,,Only if 1 = 1 - 4 or 9 - 12.,Only if 1 = 1 - 8.,Only if 130 is not 3,No,No,Yes,
Bulk upload format and duplicate check,All lettings,Question removed from 22/23 onwards,,Supported housing only,,Question Removed from 2020/21,,,,,,Duplicate check field,,,,,,,,Duplicate check field,,,,,,,,,,,,,,,Duplicate check field,,,,,,,,,,,,,,,,,,,Question removed from 22/23 onwards,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Duplicate check field,,,,,,,,,,,Question removed from 22/23 onwards,Duplicate check fields,,,,Duplicate check field,General Needs lettings only,,,All lettings,General Needs lettings only,All lettings,General Needs lettings only,,,Question removed from 2020/21,Duplicate check field, “Username does not exist”. ,,,Question removed from 21/22 onwards,,Supported Housing lettings only.,,,,,,,,,,,,Affordable Rent Lettings only,Intermediate Rent Lettings only,,All lettings,All lettings,,
Bulk upload field number,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,
,1,,,,,,123,1,4,,2,55,54,,,,,,,F,,,,,,,,,,,,,,,1,,,,,,,,17,13,2,,2,3,4,,2,7,,,,,,,,,3,,,,2,1,2,1,3,,,,,,,,,16,4,1000,100,100,100,1300,,,,,,,,,,,,13,1,23,,,4,1,1,2,,,,EC1N,2TD,,3,,3,,,,,2,,,,,,,,,,,,,,1,2,2
,1,,,,,,123,1,2,,6,55,54,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,1,,,,,,123,1,2,,,55,54,,,,,,,"A",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13,1,23,,,,,,,,,,,,,123,,123,,,,,,,,,,,,,,,,,,,,,2,
Can't render this file because it has a wrong number of fields in line 72.

50
spec/fixtures/files/2023_24_lettings_bulk_upload.csv vendored

@ -0,0 +1,50 @@
,Setting up this lettings log,,,,,,,,,,,,,,,,,Property information,,,,,,,,,,,,,,,,,,,,,Tenancy information,,,,,,Household characteristics,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Household needs,,,,,,,,,,,,,,,,,,,,,Household situation,,,,,,,,,,,,,,,,,,,,"Income, benefits and outgoings",,,,,,,,,,,,,,
Question,Which organisation owns this property?,Which organisation manages this letting?,What is the CORE username of the account this letting log should be assigned to? ,What is the needs type?,What is the letting type?,Is this letting a renewal?,What is the tenancy start date? - day DD,What is the tenancy start date? - month MM,What is the tenancy start date? - year YY,Is this a London Affordable Rent letting?,Which type of Intermediate Rent is this letting?,Which 'Other' type of Intermediate Rent is this letting?,What is the tenant code?,What is the property reference?,What management group does this letting belong to?,What scheme does this letting belong to?,Which location is this letting for?,"If known, provide this property’s UPRN",Address Line 1,Address Line 2,Town or city,County,Part 1 of the property's postcode,Part 2 of the property's postcode,What is the property's local authority?,What type was the property most recently let as?,What is the reason for the property being vacant?,How many times was the property offered between becoming vacant and this letting?,What type of unit is the property?,Which type of building is the property?,Is the property built or adapted to wheelchair-user standards?,How many bedrooms does the property have?,What is the void date? - day DD,What is the void date? - month MM,What is the void date? - year YYYY,What date were any major repairs completed on? - day DD,What date were any major repairs completed on? - month MM,What date were any major repairs completed on? - year YY,Is this a joint tenancy?,Is this a starter tenancy?,What is the type of tenancy?,"If 'Other', what is the type of tenancy?",What is the length of the fixed-term tenancy to the nearest year?,Is this letting in sheltered accommodation?,Has the tenant seen the DLUHC privacy notice?,What is the lead tenant’s age?,Which of these best describes the lead tenant’s gender identity? ,Which of these best describes the lead tenant's ethnic background?,What is the lead tenant’s nationality?,Which of these best describes the lead tenant’s working situation?,What is person 2's relationship to the lead tenant?,What is person 2's age?,Which of these best describes person 2's gender identity?,Which of these best describes person 2's working situation?,What is person 3's relationship to the lead tenant?,What is person 3's age?,Which of these best describes person 3's gender identity?,Which of these best describes person 3's working situation?,What is person 4's relationship to the lead tenant?,What is person 4's age?,Which of these best describes person 4's gender identity?,Which of these best describes person 4's working situation?,What is person 5's relationship to the lead tenant?,What is person 5's age?,Which of these best describes person 5's gender identity?,Which of these best describes person 5's working situation?,What is person 6's relationship to the lead tenant?,What is person 6's age?,Which of these best describes person 6's gender identity?,Which of these best describes person 6's working situation?,What is person 7's relationship to the lead tenant?,What is person 7's age?,Which of these best describes person 7's gender identity?,Which of these best describes person 7's working situation?,What is person 8's relationship to the lead tenant?,What is person 8's age?,Which of these best describes person 8's gender identity?,Which of these best describes person 8's working situation?,Does anybody in the household have links to the UK armed forces?,Is this person still serving in the UK armed forces?,Was this person seriously injured or ill as a result of serving in the UK armed forces?,Is anybody in the household pregnant?,"Disabled access needs
a) Fully wheelchair-accessible housing","Disabled access needs
b) Wheelchair access to essential rooms","Disabled access needs
c) Level access housing","Disabled access needs
f) Other disabled access needs","Disabled access needs
g) No disabled access needs","Disabled access needs
h) Don’t know",Does anybody in the household have a physical or mental health condition (or other illness) expected to last 12 months or more?,Does this person's condition affect their dexterity?,Does this person's condition affect their learning or understanding or concentrating?,Does this person's condition affect their hearing?,Does this person's condition affect their memory?,Does this person's condition affect their mental health?,Does this person's condition affect their mobility?,Does this person's condition affect them socially or behaviourally?,Does this person's condition affect their stamina or breathing or fatigue?,Does this person's condition affect their vision?,Does this person's condition affect them in another way?,How long has the household continuously lived in the local authority area of the new letting?,How long has the household been on the local authority waiting list for the new letting?,What is the tenant’s main reason for the household leaving their last settled home?,"If 'Other', what was the main reason for leaving their last settled home?",Where was the household immediately before this letting?,Did the household experience homelessness immediately before this letting?,Do you know the postcode of the household's last settled home?,Part 1 of postcode of last settled home,Part 2 of postcode of last settled home,What is the local authority of the household's last settled home?,Was the household given 'reasonable preference' by the local authority?,"Reasonable preference reason
They were homeless or about to lose their home (within 56 days)","Reasonable preference reason
They were living in unsanitary, overcrowded or unsatisfactory housing","Reasonable preference reason
They needed to move due to medical and welfare reasons (including disability)","Reasonable preference reason
They needed to move to avoid hardship to themselves or others","Reasonable preference reason
Don't know",Was the letting made under Choice-Based Lettings (CBL)?,Was the letting made under the Common Allocation Policy (CAP)? ,Was the letting made under the Common Housing Register (CHR)?,What was the source of referral for this letting?,Do you know the household's combined total income after tax?,How often does the household receive income?,How much income does the household have in total?,Is the tenant likely to be receiving any of these housing-related benefits?,"How much of the household's income is from Universal Credit, state pensions or benefits?",Does the household pay rent or other charges for the accommodation?,How often does the household pay rent and other charges?,"If this is a care home, how much does the household pay every [time period]?",What is the basic rent?,What is the service charge?,What is the personal service charge?,What is the support charge?,Total charge,"After the household has received any housing-related benefits, will they still need to pay for rent and charges?",What do you expect the outstanding amount to be?
Additional info,Organisation's CORE ID,,"If using new core then this will be the email address. If left empty, the letting log will be assigned to the account used to upload the log.","General needs housing includes both self-contained and shared housing without support or specific adaptations. Supported housing includes direct access hostels, group homes, residential care and nursing homes.",,This is a letting to the same tenant in the same property,,,,,,,This is how you usually refer to this tenancy on your own systems,This is how you usually refer to this property on your own systems,Provide management code if you have one,"Provide scheme code, include the 'S' at the beginning if it has one",Provide location code if you have one,"The UPRN is the Unique Property Reference Number. It's created by the Ordnance Survey so it's a unique number system used across all housing providers, all sectors (i.e. not just social housing) and all across the UK.",,,,,,,,,,"Do not include the offer that led to this letting.
This is after the last tenancy ended. If the property is being offered for let for the first time, enter 0.",,,,"If shared accommodation, enter the number of bedrooms occupied by this household. A bedsit has 1 bedroom.","This is the date the property became available to let. For a re-let, it's the day after the previous tenant's contract ends. For a new build, conversion, acquisition or lease it's the day after the provider legally took over possession or management.",,,"Major repairs are works that could not be reasonably carried out with a tenant living at the property. For example, structural repairs.",,,,Also known as an ‘introductory period’,"Fixed-term tenancies are for a set time (up to 20 years). Licence agreements are on a rolling basis, mainly for supported housing. Local authorities mostly provide secure tenancies, and housing associations mostly provide assured (ASTs).",,Not including starter or introductory period,,Make sure the tenant has seen the attached privacy notice before completing this log,"This is the household member who does the most paid work. If several people do the same paid work, it's the oldest household member.",,,,,A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education.,Mark children under 1 as 1.,,,A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education.,Mark children under 1 as 1.,,,A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education.,Mark children under 1 as 1.,,,A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education.,Mark children under 1 as 1.,,,A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education.,Mark children under 1 as 1.,,,A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education.,Mark children under 1 as 1.,,,A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education.,Mark children under 1 as 1.,,,"Excluding national service.
If several household members have these links, answer for regular first. If no regular, answer for reserve. If no reserve, answer for spouses or civil partners.",,,,,,,,,,,"For example, lifting and carrying objects, or using a keyboard",,"For example, deafness or partial hearing",,"For example, depression or anxiety",,"Anything associated with autism spectrum disorder (ASD), including Asperger’s or attention deficit hyperactivity disorder (ADHD)",,"For example, blindness or partial sight",,,,"‘Last settled home' means last long-standing home. For tenants who had temporary accommodation or slept rough, it's where they lived previously.",,,,,,,,Social housing 'reasonable preference' is also known as 'priority need',,,,,,,,,,,,"Include any income after tax from employment, pensions, and Universal Credit. Don't include National Insurance (NI) contributions and tax, housing benefit, child benefit, or council tax support.",,,"If rent is charged on the property then answer Yes, even if tenants do not pay it themselves.",,,"Amount paid before any service charges, for example hot water or cleaning. Households may get household benefits towards basic rent.","For example, cleaning. Households may get household benefits towards service charge",For example heating or hot water. This doesn’t include housing benefit or Universal Credit.,Any support service charges included in the tenancy agreement,Unnecessary for new CORE users,,Approximate figure only
Values,Numeric,,"Email format if using new CORE.
Alphanumeric, except for commas if using old CORE.",1 - 2,1 - 12,1 - 2,1 - 31,1 - 12,23 - 24,1 - 3,,Text,"Alphanumeric, max 13 characters","Alphanumeric, max 12 characters",1 - 999,Alphanumeric,1 - 999,Numeric,Alphanumeric,,Text,,XX(XX),XXX,"ONS CODE: Alphanumeric, 9 characters beginning with 'E'",1 - 3 or 5 - 8,"5 - 6, or 8 - 20",0+,"1 - 2, 4 or 6 - 10",1 - 2,,1 - 7,1 - 31,1 - 12,20 - 24,1 - 31,1 - 12,14 - 24,1 - 3,1 - 2,2 - 7,Text,1 - 99,1 - 5,1,16 - 120 or R,"F, M, X or R",1 - 19,"12 - 13, 17 - 21",0 - 10,"P, C, X or R","Numeric, range 1 - 120 or text (upper case 'R')
Must be >= 16 if working situation = 1 - 8 or 0
Must be <16 if working situation = 9","F, M, X or R",0 - 10,"P, C, X or R","Numeric, range 1 - 120 or text (upper case 'R')
Must be >= 16 if working situation = 1 - 8 or 0
Must be <16 if working situation = 9","F, M, X or R",0 - 10,"P, C, X or R","Numeric, range 1 - 120 or text (upper case 'R')
Must be >= 16 if working situation = 1 - 8 or 0
Must be <16 if working situation = 9","F, M, X or R",0 - 10,"P, C, X or R","Numeric, range 1 - 120 or text (upper case 'R')
Must be >= 16 if working situation = 1 - 8 or 0
Must be <16 if working situation = 9","F, M, X or R",0 - 10,"P, C, X or R","Numeric, range 1 - 120 or text (upper case 'R')
Must be >= 16 if working situation = 1 - 8 or 0
Must be <16 if working situation = 9","F, M, X or R",0 - 10,"P, C, X or R","Numeric, range 1 - 120 or text (upper case 'R')
Must be >= 16 if working situation = 1 - 8 or 0
Must be <16 if working situation = 9","F, M, X or R",0 - 10,"P, C, X or R","Numeric, range 1 - 120 or text (upper case 'R')
Must be >= 16 if working situation = 1 - 8 or 0
Must be <16 if working situation = 9","F, M, X or R",0 - 10,1 - 6,3 - 6,1 - 3,,1 or empty,,,,,,1 - 3,1 or empty,,,,,,,,,,1 - 2 or 5 - 10,2 or 5 - 10,"1 - 2, 4, 8 - 14, 16 - 20, 28 - 31 or 34 - 49",Text,"3 - 4, 6 - 7, 9 - 10, 13 - 14, 18 - 19, 21 or 23 - 37",1 or 11,1 - 2,XX(XX),XXX,"ONS CODE: Alphanumeric, 9 characters beginning with 'E'",1 - 3,1 or empty,,,,,1 - 2,,,"1 - 4, 7 - 10, 12 - 17",1 - 3,,0 - 99999,"1, 3, 6, 9 or 10",1 - 4,0 - 1,1 - 10,xxxx.xx,,,,,,1 - 3,xxxx.xx
Can be empty?,No,,Yes,No,,,No,,,"Yes, if letting type is not an Affordable Rent letting (if field 5 = 1 - 4 or 9 - 12)","Yes, if letting type is not an Intermediate Rent letting (if field 5 = 1 - 8)","Yes, if letting type is not an Intermediate Rent letting (if field 5 = 1 - 8) or if 'Other intermediate rent product' is not selected for type of Intermediate Rent (if field 11 is not 3)",Yes,,"Yes, if letting is general needs (if field 4 = 1) or if location code is provided (if field 17 is not empty)","Yes, if letting is general needs (if field 4 = 1)","Yes, if letting is general needs (if field 4 = 1) or if management code is provided (if field 15 is not empty)","Yes, if letting is supported housing (if field 4 = 2) or if the property's postcode is not empty (if fields 23 and 24 contain full and valid entries)","Yes, if letting is supported housing (if field 4 = 2) or if property's UPRN and local authority are known (if fields 18 and 25 are not empty)",Yes,"Yes, if letting is supported housing (if field 4 = 2) or if property's UPRN and local authority are known (if fields 18 and 25 are not empty)",Yes,"Yes, if letting is supported housing (if field 4 = 2) or if property's UPRN and local authority are known (if fields 18 and 25 are not empty)",,"Yes, if letting is supported housing (if field 4 = 2)","Yes, if letting is a renewal (if field 6 = 1) or a first-time let (if field 27 = 15 - 17)","Yes, if letting is a renewal (if field 6 = 1)",,"Yes, if letting is supported housing (if field 4 = 2)",,,,"Yes, if letting is a renewal (if field 6 = 1)",,,Yes,,,No,,,"Yes, if 'Other' is not selected for tenancy type (if field 41 is not 3)","Yes, if letting is not a fixed-term tenancy (if field 41 = 2, 3, 5 or 7)","Yes, if letting is general needs (if field 4 = 1)",No,No,,,,,"Yes, if the other fields about this person (fields 52, 53 and 54) are also empty","Yes, if the other fields about this person (fields 51, 53 and 54) are also empty","Yes, if the other fields about this person (fields 51, 52 and 54) are also empty","Yes, if the other fields about this person (fields 51, 52 and 53) are also empty","Yes, if the other fields about this person (fields 56, 57 and 58) are also empty","Yes, if the other fields about this person (fields 55, 57 and 58) are also empty","Yes, if the other fields about this person (fields 55, 56 and 58) are also empty","Yes, if the other fields about this person (fields 55, 56 and 57) are also empty","Yes, if the other fields about this person (fields 60, 61 and 62) are also empty","Yes, if the other fields about this person (fields 59, 61 and 62) are also empty","Yes, if the other fields about this person (fields 59, 60 and 62) are also empty","Yes, if the other fields about this person (fields 59, 60 and 61) are also empty","Yes, if the other fields about this person (fields 64, 65 and 66) are also empty","Yes, if the other fields about this person (fields 63, 65 and 66) are also empty","Yes, if the other fields about this person (fields 63, 64 and 66) are also empty","Yes, if the other fields about this person (fields 63, 64 and 65) are also empty","Yes, if the other fields about this person (fields 68, 69 and 70) are also empty","Yes, if the other fields about this person (fields 67, 69 and 70) are also empty","Yes, if the other fields about this person (fields 67, 68 and 70) are also empty","Yes, if the other fields about this person (fields 67, 68 and 69) are also empty","Yes, if the other fields about this person (fields 72, 73 and 74) are also empty","Yes, if the other fields about this person (fields 71, 73 and 74) are also empty","Yes, if the other fields about this person (fields 71, 72 and 74) are also empty","Yes, if the other fields about this person (fields 71, 72 and 73) are also empty","Yes, if the other fields about this person (fields 76, 77 and 78) are also empty","Yes, if the other fields about this person (fields 75, 77 and 78) are also empty","Yes, if the other fields about this person (fields 75, 76 and 78) are also empty","Yes, if the other fields about this person (fields 75, 76 and 77) are also empty",No,"Yes, if no one in the household is a current or former regular (if field 79 is not 1)","Yes, if no one in the household is a current or former regular or reserve (if field 79 = 2, 3, 5 or 6)",No,"Yes, if no household members have access needs or if it is unknown (if field 87 or 88 = 1)",,,,"Yes, if a household member has an access need (if at least one of fields 83, 84, 85 and 86 = 1)",,No,"Yes, if no one in the household has a physical or mental health condition (if field 89 is 2 or 3).
If someone in the household does have such a condition (if field 89 = 1), then at least 1 of these fields must be 1.",,,,,,,,,,No,"Yes, if letting is a renewal (if field 6 = 1)",No,"Yes, if 'Other' is not selected for reason for leaving last settled home (if field 102 is not 20)","Yes, if letting is a renewal (if field 6 = 1)",No,,"Yes, if postcode of household's last settled home is not known (if 106 = 2)",,Yes,No,"If household was given 'reasonable preference' (if field 110 = 1), at least one of these fields must be 1.
If household was not given 'reasonable preference' (if field 110 = 2 or 3), these fields will be ignored.",,,,,No,,,"Yes, if letting is a renewal (if field 6 = 1)",No,"Yes, if household's income is unknown (if field 120 = 2 or 3)",,No,,"Yes, if all rent and accommodation charges are provided (if fields 127 - 132 are not empty)",No,"Yes, if accommodation is not a care home (if field 125 = 1) and all rent and accommodation charges are provided (if fields 128 - 132 are not empty)","Yes, if the household does not pay rent (if field 125 = 1) or if the accommodation is not a care home (if field 127 is empty)",Yes,,,"Yes, if submitting data to new CORE, if the household does not pay rent (if field 125 = 1) or if the accommodation is not a care home (if field 127 is empty)","Yes, if the household doesn't receive housing benefits, or if it is unknown (if field 123 = 3, 9 or 10)","Yes, if the household does not need to pay rent/charges after receiving housing benefits (if field133 = 2 or 3)"
Type of letting the question applies to,,,,,,,,,,Affordable Rent only,Intermediate Rent only,,,,Supported housing only,,,General needs only,,,,,,,,,,,General needs only,,,,,,,,,,,,,,,Supported housing only,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Supported housing only,,,,,,,,,
Duplicate check field?,Yes,,,,,,Yes,,,,,,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Yes,,,,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Bulk upload field number,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134
,3,3,,1,1,1,10,10,23,,2,,54,,,,,,123,123,123,123,A1,1AA,E07000004,1,6,0,1,1,1,1,1,10,22,1,1,22,1,1,1,,1,1,1,20,M,3,4,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,2,0,,1,,,,,,,,,,,,,,24,,,4,40,1,2,,,EC1N,2TD,,,3,,3,,,,,2,,,,,,,,,,,,,,1,2,2
1 Setting up this lettings log Property information Tenancy information Household characteristics Household needs Household situation Income, benefits and outgoings
2 Question Which organisation owns this property? Which organisation manages this letting? What is the CORE username of the account this letting log should be assigned to? What is the needs type? What is the letting type? Is this letting a renewal? What is the tenancy start date? - day DD What is the tenancy start date? - month MM What is the tenancy start date? - year YY Is this a London Affordable Rent letting? Which type of Intermediate Rent is this letting? Which 'Other' type of Intermediate Rent is this letting? What is the tenant code? What is the property reference? What management group does this letting belong to? What scheme does this letting belong to? Which location is this letting for? If known, provide this property’s UPRN Address Line 1 Address Line 2 Town or city County Part 1 of the property's postcode Part 2 of the property's postcode What is the property's local authority? What type was the property most recently let as? What is the reason for the property being vacant? How many times was the property offered between becoming vacant and this letting? What type of unit is the property? Which type of building is the property? Is the property built or adapted to wheelchair-user standards? How many bedrooms does the property have? What is the void date? - day DD What is the void date? - month MM What is the void date? - year YYYY What date were any major repairs completed on? - day DD What date were any major repairs completed on? - month MM What date were any major repairs completed on? - year YY Is this a joint tenancy? Is this a starter tenancy? What is the type of tenancy? If 'Other', what is the type of tenancy? What is the length of the fixed-term tenancy to the nearest year? Is this letting in sheltered accommodation? Has the tenant seen the DLUHC privacy notice? What is the lead tenant’s age? Which of these best describes the lead tenant’s gender identity? Which of these best describes the lead tenant's ethnic background? What is the lead tenant’s nationality? Which of these best describes the lead tenant’s working situation? What is person 2's relationship to the lead tenant? What is person 2's age? Which of these best describes person 2's gender identity? Which of these best describes person 2's working situation? What is person 3's relationship to the lead tenant? What is person 3's age? Which of these best describes person 3's gender identity? Which of these best describes person 3's working situation? What is person 4's relationship to the lead tenant? What is person 4's age? Which of these best describes person 4's gender identity? Which of these best describes person 4's working situation? What is person 5's relationship to the lead tenant? What is person 5's age? Which of these best describes person 5's gender identity? Which of these best describes person 5's working situation? What is person 6's relationship to the lead tenant? What is person 6's age? Which of these best describes person 6's gender identity? Which of these best describes person 6's working situation? What is person 7's relationship to the lead tenant? What is person 7's age? Which of these best describes person 7's gender identity? Which of these best describes person 7's working situation? What is person 8's relationship to the lead tenant? What is person 8's age? Which of these best describes person 8's gender identity? Which of these best describes person 8's working situation? Does anybody in the household have links to the UK armed forces? Is this person still serving in the UK armed forces? Was this person seriously injured or ill as a result of serving in the UK armed forces? Is anybody in the household pregnant? Disabled access needs a) Fully wheelchair-accessible housing Disabled access needs b) Wheelchair access to essential rooms Disabled access needs c) Level access housing Disabled access needs f) Other disabled access needs Disabled access needs g) No disabled access needs Disabled access needs h) Don’t know Does anybody in the household have a physical or mental health condition (or other illness) expected to last 12 months or more? Does this person's condition affect their dexterity? Does this person's condition affect their learning or understanding or concentrating? Does this person's condition affect their hearing? Does this person's condition affect their memory? Does this person's condition affect their mental health? Does this person's condition affect their mobility? Does this person's condition affect them socially or behaviourally? Does this person's condition affect their stamina or breathing or fatigue? Does this person's condition affect their vision? Does this person's condition affect them in another way? How long has the household continuously lived in the local authority area of the new letting? How long has the household been on the local authority waiting list for the new letting? What is the tenant’s main reason for the household leaving their last settled home? If 'Other', what was the main reason for leaving their last settled home? Where was the household immediately before this letting? Did the household experience homelessness immediately before this letting? Do you know the postcode of the household's last settled home? Part 1 of postcode of last settled home Part 2 of postcode of last settled home What is the local authority of the household's last settled home? Was the household given 'reasonable preference' by the local authority? Reasonable preference reason They were homeless or about to lose their home (within 56 days) Reasonable preference reason They were living in unsanitary, overcrowded or unsatisfactory housing Reasonable preference reason They needed to move due to medical and welfare reasons (including disability) Reasonable preference reason They needed to move to avoid hardship to themselves or others Reasonable preference reason Don't know Was the letting made under Choice-Based Lettings (CBL)? Was the letting made under the Common Allocation Policy (CAP)? Was the letting made under the Common Housing Register (CHR)? What was the source of referral for this letting? Do you know the household's combined total income after tax? How often does the household receive income? How much income does the household have in total? Is the tenant likely to be receiving any of these housing-related benefits? How much of the household's income is from Universal Credit, state pensions or benefits? Does the household pay rent or other charges for the accommodation? How often does the household pay rent and other charges? If this is a care home, how much does the household pay every [time period]? What is the basic rent? What is the service charge? What is the personal service charge? What is the support charge? Total charge After the household has received any housing-related benefits, will they still need to pay for rent and charges? What do you expect the outstanding amount to be?
3 Additional info Organisation's CORE ID If using new core then this will be the email address. If left empty, the letting log will be assigned to the account used to upload the log. General needs housing includes both self-contained and shared housing without support or specific adaptations. Supported housing includes direct access hostels, group homes, residential care and nursing homes. This is a letting to the same tenant in the same property This is how you usually refer to this tenancy on your own systems This is how you usually refer to this property on your own systems Provide management code if you have one Provide scheme code, include the 'S' at the beginning if it has one Provide location code if you have one The UPRN is the Unique Property Reference Number. It's created by the Ordnance Survey so it's a unique number system used across all housing providers, all sectors (i.e. not just social housing) and all across the UK. Do not include the offer that led to this letting. This is after the last tenancy ended. If the property is being offered for let for the first time, enter 0. If shared accommodation, enter the number of bedrooms occupied by this household. A bedsit has 1 bedroom. This is the date the property became available to let. For a re-let, it's the day after the previous tenant's contract ends. For a new build, conversion, acquisition or lease it's the day after the provider legally took over possession or management. Major repairs are works that could not be reasonably carried out with a tenant living at the property. For example, structural repairs. Also known as an ‘introductory period’ Fixed-term tenancies are for a set time (up to 20 years). Licence agreements are on a rolling basis, mainly for supported housing. Local authorities mostly provide secure tenancies, and housing associations mostly provide assured (ASTs). Not including starter or introductory period Make sure the tenant has seen the attached privacy notice before completing this log This is the household member who does the most paid work. If several people do the same paid work, it's the oldest household member. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. Excluding national service. If several household members have these links, answer for regular first. If no regular, answer for reserve. If no reserve, answer for spouses or civil partners. For example, lifting and carrying objects, or using a keyboard For example, deafness or partial hearing For example, depression or anxiety Anything associated with autism spectrum disorder (ASD), including Asperger’s or attention deficit hyperactivity disorder (ADHD) For example, blindness or partial sight ‘Last settled home' means last long-standing home. For tenants who had temporary accommodation or slept rough, it's where they lived previously. Social housing 'reasonable preference' is also known as 'priority need' Include any income after tax from employment, pensions, and Universal Credit. Don't include National Insurance (NI) contributions and tax, housing benefit, child benefit, or council tax support. If rent is charged on the property then answer Yes, even if tenants do not pay it themselves. Amount paid before any service charges, for example hot water or cleaning. Households may get household benefits towards basic rent. For example, cleaning. Households may get household benefits towards service charge For example heating or hot water. This doesn’t include housing benefit or Universal Credit. Any support service charges included in the tenancy agreement Unnecessary for new CORE users Approximate figure only
4 Values Numeric Email format if using new CORE. Alphanumeric, except for commas if using old CORE. 1 - 2 1 - 12 1 - 2 1 - 31 1 - 12 23 - 24 1 - 3 Text Alphanumeric, max 13 characters Alphanumeric, max 12 characters 1 - 999 Alphanumeric 1 - 999 Numeric Alphanumeric Text XX(XX) XXX ONS CODE: Alphanumeric, 9 characters beginning with 'E' 1 - 3 or 5 - 8 5 - 6, or 8 - 20 0+ 1 - 2, 4 or 6 - 10 1 - 2 1 - 7 1 - 31 1 - 12 20 - 24 1 - 31 1 - 12 14 - 24 1 - 3 1 - 2 2 - 7 Text 1 - 99 1 - 5 1 16 - 120 or R F, M, X or R 1 - 19 12 - 13, 17 - 21 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 1 - 6 3 - 6 1 - 3 1 or empty 1 - 3 1 or empty 1 - 2 or 5 - 10 2 or 5 - 10 1 - 2, 4, 8 - 14, 16 - 20, 28 - 31 or 34 - 49 Text 3 - 4, 6 - 7, 9 - 10, 13 - 14, 18 - 19, 21 or 23 - 37 1 or 11 1 - 2 XX(XX) XXX ONS CODE: Alphanumeric, 9 characters beginning with 'E' 1 - 3 1 or empty 1 - 2 1 - 4, 7 - 10, 12 - 17 1 - 3 0 - 99999 1, 3, 6, 9 or 10 1 - 4 0 - 1 1 - 10 xxxx.xx 1 - 3 xxxx.xx
5 Can be empty? No Yes No No Yes, if letting type is not an Affordable Rent letting (if field 5 = 1 - 4 or 9 - 12) Yes, if letting type is not an Intermediate Rent letting (if field 5 = 1 - 8) Yes, if letting type is not an Intermediate Rent letting (if field 5 = 1 - 8) or if 'Other intermediate rent product' is not selected for type of Intermediate Rent (if field 11 is not 3) Yes Yes, if letting is general needs (if field 4 = 1) or if location code is provided (if field 17 is not empty) Yes, if letting is general needs (if field 4 = 1) Yes, if letting is general needs (if field 4 = 1) or if management code is provided (if field 15 is not empty) Yes, if letting is supported housing (if field 4 = 2) or if the property's postcode is not empty (if fields 23 and 24 contain full and valid entries) Yes, if letting is supported housing (if field 4 = 2) or if property's UPRN and local authority are known (if fields 18 and 25 are not empty) Yes Yes, if letting is supported housing (if field 4 = 2) or if property's UPRN and local authority are known (if fields 18 and 25 are not empty) Yes Yes, if letting is supported housing (if field 4 = 2) or if property's UPRN and local authority are known (if fields 18 and 25 are not empty) Yes, if letting is supported housing (if field 4 = 2) Yes, if letting is a renewal (if field 6 = 1) or a first-time let (if field 27 = 15 - 17) Yes, if letting is a renewal (if field 6 = 1) Yes, if letting is supported housing (if field 4 = 2) Yes, if letting is a renewal (if field 6 = 1) Yes No Yes, if 'Other' is not selected for tenancy type (if field 41 is not 3) Yes, if letting is not a fixed-term tenancy (if field 41 = 2, 3, 5 or 7) Yes, if letting is general needs (if field 4 = 1) No No Yes, if the other fields about this person (fields 52, 53 and 54) are also empty Yes, if the other fields about this person (fields 51, 53 and 54) are also empty Yes, if the other fields about this person (fields 51, 52 and 54) are also empty Yes, if the other fields about this person (fields 51, 52 and 53) are also empty Yes, if the other fields about this person (fields 56, 57 and 58) are also empty Yes, if the other fields about this person (fields 55, 57 and 58) are also empty Yes, if the other fields about this person (fields 55, 56 and 58) are also empty Yes, if the other fields about this person (fields 55, 56 and 57) are also empty Yes, if the other fields about this person (fields 60, 61 and 62) are also empty Yes, if the other fields about this person (fields 59, 61 and 62) are also empty Yes, if the other fields about this person (fields 59, 60 and 62) are also empty Yes, if the other fields about this person (fields 59, 60 and 61) are also empty Yes, if the other fields about this person (fields 64, 65 and 66) are also empty Yes, if the other fields about this person (fields 63, 65 and 66) are also empty Yes, if the other fields about this person (fields 63, 64 and 66) are also empty Yes, if the other fields about this person (fields 63, 64 and 65) are also empty Yes, if the other fields about this person (fields 68, 69 and 70) are also empty Yes, if the other fields about this person (fields 67, 69 and 70) are also empty Yes, if the other fields about this person (fields 67, 68 and 70) are also empty Yes, if the other fields about this person (fields 67, 68 and 69) are also empty Yes, if the other fields about this person (fields 72, 73 and 74) are also empty Yes, if the other fields about this person (fields 71, 73 and 74) are also empty Yes, if the other fields about this person (fields 71, 72 and 74) are also empty Yes, if the other fields about this person (fields 71, 72 and 73) are also empty Yes, if the other fields about this person (fields 76, 77 and 78) are also empty Yes, if the other fields about this person (fields 75, 77 and 78) are also empty Yes, if the other fields about this person (fields 75, 76 and 78) are also empty Yes, if the other fields about this person (fields 75, 76 and 77) are also empty No Yes, if no one in the household is a current or former regular (if field 79 is not 1) Yes, if no one in the household is a current or former regular or reserve (if field 79 = 2, 3, 5 or 6) No Yes, if no household members have access needs or if it is unknown (if field 87 or 88 = 1) Yes, if a household member has an access need (if at least one of fields 83, 84, 85 and 86 = 1) No Yes, if no one in the household has a physical or mental health condition (if field 89 is 2 or 3). If someone in the household does have such a condition (if field 89 = 1), then at least 1 of these fields must be 1. No Yes, if letting is a renewal (if field 6 = 1) No Yes, if 'Other' is not selected for reason for leaving last settled home (if field 102 is not 20) Yes, if letting is a renewal (if field 6 = 1) No Yes, if postcode of household's last settled home is not known (if 106 = 2) Yes No If household was given 'reasonable preference' (if field 110 = 1), at least one of these fields must be 1. If household was not given 'reasonable preference' (if field 110 = 2 or 3), these fields will be ignored. No Yes, if letting is a renewal (if field 6 = 1) No Yes, if household's income is unknown (if field 120 = 2 or 3) No Yes, if all rent and accommodation charges are provided (if fields 127 - 132 are not empty) No Yes, if accommodation is not a care home (if field 125 = 1) and all rent and accommodation charges are provided (if fields 128 - 132 are not empty) Yes, if the household does not pay rent (if field 125 = 1) or if the accommodation is not a care home (if field 127 is empty) Yes Yes, if submitting data to new CORE, if the household does not pay rent (if field 125 = 1) or if the accommodation is not a care home (if field 127 is empty) Yes, if the household doesn't receive housing benefits, or if it is unknown (if field 123 = 3, 9 or 10) Yes, if the household does not need to pay rent/charges after receiving housing benefits (if field133 = 2 or 3)
6 Type of letting the question applies to Affordable Rent only Intermediate Rent only Supported housing only General needs only General needs only Supported housing only Supported housing only
7 Duplicate check field? Yes Yes Yes Yes Yes
8 Bulk upload field number 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
9 3 3 1 1 1 10 10 23 2 54 123 123 123 123 A1 1AA E07000004 1 6 0 1 1 1 1 1 10 22 1 1 22 1 1 1 1 1 1 20 M 3 4 1 1 1 2 0 1 24 4 40 1 2 EC1N 2TD 3 3 2 1 2 2

BIN
spec/fixtures/files/2023_24_lettings_bulk_upload.xlsx vendored

Binary file not shown.

1
spec/fixtures/files/2022_23_lettings_bulk_upload_empty_with_headers.csv → spec/fixtures/files/2023_24_lettings_bulk_upload_invalid.csv vendored

@ -47,3 +47,4 @@ If household was not given 'reasonable preference' (if field 110 = 2 or 3), thes
Type of letting the question applies to,,,,,,,,,,Affordable Rent only,Intermediate Rent only,,,,Supported housing only,,,General needs only,,,,,,,,,,,General needs only,,,,,,,,,,,,,,,Supported housing only,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Supported housing only,,,,,,,,,
Duplicate check field?,Yes,,,,,,Yes,,,,,,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Yes,,,,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Bulk upload field number,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134
,3,3,,1,1,1,,10,23,,2,,123,,,,,,123,123,123,123,A1,1AA,E07000004,1,6,0,1,1,1,1,1,10,22,1,1,22,1,1,1,,1,1,1,20,M,3,4,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,2,0,,1,,,,,,,,,,,,,,24,,,4,40,1,2,,,EC1N,2TD,,,3,,3,,,,,2,,,,,,,,,,,,,,1,2,2
1 Setting up this lettings log Property information Tenancy information Household characteristics Household needs Household situation Income, benefits and outgoings
2 Question Which organisation owns this property? Which organisation manages this letting? What is the CORE username of the account this letting log should be assigned to? What is the needs type? What is the letting type? Is this letting a renewal? What is the tenancy start date? - day DD What is the tenancy start date? - month MM What is the tenancy start date? - year YY Is this a London Affordable Rent letting? Which type of Intermediate Rent is this letting? Which 'Other' type of Intermediate Rent is this letting? What is the tenant code? What is the property reference? What management group does this letting belong to? What scheme does this letting belong to? Which location is this letting for? If known, provide this property’s UPRN Address Line 1 Address Line 2 Town or city County Part 1 of the property's postcode Part 2 of the property's postcode What is the property's local authority? What type was the property most recently let as? What is the reason for the property being vacant? How many times was the property offered between becoming vacant and this letting? What type of unit is the property? Which type of building is the property? Is the property built or adapted to wheelchair-user standards? How many bedrooms does the property have? What is the void date? - day DD What is the void date? - month MM What is the void date? - year YYYY What date were any major repairs completed on? - day DD What date were any major repairs completed on? - month MM What date were any major repairs completed on? - year YY Is this a joint tenancy? Is this a starter tenancy? What is the type of tenancy? If 'Other', what is the type of tenancy? What is the length of the fixed-term tenancy to the nearest year? Is this letting in sheltered accommodation? Has the tenant seen the DLUHC privacy notice? What is the lead tenant’s age? Which of these best describes the lead tenant’s gender identity? Which of these best describes the lead tenant's ethnic background? What is the lead tenant’s nationality? Which of these best describes the lead tenant’s working situation? What is person 2's relationship to the lead tenant? What is person 2's age? Which of these best describes person 2's gender identity? Which of these best describes person 2's working situation? What is person 3's relationship to the lead tenant? What is person 3's age? Which of these best describes person 3's gender identity? Which of these best describes person 3's working situation? What is person 4's relationship to the lead tenant? What is person 4's age? Which of these best describes person 4's gender identity? Which of these best describes person 4's working situation? What is person 5's relationship to the lead tenant? What is person 5's age? Which of these best describes person 5's gender identity? Which of these best describes person 5's working situation? What is person 6's relationship to the lead tenant? What is person 6's age? Which of these best describes person 6's gender identity? Which of these best describes person 6's working situation? What is person 7's relationship to the lead tenant? What is person 7's age? Which of these best describes person 7's gender identity? Which of these best describes person 7's working situation? What is person 8's relationship to the lead tenant? What is person 8's age? Which of these best describes person 8's gender identity? Which of these best describes person 8's working situation? Does anybody in the household have links to the UK armed forces? Is this person still serving in the UK armed forces? Was this person seriously injured or ill as a result of serving in the UK armed forces? Is anybody in the household pregnant? Disabled access needs a) Fully wheelchair-accessible housing Disabled access needs b) Wheelchair access to essential rooms Disabled access needs c) Level access housing Disabled access needs f) Other disabled access needs Disabled access needs g) No disabled access needs Disabled access needs h) Don’t know Does anybody in the household have a physical or mental health condition (or other illness) expected to last 12 months or more? Does this person's condition affect their dexterity? Does this person's condition affect their learning or understanding or concentrating? Does this person's condition affect their hearing? Does this person's condition affect their memory? Does this person's condition affect their mental health? Does this person's condition affect their mobility? Does this person's condition affect them socially or behaviourally? Does this person's condition affect their stamina or breathing or fatigue? Does this person's condition affect their vision? Does this person's condition affect them in another way? How long has the household continuously lived in the local authority area of the new letting? How long has the household been on the local authority waiting list for the new letting? What is the tenant’s main reason for the household leaving their last settled home? If 'Other', what was the main reason for leaving their last settled home? Where was the household immediately before this letting? Did the household experience homelessness immediately before this letting? Do you know the postcode of the household's last settled home? Part 1 of postcode of last settled home Part 2 of postcode of last settled home What is the local authority of the household's last settled home? Was the household given 'reasonable preference' by the local authority? Reasonable preference reason They were homeless or about to lose their home (within 56 days) Reasonable preference reason They were living in unsanitary, overcrowded or unsatisfactory housing Reasonable preference reason They needed to move due to medical and welfare reasons (including disability) Reasonable preference reason They needed to move to avoid hardship to themselves or others Reasonable preference reason Don't know Was the letting made under Choice-Based Lettings (CBL)? Was the letting made under the Common Allocation Policy (CAP)? Was the letting made under the Common Housing Register (CHR)? What was the source of referral for this letting? Do you know the household's combined total income after tax? How often does the household receive income? How much income does the household have in total? Is the tenant likely to be receiving any of these housing-related benefits? How much of the household's income is from Universal Credit, state pensions or benefits? Does the household pay rent or other charges for the accommodation? How often does the household pay rent and other charges? If this is a care home, how much does the household pay every [time period]? What is the basic rent? What is the service charge? What is the personal service charge? What is the support charge? Total charge After the household has received any housing-related benefits, will they still need to pay for rent and charges? What do you expect the outstanding amount to be?
3 Additional info Organisation's CORE ID If using new core then this will be the email address. If left empty, the letting log will be assigned to the account used to upload the log. General needs housing includes both self-contained and shared housing without support or specific adaptations. Supported housing includes direct access hostels, group homes, residential care and nursing homes. This is a letting to the same tenant in the same property This is how you usually refer to this tenancy on your own systems This is how you usually refer to this property on your own systems Provide management code if you have one Provide scheme code, include the 'S' at the beginning if it has one Provide location code if you have one The UPRN is the Unique Property Reference Number. It's created by the Ordnance Survey so it's a unique number system used across all housing providers, all sectors (i.e. not just social housing) and all across the UK. Do not include the offer that led to this letting. This is after the last tenancy ended. If the property is being offered for let for the first time, enter 0. If shared accommodation, enter the number of bedrooms occupied by this household. A bedsit has 1 bedroom. This is the date the property became available to let. For a re-let, it's the day after the previous tenant's contract ends. For a new build, conversion, acquisition or lease it's the day after the provider legally took over possession or management. Major repairs are works that could not be reasonably carried out with a tenant living at the property. For example, structural repairs. Also known as an ‘introductory period’ Fixed-term tenancies are for a set time (up to 20 years). Licence agreements are on a rolling basis, mainly for supported housing. Local authorities mostly provide secure tenancies, and housing associations mostly provide assured (ASTs). Not including starter or introductory period Make sure the tenant has seen the attached privacy notice before completing this log This is the household member who does the most paid work. If several people do the same paid work, it's the oldest household member. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. A child is anyone eligible for child benefit: under age 16 or under 20 if still in full-time education. Mark children under 1 as 1. Excluding national service. If several household members have these links, answer for regular first. If no regular, answer for reserve. If no reserve, answer for spouses or civil partners. For example, lifting and carrying objects, or using a keyboard For example, deafness or partial hearing For example, depression or anxiety Anything associated with autism spectrum disorder (ASD), including Asperger’s or attention deficit hyperactivity disorder (ADHD) For example, blindness or partial sight ‘Last settled home' means last long-standing home. For tenants who had temporary accommodation or slept rough, it's where they lived previously. Social housing 'reasonable preference' is also known as 'priority need' Include any income after tax from employment, pensions, and Universal Credit. Don't include National Insurance (NI) contributions and tax, housing benefit, child benefit, or council tax support. If rent is charged on the property then answer Yes, even if tenants do not pay it themselves. Amount paid before any service charges, for example hot water or cleaning. Households may get household benefits towards basic rent. For example, cleaning. Households may get household benefits towards service charge For example heating or hot water. This doesn’t include housing benefit or Universal Credit. Any support service charges included in the tenancy agreement Unnecessary for new CORE users Approximate figure only
4 Values Numeric Email format if using new CORE. Alphanumeric, except for commas if using old CORE. 1 - 2 1 - 12 1 - 2 1 - 31 1 - 12 23 - 24 1 - 3 Text Alphanumeric, max 13 characters Alphanumeric, max 12 characters 1 - 999 Alphanumeric 1 - 999 Numeric Alphanumeric Text XX(XX) XXX ONS CODE: Alphanumeric, 9 characters beginning with 'E' 1 - 3 or 5 - 8 5 - 6, or 8 - 20 0+ 1 - 2, 4 or 6 - 10 1 - 2 1 - 7 1 - 31 1 - 12 20 - 24 1 - 31 1 - 12 14 - 24 1 - 3 1 - 2 2 - 7 Text 1 - 99 1 - 5 1 16 - 120 or R F, M, X or R 1 - 19 12 - 13, 17 - 21 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 P, C, X or R Numeric, range 1 - 120 or text (upper case 'R') Must be >= 16 if working situation = 1 - 8 or 0 Must be <16 if working situation = 9 F, M, X or R 0 - 10 1 - 6 3 - 6 1 - 3 1 or empty 1 - 3 1 or empty 1 - 2 or 5 - 10 2 or 5 - 10 1 - 2, 4, 8 - 14, 16 - 20, 28 - 31 or 34 - 49 Text 3 - 4, 6 - 7, 9 - 10, 13 - 14, 18 - 19, 21 or 23 - 37 1 or 11 1 - 2 XX(XX) XXX ONS CODE: Alphanumeric, 9 characters beginning with 'E' 1 - 3 1 or empty 1 - 2 1 - 4, 7 - 10, 12 - 17 1 - 3 0 - 99999 1, 3, 6, 9 or 10 1 - 4 0 - 1 1 - 10 xxxx.xx 1 - 3 xxxx.xx
5 Can be empty? No Yes No No Yes, if letting type is not an Affordable Rent letting (if field 5 = 1 - 4 or 9 - 12) Yes, if letting type is not an Intermediate Rent letting (if field 5 = 1 - 8) Yes, if letting type is not an Intermediate Rent letting (if field 5 = 1 - 8) or if 'Other intermediate rent product' is not selected for type of Intermediate Rent (if field 11 is not 3) Yes Yes, if letting is general needs (if field 4 = 1) or if location code is provided (if field 17 is not empty) Yes, if letting is general needs (if field 4 = 1) Yes, if letting is general needs (if field 4 = 1) or if management code is provided (if field 15 is not empty) Yes, if letting is supported housing (if field 4 = 2) or if the property's postcode is not empty (if fields 23 and 24 contain full and valid entries) Yes, if letting is supported housing (if field 4 = 2) or if property's UPRN and local authority are known (if fields 18 and 25 are not empty) Yes Yes, if letting is supported housing (if field 4 = 2) or if property's UPRN and local authority are known (if fields 18 and 25 are not empty) Yes Yes, if letting is supported housing (if field 4 = 2) or if property's UPRN and local authority are known (if fields 18 and 25 are not empty) Yes, if letting is supported housing (if field 4 = 2) Yes, if letting is a renewal (if field 6 = 1) or a first-time let (if field 27 = 15 - 17) Yes, if letting is a renewal (if field 6 = 1) Yes, if letting is supported housing (if field 4 = 2) Yes, if letting is a renewal (if field 6 = 1) Yes No Yes, if 'Other' is not selected for tenancy type (if field 41 is not 3) Yes, if letting is not a fixed-term tenancy (if field 41 = 2, 3, 5 or 7) Yes, if letting is general needs (if field 4 = 1) No No Yes, if the other fields about this person (fields 52, 53 and 54) are also empty Yes, if the other fields about this person (fields 51, 53 and 54) are also empty Yes, if the other fields about this person (fields 51, 52 and 54) are also empty Yes, if the other fields about this person (fields 51, 52 and 53) are also empty Yes, if the other fields about this person (fields 56, 57 and 58) are also empty Yes, if the other fields about this person (fields 55, 57 and 58) are also empty Yes, if the other fields about this person (fields 55, 56 and 58) are also empty Yes, if the other fields about this person (fields 55, 56 and 57) are also empty Yes, if the other fields about this person (fields 60, 61 and 62) are also empty Yes, if the other fields about this person (fields 59, 61 and 62) are also empty Yes, if the other fields about this person (fields 59, 60 and 62) are also empty Yes, if the other fields about this person (fields 59, 60 and 61) are also empty Yes, if the other fields about this person (fields 64, 65 and 66) are also empty Yes, if the other fields about this person (fields 63, 65 and 66) are also empty Yes, if the other fields about this person (fields 63, 64 and 66) are also empty Yes, if the other fields about this person (fields 63, 64 and 65) are also empty Yes, if the other fields about this person (fields 68, 69 and 70) are also empty Yes, if the other fields about this person (fields 67, 69 and 70) are also empty Yes, if the other fields about this person (fields 67, 68 and 70) are also empty Yes, if the other fields about this person (fields 67, 68 and 69) are also empty Yes, if the other fields about this person (fields 72, 73 and 74) are also empty Yes, if the other fields about this person (fields 71, 73 and 74) are also empty Yes, if the other fields about this person (fields 71, 72 and 74) are also empty Yes, if the other fields about this person (fields 71, 72 and 73) are also empty Yes, if the other fields about this person (fields 76, 77 and 78) are also empty Yes, if the other fields about this person (fields 75, 77 and 78) are also empty Yes, if the other fields about this person (fields 75, 76 and 78) are also empty Yes, if the other fields about this person (fields 75, 76 and 77) are also empty No Yes, if no one in the household is a current or former regular (if field 79 is not 1) Yes, if no one in the household is a current or former regular or reserve (if field 79 = 2, 3, 5 or 6) No Yes, if no household members have access needs or if it is unknown (if field 87 or 88 = 1) Yes, if a household member has an access need (if at least one of fields 83, 84, 85 and 86 = 1) No Yes, if no one in the household has a physical or mental health condition (if field 89 is 2 or 3). If someone in the household does have such a condition (if field 89 = 1), then at least 1 of these fields must be 1. No Yes, if letting is a renewal (if field 6 = 1) No Yes, if 'Other' is not selected for reason for leaving last settled home (if field 102 is not 20) Yes, if letting is a renewal (if field 6 = 1) No Yes, if postcode of household's last settled home is not known (if 106 = 2) Yes No If household was given 'reasonable preference' (if field 110 = 1), at least one of these fields must be 1. If household was not given 'reasonable preference' (if field 110 = 2 or 3), these fields will be ignored. No Yes, if letting is a renewal (if field 6 = 1) No Yes, if household's income is unknown (if field 120 = 2 or 3) No Yes, if all rent and accommodation charges are provided (if fields 127 - 132 are not empty) No Yes, if accommodation is not a care home (if field 125 = 1) and all rent and accommodation charges are provided (if fields 128 - 132 are not empty) Yes, if the household does not pay rent (if field 125 = 1) or if the accommodation is not a care home (if field 127 is empty) Yes Yes, if submitting data to new CORE, if the household does not pay rent (if field 125 = 1) or if the accommodation is not a care home (if field 127 is empty) Yes, if the household doesn't receive housing benefits, or if it is unknown (if field 123 = 3, 9 or 10) Yes, if the household does not need to pay rent/charges after receiving housing benefits (if field133 = 2 or 3)
6 Type of letting the question applies to Affordable Rent only Intermediate Rent only Supported housing only General needs only General needs only Supported housing only Supported housing only
7 Duplicate check field? Yes Yes Yes Yes Yes
8 Bulk upload field number 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
9 3 3 1 1 1 10 23 2 123 123 123 123 123 A1 1AA E07000004 1 6 0 1 1 1 1 1 10 22 1 1 22 1 1 1 1 1 1 20 M 3 4 1 1 1 2 0 1 24 4 40 1 2 EC1N 2TD 3 3 2 1 2 2

12
spec/fixtures/files/2023_24_sales_bulk_upload.csv vendored

File diff suppressed because one or more lines are too long

12
spec/fixtures/files/2023_24_sales_bulk_upload_invalid.csv vendored

File diff suppressed because one or more lines are too long

119
spec/fixtures/files/completed_2022_23_sales_bulk_upload.csv vendored

@ -1,119 +0,0 @@
Question,What is the purchaser code?,What is the day of the sale completion date? - DD,What is the month of the sale completion date? - MM,What is the year of the sale completion date? - YY,[BLANK],Was the buyer interviewed for any of the answers you will provide on this log?,Age of Buyer 1,Age of Buyer 2 or Person 2,Age of Person 3,Age of Person 4,Age of Person 5,Age of Person 6,Gender identity of Buyer 1,Gender identity of Buyer 2 or Person 2,Gender identity of Person 3,Gender identity of Person 4,Gender identity of Person 5,Gender identity of Person 6,Person 2's relationship to lead tenant,Person 3's relationship to lead tenant,Person 4's relationship to lead tenant,Person 5's relationship to lead tenant,Person 6's relationship to lead tenant,Working situation of Buyer 1,Working situation of Buyer 2 or Person 2,Working situation of Person 3,Working situation of Person 4,Working situation of Person 5,Working situation of Person 6,What is the buyer 1's ethnic group?,What is buyer 1's nationality?,What is buyer 1's gross annual income?,What is buyer 2's gross annual income?,Was buyer 1's income used for a mortgage application?,Was buyer 2's income used for a mortgage application?,"What is the total amount the buyers had in savings before they paid any deposit for the property?
To the nearest £10",Have any of the buyers previously owned a property?,[BLANK],What was buyer 1's previous tenure?,What is the local authority of buyer 1's last settled home,Part 1 of postcode of buyer 1's last settled home,Part 2 of postcode of buyer 1's last settled home,Do you know the postcode of buyer 1's last settled home?,Was the buyer registered with their PRP (HA)?,Was the buyer registered with the local authority?,Was the buyer registered with a Help to Buy agent?,Was the buyer registered with another PRP (HA)?,Does anyone in the household consider themselves to have a disability?,Does anyone in the household use a wheelchair?,How many bedrooms does the property have?,What type of unit is the property?,Which type of building is the property?,What is the local authority of the property?,Part 1 of postcode of property,Part 2 of postcode of property,Is the property built or adapted to wheelchair-user standards?,What is the type of shared ownership sale?,"Is this a resale?
Shared ownership","What is the day of the practical completion or handover date? - DD
Shared ownership","What is the month of the practical completion or handover date? - MM
Shared ownership","What is the year of the practical completion or handover date? - YY
Shared ownership","What is the day of the exchange of contracts date? - DD
Shared ownership","What is the month of the exchange of contracts date? - MM
Shared ownership","What is the year of the exchange of contracts date? - YY
Shared ownership","Was the household re-housed under a local authority nominations agreement?
Shared ownership","How many bedrooms did the buyer's previous property have?
Shared ownership","What was the type of the buyer's previous property?
Shared ownership","What was the full purchase price?
Shared ownership","What was the initial percentage equity stake purchased?
Shared ownership","What is the mortgage amount?
Shared ownership","Does this include any extra borrowing?
Shared ownership","How much was the cash deposit paid on the property?
Shared ownership","How much cash discount was given through Social Homebuy?
Shared ownership","What is the basic monthly rent?
Shared ownership","What are the total monthly leasehold charges for the property?
Shared ownership",What is the type of discounted ownership sale?,"What was the full purchase price?
Discounted ownership","What was the amount of any loan, grant, discount or subsidy given?
Discounted ownership","What was the percentage discount?
Discounted ownership","What is the mortgage amount?
Discounted ownership","Does this include any extra borrowing?
Discounted ownership","How much was the cash deposit paid on the property?
Discounted ownership","What are the total monthly leasehold charges for the property?
Discounted ownership",What is the type of outright sale?,"What is the 'other' type of outright sale?
Outright sale",[BLANK],"What is the full purchase price?
Outright sale","What is the mortgage amount?
Outright sale","Does this include any extra borrowing?
Outright sale","How much was the cash deposit paid on the property?
Outright sale","What are the total monthly leasehold charges for the property?
Outright sale","Which organisation owned this property before the sale?
Organisation's CORE ID",Username,BLANK,Has the buyer ever served in the UK Armed Forces and for how long?,[BLANK],Are any of the buyers a spouse or civil partner of a UK Armed Forces regular who died in service within the last 2 years?,"What is the name of the mortgage lender?
Shared ownership","What is the name of the 'other' mortgage lender?
Shared ownership","What is the name of the mortgage lender?
Discounted ownership","What is the name of the 'other' mortgage lender?
Discounted ownership","What is the name of the mortgage lender?
Outright sale","What is the name of the 'other' mortgage lender?
Outright sale",Were the buyers receiving any of these housing-related benefits immediately before buying this property?,"What is the length of the mortgage in years?
Shared ownership","What is the length of the mortgage in years?
Discounted ownership","What is the length of the mortgage in years?
Outright sale","How long have the buyers been living in the property before the purchase?
Discounted ownership",Are there more than two joint purchasers of this property?,"How long have the buyers been living in the property before the purchase?
Shared ownership",Is this a staircasing transaction?,Data Protection question,Was this purchase made through an ownership scheme?,"Is the buyer a company?
Outright sale",Will the buyers live in the property?,Is this a joint purchase?,Will buyer 1 live in the property?,Will buyer 2 live in the property?,"Besides the buyers, how many people live in the property?","What percentage of the property has been bought in this staircasing transaction?
Shared ownership","What percentage of the property does the buyer now own in total?
Shared ownership","What was the rent type of the buyer's previous property?
Shared ownership","Was a mortgage used for the purchase of this property?
Shared ownership","Was a mortgage used for the purchase of this property?
Discounted ownership","Was a mortgage used for the purchase of this property?
Outright sale"
Values,Max 9 digits,1 - 31,1 - 12,19 - 23,,1 or null,"15 - 110
or R",1 - 110 or R,,,,,"M, F, X or R",,,,,,"P, C, X or R",,,,,0 - 10,,,,,,1 - 19,"12 -13, 17 -19",0 - 99999,,1 or 2,1 or 2,0 - 999990,1 - 3,,1 - 7 or 9,ONS CODE - E + 9 digits,XXX(X),XXX,1 or null,,,,,1 - 3,1 - 3,1 - 9,1 - 4 or 9,1 or 2,ONS CODE E + 9 digits,XXX(X),XXX,1 - 3,"2, 16, 18, 24, 28 or 30-31",1 or 2,1 - 31,1 - 12,19 - 23,1 - 31,1 - 12,19 - 23,1 - 3,1 - 9,1 - 4 or 9,0 - 999999,0 - 100,0 - 999999,1 - 3,0 - 999999,,0 - 999.99,,"8, 9, 14, 21, 22, 27 or 29",0 - 999999,,0 - 100,0 - 999999,1 - 3,0 - 999999,0 - 999.99,10 or 12,,,0 - 999999,,1-3,0 - 999999,0-999.99,Up to 7 digits,Username of CORE account this sales log should be assigned to,,3 - 8,,4 - 7,1 - 40,,1 - 40,,1 - 40,,1 - 4, Integer <=60, Integer <=60, Integer <=60, Integer <=80,1 - 3, Integer <=80,1 - 3,1,1 - 3,1 - 2,1 - 2,1 - 2,1 - 2,1 - 2,0 - 5,1 - 100,1 - 100,1-3 or 9-10,1 - 2,1 - 2,1 - 2
Can be Null?,No,,,,,No,No,"If fields 14, 19 and 25 are all also null","If fields 15, 20 and 26 are all also null","If fields 16, 21 and 27 are all also null","If fields 17, 22 and 28 are all also null","If fields 18, 23 and 29 are all also null",No,"If fields 8, 19 and 25 are all also null","If fields 9, 20 and 26 are also null","If fields 10, 21 and 27 are all also null","If fields 11, 22 and 28 are all also null","If fields 12, 23 and 29 are all also null","If fields 8, 14 and 25 are all also null","If fields 9, 15 and 26 are all also null","If fields 10, 16 and 27 are all also null","If fields 11, 17 and 28 are all also null","If fields 12, 18 and 29 are all also null",If field 6 = 1,"If fields 8, 14 and 19 are all also null","If fields 9, 15 and 20 are all also null","If fields 10, 16 and 21 are all also null","If fields 11, 17 and 22 are all also null","If fields 12, 18 and 23 are all also null",If field 6 = 1,,,If field 116 = 2,If field 32 is null,If field 116 = 2,If field 6 = 1,,,If field 6 = 1,No,If field 43 = 1,,If fields 41 and 42 BOTH have valid entries,Yes,,,,If field 6 = 1,,No,,,,,,,If field 113 = 2 or 3,,,,,,,,,"If field 113 = 2 or 3
OR
field 39 = 3 - 7 or 9",,If field 113 = 2 or 3,,,,,"If field 57 is null, 2, 16, 24 or 28",If field 113 = 2 or 3,,If field 113 = 1 or 3,If field 76 is null,"If field 76 is null, 9 or 14","If field 76 is null, 8, 21 or 22",If field 113 = 1 or 3,,,,If field 113 = 1 or 2,If field 84 is null or 10,,If field 113 = 1 or 2,,,,,No,Yes,,No,,No,If field 113 = 2 or 3,"If field 113 = 2 or 3
OR
If field 98 is not 40",If field 113 = 1 or 3,"If field 113 = 1 or 3
OR
If field 100 is not 40",If field 113 = 1 or 2,"If field 113 = 1 or 2
OR
If field 102 is not 40",No,If field 113 = 2 or 3,If field 113 = 1 or 3,If field 113 = 1 or 2,If field 113 = 1 or 3,If field 116 = 2,If field 113 = 2 or 3,If field 113 = 2 or 3,No,No,If field 113 = 1 or 2,If field 113 = 1 or 2,No,No,If field 116 = 2,No,If field 113 = 2 or 3,If field 113 = 2 or 3,"If field 113 = 1 or 2
OR
If field 39 = 3 - 9",If field 113 = 2 or 3,If field 113 = 1 or 3,If field 113 = 1 or 2
Bulk upload format and duplicate check,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
Field number,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125
,22 test BU,22,2,23,,1,32,32,,,,,M,F,,,,,R,,,,,1,2,,,,,12,18,30000,15000,1,1,20000,3,,1,E09000008,A1,1AA,1,,1,1,,3,3,2,1,1,E09000008,CR0,4BB,3,2,2,23,3,22,30,3,22,3,1,1,250000,25,42500,3,20000,,800,200,,,,,,,,,,,,,,,,,123,,,3,,5,1,,,,,,4,20,,,,2,5,1,1,1,,1,1,1,1,0,10,10,1,1,,
1 Question What is the purchaser code? What is the day of the sale completion date? - DD What is the month of the sale completion date? - MM What is the year of the sale completion date? - YY [BLANK] Was the buyer interviewed for any of the answers you will provide on this log? Age of Buyer 1 Age of Buyer 2 or Person 2 Age of Person 3 Age of Person 4 Age of Person 5 Age of Person 6 Gender identity of Buyer 1 Gender identity of Buyer 2 or Person 2 Gender identity of Person 3 Gender identity of Person 4 Gender identity of Person 5 Gender identity of Person 6 Person 2's relationship to lead tenant Person 3's relationship to lead tenant Person 4's relationship to lead tenant Person 5's relationship to lead tenant Person 6's relationship to lead tenant Working situation of Buyer 1 Working situation of Buyer 2 or Person 2 Working situation of Person 3 Working situation of Person 4 Working situation of Person 5 Working situation of Person 6 What is the buyer 1's ethnic group? What is buyer 1's nationality? What is buyer 1's gross annual income? What is buyer 2's gross annual income? Was buyer 1's income used for a mortgage application? Was buyer 2's income used for a mortgage application? What is the total amount the buyers had in savings before they paid any deposit for the property? To the nearest £10 Have any of the buyers previously owned a property? [BLANK] What was buyer 1's previous tenure? What is the local authority of buyer 1's last settled home Part 1 of postcode of buyer 1's last settled home Part 2 of postcode of buyer 1's last settled home Do you know the postcode of buyer 1's last settled home? Was the buyer registered with their PRP (HA)? Was the buyer registered with the local authority? Was the buyer registered with a Help to Buy agent? Was the buyer registered with another PRP (HA)? Does anyone in the household consider themselves to have a disability? Does anyone in the household use a wheelchair? How many bedrooms does the property have? What type of unit is the property? Which type of building is the property? What is the local authority of the property? Part 1 of postcode of property Part 2 of postcode of property Is the property built or adapted to wheelchair-user standards? What is the type of shared ownership sale? Is this a resale? Shared ownership What is the day of the practical completion or handover date? - DD Shared ownership What is the month of the practical completion or handover date? - MM Shared ownership What is the year of the practical completion or handover date? - YY Shared ownership What is the day of the exchange of contracts date? - DD Shared ownership What is the month of the exchange of contracts date? - MM Shared ownership What is the year of the exchange of contracts date? - YY Shared ownership Was the household re-housed under a local authority nominations agreement? Shared ownership How many bedrooms did the buyer's previous property have? Shared ownership What was the type of the buyer's previous property? Shared ownership What was the full purchase price? Shared ownership What was the initial percentage equity stake purchased? Shared ownership What is the mortgage amount? Shared ownership Does this include any extra borrowing? Shared ownership How much was the cash deposit paid on the property? Shared ownership How much cash discount was given through Social Homebuy? Shared ownership What is the basic monthly rent? Shared ownership What are the total monthly leasehold charges for the property? Shared ownership What is the type of discounted ownership sale? What was the full purchase price? Discounted ownership What was the amount of any loan, grant, discount or subsidy given? Discounted ownership What was the percentage discount? Discounted ownership What is the mortgage amount? Discounted ownership Does this include any extra borrowing? Discounted ownership How much was the cash deposit paid on the property? Discounted ownership What are the total monthly leasehold charges for the property? Discounted ownership What is the type of outright sale? What is the 'other' type of outright sale? Outright sale [BLANK] What is the full purchase price? Outright sale What is the mortgage amount? Outright sale Does this include any extra borrowing? Outright sale How much was the cash deposit paid on the property? Outright sale What are the total monthly leasehold charges for the property? Outright sale Which organisation owned this property before the sale? Organisation's CORE ID Username BLANK Has the buyer ever served in the UK Armed Forces and for how long? [BLANK] Are any of the buyers a spouse or civil partner of a UK Armed Forces regular who died in service within the last 2 years? What is the name of the mortgage lender? Shared ownership What is the name of the 'other' mortgage lender? Shared ownership What is the name of the mortgage lender? Discounted ownership What is the name of the 'other' mortgage lender? Discounted ownership What is the name of the mortgage lender? Outright sale What is the name of the 'other' mortgage lender? Outright sale Were the buyers receiving any of these housing-related benefits immediately before buying this property? What is the length of the mortgage in years? Shared ownership What is the length of the mortgage in years? Discounted ownership What is the length of the mortgage in years? Outright sale How long have the buyers been living in the property before the purchase? Discounted ownership Are there more than two joint purchasers of this property? How long have the buyers been living in the property before the purchase? Shared ownership Is this a staircasing transaction? Data Protection question Was this purchase made through an ownership scheme? Is the buyer a company? Outright sale Will the buyers live in the property? Is this a joint purchase? Will buyer 1 live in the property? Will buyer 2 live in the property? Besides the buyers, how many people live in the property? What percentage of the property has been bought in this staircasing transaction? Shared ownership What percentage of the property does the buyer now own in total? Shared ownership What was the rent type of the buyer's previous property? Shared ownership Was a mortgage used for the purchase of this property? Shared ownership Was a mortgage used for the purchase of this property? Discounted ownership Was a mortgage used for the purchase of this property? Outright sale
2 Values Max 9 digits 1 - 31 1 - 12 19 - 23 1 or null 15 - 110 or R 1 - 110 or R M, F, X or R P, C, X or R 0 - 10 1 - 19 12 -13, 17 -19 0 - 99999 1 or 2 1 or 2 0 - 999990 1 - 3 1 - 7 or 9 ONS CODE - E + 9 digits XXX(X) XXX 1 or null 1 - 3 1 - 3 1 - 9 1 - 4 or 9 1 or 2 ONS CODE E + 9 digits XXX(X) XXX 1 - 3 2, 16, 18, 24, 28 or 30-31 1 or 2 1 - 31 1 - 12 19 - 23 1 - 31 1 - 12 19 - 23 1 - 3 1 - 9 1 - 4 or 9 0 - 999999 0 - 100 0 - 999999 1 - 3 0 - 999999 0 - 999.99 8, 9, 14, 21, 22, 27 or 29 0 - 999999 0 - 100 0 - 999999 1 - 3 0 - 999999 0 - 999.99 10 or 12 0 - 999999 1-3 0 - 999999 0-999.99 Up to 7 digits Username of CORE account this sales log should be assigned to 3 - 8 4 - 7 1 - 40 1 - 40 1 - 40 1 - 4 Integer <=60 Integer <=60 Integer <=60 Integer <=80 1 - 3 Integer <=80 1 - 3 1 1 - 3 1 - 2 1 - 2 1 - 2 1 - 2 1 - 2 0 - 5 1 - 100 1 - 100 1-3 or 9-10 1 - 2 1 - 2 1 - 2
3 Can be Null? No No No If fields 14, 19 and 25 are all also null If fields 15, 20 and 26 are all also null If fields 16, 21 and 27 are all also null If fields 17, 22 and 28 are all also null If fields 18, 23 and 29 are all also null No If fields 8, 19 and 25 are all also null If fields 9, 20 and 26 are also null If fields 10, 21 and 27 are all also null If fields 11, 22 and 28 are all also null If fields 12, 23 and 29 are all also null If fields 8, 14 and 25 are all also null If fields 9, 15 and 26 are all also null If fields 10, 16 and 27 are all also null If fields 11, 17 and 28 are all also null If fields 12, 18 and 29 are all also null If field 6 = 1 If fields 8, 14 and 19 are all also null If fields 9, 15 and 20 are all also null If fields 10, 16 and 21 are all also null If fields 11, 17 and 22 are all also null If fields 12, 18 and 23 are all also null If field 6 = 1 If field 116 = 2 If field 32 is null If field 116 = 2 If field 6 = 1 If field 6 = 1 No If field 43 = 1 If fields 41 and 42 BOTH have valid entries Yes If field 6 = 1 No If field 113 = 2 or 3 If field 113 = 2 or 3 OR field 39 = 3 - 7 or 9 If field 113 = 2 or 3 If field 57 is null, 2, 16, 24 or 28 If field 113 = 2 or 3 If field 113 = 1 or 3 If field 76 is null If field 76 is null, 9 or 14 If field 76 is null, 8, 21 or 22 If field 113 = 1 or 3 If field 113 = 1 or 2 If field 84 is null or 10 If field 113 = 1 or 2 No Yes No No If field 113 = 2 or 3 If field 113 = 2 or 3 OR If field 98 is not 40 If field 113 = 1 or 3 If field 113 = 1 or 3 OR If field 100 is not 40 If field 113 = 1 or 2 If field 113 = 1 or 2 OR If field 102 is not 40 No If field 113 = 2 or 3 If field 113 = 1 or 3 If field 113 = 1 or 2 If field 113 = 1 or 3 If field 116 = 2 If field 113 = 2 or 3 If field 113 = 2 or 3 No No If field 113 = 1 or 2 If field 113 = 1 or 2 No No If field 116 = 2 No If field 113 = 2 or 3 If field 113 = 2 or 3 If field 113 = 1 or 2 OR If field 39 = 3 - 9 If field 113 = 2 or 3 If field 113 = 1 or 3 If field 113 = 1 or 2
4 Bulk upload format and duplicate check Yes
5 Field number 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
6 22 test BU 22 2 23 1 32 32 M F R 1 2 12 18 30000 15000 1 1 20000 3 1 E09000008 A1 1AA 1 1 1 3 3 2 1 1 E09000008 CR0 4BB 3 2 2 23 3 22 30 3 22 3 1 1 250000 25 42500 3 20000 800 200 123 3 5 1 4 20 2 5 1 1 1 1 1 1 1 0 10 10 1 1

4
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 2022/23 data you uploaded has been checked. The 0 logs you uploaded are now complete.",
success_description: "The lettings 2023/24 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 2022/23 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 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.",
cta_link: bulk_upload_lettings_soft_validations_check_url(bulk_upload, page: "confirm-soft-errors"),
},
)

4
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 (2022/23)")
expect(response.body).to include("Bulk upload for lettings (2023/24)")
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 (2022/23)")
expect(response.body).to include("Bulk upload for lettings (2023/24)")
end
it "renders correct number of errors" do

4
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("2022/23")
expect(response.body).to include("2023/24")
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("2022/23")
expect(response.body).to include("2023/24")
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")

2
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("2022/23")
expect(response.body).to include("2023/24")
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?")

2
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 (2022/23)")
expect(response.body).to include("Bulk Upload for sales (2023/24)")
end
it "renders correct number of errors" do

4
spec/requests/bulk_upload_sales_resume_controller_spec.rb

@ -16,7 +16,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("2022/23")
expect(response.body).to include("2023/24")
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)
@ -170,7 +170,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("2022/23")
expect(response.body).to include("2023/24")
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")

2
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("2022/23")
expect(response.body).to include("2023/24")
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?")

53
spec/services/bulk_upload/lettings/log_creator_spec.rb

@ -1,16 +1,27 @@
require "rails_helper"
RSpec.describe BulkUpload::Lettings::LogCreator do
subject(:service) { described_class.new(bulk_upload:, path:) }
subject(:service) { described_class.new(bulk_upload:, path: "") }
let(:owning_org) { create(:organisation, old_visible_id: 123) }
let(:user) { create(:user, organisation: owning_org) }
let(:bulk_upload) { create(:bulk_upload, :lettings, user:) }
let(:path) { file_fixture("2022_23_lettings_bulk_upload.csv") }
let(:csv_parser) { instance_double(BulkUpload::Lettings::Year2023::CsvParser) }
let(:row_parser) { instance_double(BulkUpload::Lettings::Year2023::RowParser) }
let(:log) { build(:lettings_log, :completed, created_by: user, owning_organisation: owning_org, managing_organisation: owning_org) }
before do
allow(BulkUpload::Lettings::Year2023::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)
allow(row_parser).to receive(:valid?).and_return(true)
allow(row_parser).to receive(:blank_row?).and_return(false)
end
around do |example|
Timecop.freeze(Time.zone.local(2023, 1, 1)) do
Timecop.freeze(Time.zone.local(2023, 4, 1)) do
Singleton.__init__(FormHandler)
example.run
end
@ -52,15 +63,8 @@ RSpec.describe BulkUpload::Lettings::LogCreator do
end
context "when a valid csv with several blank rows" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { LettingsLog.new }
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
allow(row_parser).to receive(:blank_row?).and_return(true)
end
it "ignores them and does not create the logs" do
@ -69,16 +73,16 @@ RSpec.describe BulkUpload::Lettings::LogCreator do
end
context "when a valid csv with row with one invalid non setup field" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) do
build(
:lettings_log,
:completed,
renttype: 3,
age1_known: 0,
age1: 5,
owning_organisation: owning_org,
managing_organisation: owning_org,
created_by: user,
national: 18,
waityear: 9,
joint: 2,
@ -87,16 +91,12 @@ RSpec.describe BulkUpload::Lettings::LogCreator do
)
end
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
end
it "creates the log" do
expect { service.call }.to change(LettingsLog, :count).by(1)
end
it "blanks invalid field" do
allow(row_parser).to receive(:valid?).and_return(false)
service.call
record = LettingsLog.last
@ -105,8 +105,6 @@ RSpec.describe BulkUpload::Lettings::LogCreator do
end
context "when a valid csv with row with compound errors on non setup field" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) do
build(
:lettings_log,
@ -116,16 +114,12 @@ RSpec.describe BulkUpload::Lettings::LogCreator do
)
end
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2023_csv_row)
file.rewind
end
it "creates the log" do
expect { service.call }.to change(LettingsLog, :count).by(1)
end
it "blanks invalid fields" do
allow(row_parser).to receive(:valid?).and_return(false)
service.call
record = LettingsLog.last
@ -135,8 +129,6 @@ RSpec.describe BulkUpload::Lettings::LogCreator do
end
context "when pre-creating logs" do
subject(:service) { described_class.new(bulk_upload:, path:) }
it "creates a new log" do
expect { service.call }.to change(LettingsLog, :count)
end
@ -152,8 +144,6 @@ RSpec.describe BulkUpload::Lettings::LogCreator do
end
context "with a valid csv and soft validations" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) do
build(
:lettings_log,
@ -173,11 +163,6 @@ RSpec.describe BulkUpload::Lettings::LogCreator do
)
end
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
end
it "creates a new log" do
expect { service.call }.to change(LettingsLog, :count)
end

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

@ -10,134 +10,7 @@ RSpec.describe BulkUpload::Lettings::Validator do
let(:path) { file.path }
let(:file) { Tempfile.new }
around do |example|
Timecop.freeze(Date.new(2023, 10, 1)) do
example.run
end
Timecop.return
end
describe "validations" do
context "when 2022" do
let(:bulk_upload) { create(:bulk_upload, user:, year: 2022) }
context "when file has no headers" do
context "and too many columns" do
before do
file.write(("a" * 136).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 has a new line in it (empty)" do
before do
file.write("\n")
file.rewind
end
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" * 95).chars.join(","))
file.write(",1,10,22,")
file.write(("a" * 37).chars.join(","))
file.write("\n")
file.rewind
end
it "is valid" do
expect(validator).to be_valid
end
end
end
context "when file has headers" do
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_2022_field_numbers + %w[invalid_field_number] }
let(:field_values) { log_to_csv.to_2022_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
it "returns correct total logs count" do
expect(validator.total_logs_count).to be(1)
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 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_2022_field_numbers }
let(:field_values) { log_to_csv.to_2022_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
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_2022_field_numbers + %w[23] }
let(:field_values) { log_to_csv.to_2022_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
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
end
context "when 2023" do
let(:bulk_upload) { create(:bulk_upload, user:, year: 2023) }
@ -245,7 +118,7 @@ RSpec.describe BulkUpload::Lettings::Validator do
context "with no headers" do
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row)
file.close
end
@ -276,7 +149,7 @@ RSpec.describe BulkUpload::Lettings::Validator do
describe "#call" do
context "when a valid csv" do
let(:path) { file_fixture("2022_23_lettings_bulk_upload.csv") }
let(:path) { file_fixture("2023_24_lettings_bulk_upload_invalid.csv") }
it "creates validation errors" do
expect { validator.call }.to change(BulkUploadError, :count)
@ -285,15 +158,15 @@ RSpec.describe BulkUpload::Lettings::Validator do
it "create validation error with correct values" do
validator.call
error = BulkUploadError.find_by(row: "7", field: "field_96", category: "setup")
error = BulkUploadError.find_by(row: "9", field: "field_7", category: "setup")
expect(error.field).to eql("field_96")
expect(error.field).to eql("field_7")
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("7")
expect(error.cell).to eql("CS7")
expect(error.col).to eql("CS")
expect(error.row).to eql("9")
expect(error.cell).to eql("H9")
expect(error.col).to eql("H")
end
end
@ -350,12 +223,12 @@ RSpec.describe BulkUpload::Lettings::Validator do
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(20)
expect { validator.call }.to change(BulkUploadError.where(category: :setup, error: "This is a duplicate of a log in your file"), :count).by(22)
end
end
context "with unix line endings" do
let(:fixture_path) { file_fixture("2022_23_lettings_bulk_upload.csv") }
let(:fixture_path) { file_fixture("2023_24_lettings_bulk_upload.csv") }
let(:file) { Tempfile.new }
let(:path) { file.path }
@ -377,7 +250,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_2022_csv_row)
file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row)
file.close
end
@ -389,16 +262,7 @@ RSpec.describe BulkUpload::Lettings::Validator do
describe "#create_logs?" do
context "when all logs are valid" do
let(:target_path) { file_fixture("2022_23_lettings_bulk_upload.csv") }
before do
allow(FormHandler.instance).to receive(:lettings_in_crossover_period?).and_return(true)
target_array = File.open(target_path).readlines
target_array[0..71].each do |line|
file.write line
end
file.rewind
end
let(:target_path) { file_fixture("2023_24_lettings_bulk_upload.csv") }
it "returns truthy" do
validator.call
@ -407,7 +271,7 @@ RSpec.describe BulkUpload::Lettings::Validator do
end
context "when there is an invalid log" do
let(:path) { file_fixture("2022_23_lettings_bulk_upload.csv") }
let(:path) { file_fixture("2023_24_lettings_bulk_upload_invalid.csv") }
it "returns falsey" do
validator.call
@ -420,8 +284,8 @@ RSpec.describe BulkUpload::Lettings::Validator do
let(:log_2) { build(:lettings_log, :completed, created_by: user) }
before do
file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::LettingsLogToCsv.new(log: log_2, line_ending: "\r\n", col_offset: 0, overrides: { illness: 100 }).to_2022_csv_row)
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.close
end
@ -435,16 +299,9 @@ RSpec.describe BulkUpload::Lettings::Validator do
let(:log_1) { build(:lettings_log, :completed, renttype: 1, created_by: user) }
let(:log_2) { build(:lettings_log, :completed, renttype: 1, created_by: user) }
around do |example|
Timecop.freeze(Time.zone.local(2023, 2, 22)) do
example.run
end
Timecop.return
end
before do
file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::LettingsLogToCsv.new(log: log_2, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
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.close
end
@ -460,7 +317,7 @@ RSpec.describe BulkUpload::Lettings::Validator do
let(:log_1) { build(:lettings_log, :completed, renttype: 1, created_by: user, owning_organisation: unaffiliated_org) }
before do
file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::LettingsLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2023_csv_row)
file.close
end
@ -474,7 +331,7 @@ RSpec.describe BulkUpload::Lettings::Validator do
let(:log) { build(:lettings_log, :in_progress, created_by: user, startdate: Time.zone.local(2022, 5, 1)) }
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row)
file.close
end

218
spec/services/bulk_upload/lettings/year2022/csv_parser_spec.rb

@ -1,218 +0,0 @@
require "rails_helper"
RSpec.describe BulkUpload::Lettings::Year2022::CsvParser do
subject(:service) { described_class.new(path:) }
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:lettings_log, :completed) }
context "when parsing csv with headers" do
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_2022_field_numbers_row)
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_2022_csv_row)
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(1)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_12.to_i).to eq(35)
end
end
context "when parsing csv with headers with extra rows" do
before do
file.write("Extra row\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_2022_field_numbers_row)
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_2022_csv_row)
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(2)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_12.to_i).to eq(35)
end
end
context "when parsing csv with headers in arbitrary order" do
let(:seed) { rand }
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_2022_field_numbers_row(seed:))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_2022_csv_row(seed:))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(1)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_12.to_i).to eq(35)
end
end
context "when parsing csv with extra invalid headers" do
let(:seed) { rand }
let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) }
let(:field_numbers) { log_to_csv.default_2022_field_numbers + %w[invalid_field_number] }
let(:field_values) { log_to_csv.to_2022_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 "parses csv correctly" do
expect(service.row_parsers[0].field_12.to_i).to eq(35)
end
it "counts the number of valid field numbers correctly" do
expect(service).to be_correct_field_count
end
end
context "when parsing csv without headers" do
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(0)
expect(service.col_offset).to eq(0)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_12.to_i).to be(35)
end
end
context "when parsing with BOM aka byte order mark" do
let(:bom) { "\uFEFF" }
before do
file.write(bom)
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_12.to_i).to be(35)
end
end
context "when an invalid byte sequence" do
let(:invalid_sequence) { "\x81" }
before do
file.write(invalid_sequence)
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_12.to_i).to be(35)
end
end
describe "#column_for_field", aggregate_failures: true do
context "when with headers using default ordering" do
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_2022_field_numbers_row)
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_2022_csv_row)
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_1")).to eql("B")
expect(service.column_for_field("field_134")).to eql("EE")
end
end
context "when without headers using default ordering" do
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_2022_csv_row)
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_1")).to eql("A")
expect(service.column_for_field("field_134")).to eql("ED")
end
end
context "when with headers using custom ordering" do
let(:seed) { 123 }
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_2022_field_numbers_row(seed:))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_2022_csv_row(seed:))
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_1")).to eql("I")
expect(service.column_for_field("field_45")).to eql("BE")
expect(service.column_for_field("field_90")).to eql("AN")
expect(service.column_for_field("field_134")).to eql("BA")
end
end
end
context "when parsing csv with carriage returns" do
before do
file.write("Question\r\n")
file.write("Additional info\r")
file.write("Values\r\n")
file.write("Can be empty?\r")
file.write("Type of letting the question applies to\r\n")
file.write("Duplicate check field?\r")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_2022_field_numbers_row)
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_2022_csv_row)
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_12.to_i).to eq(35)
end
end
describe "#wrong_template_for_year?" do
context "when 23/24 file with 23/24 data" do
let(:log) { build(:lettings_log, :completed, startdate: Date.new(2024, 1, 1)) }
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2023_csv_row)
file.rewind
end
it "returns true" do
expect(service).to be_wrong_template_for_year
end
end
context "when 22/23 file with 22/23 data" do
let(:log) { build(:lettings_log, :completed, startdate: Date.new(2022, 10, 1)) }
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
end
it "returns false" do
expect(service).not_to be_wrong_template_for_year
end
end
end
end

2181
spec/services/bulk_upload/lettings/year2022/row_parser_spec.rb

File diff suppressed because it is too large Load Diff

88
spec/services/bulk_upload/processor_spec.rb

@ -6,12 +6,15 @@ 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) }
around do |example|
Timecop.freeze(Time.utc(2023, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
let(:mock_validator) do
instance_double(
BulkUpload::Lettings::Validator,
invalid?: false,
call: nil,
total_logs_count: 1,
any_setup_errors?: false,
create_logs?: false,
)
end
describe "#call" do
@ -39,7 +42,7 @@ RSpec.describe BulkUpload::Processor do
instance_double(
BulkUpload::Downloader,
call: nil,
path: file_fixture("2022_23_lettings_bulk_upload.csv"),
path: file_fixture("2023_24_lettings_bulk_upload.csv"),
delete_local_file!: nil,
)
end
@ -89,7 +92,7 @@ RSpec.describe BulkUpload::Processor do
instance_double(
BulkUpload::Downloader,
call: nil,
path: file_fixture("2022_23_lettings_bulk_upload.csv"),
path: file_fixture("2023_24_lettings_bulk_upload.csv"),
delete_local_file!: nil,
)
end
@ -134,7 +137,7 @@ RSpec.describe BulkUpload::Processor do
instance_double(
BulkUpload::Downloader,
call: nil,
path: file_fixture("2022_23_lettings_bulk_upload.csv"),
path: file_fixture("2023_24_lettings_bulk_upload.csv"),
delete_local_file!: nil,
)
end
@ -183,25 +186,16 @@ RSpec.describe BulkUpload::Processor do
build(
:lettings_log,
:completed,
renttype: 3,
age1: 20,
owning_organisation: owning_org,
managing_organisation: owning_org,
created_by: nil,
national: 18,
waityear: 9,
joint: 2,
tenancy: 9,
ppcodenk: 1,
voiddate: nil,
mrcdate: nil,
startdate: Date.new(2022, 10, 1),
tenancylength: nil,
created_by: user,
renttype: 1,
leftreg: 3,
)
end
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
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)
@ -255,37 +249,6 @@ RSpec.describe BulkUpload::Processor do
end
end
context "when processing an empty file with headers" do
context "when 2022-23" do
let(:mock_downloader) do
instance_double(
BulkUpload::Downloader,
call: nil,
path: file_fixture("2022_23_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
end
context "when 2023-24" do
let(:mock_downloader) do
instance_double(
@ -334,17 +297,20 @@ RSpec.describe BulkUpload::Processor do
renttype: 3,
owning_organisation: owning_org,
managing_organisation: owning_org,
startdate: Time.zone.local(2022, 10, 1),
startdate: Time.zone.local(2023, 10, 1),
renewal: 2,
declaration: 1,
)
end
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
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)
end
@ -406,17 +372,20 @@ RSpec.describe BulkUpload::Processor do
reason: 40,
leftreg: 3,
mrcdate: nil,
startdate: Date.new(2022, 10, 1),
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_2022_csv_row)
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
@ -473,7 +442,7 @@ RSpec.describe BulkUpload::Processor do
renttype: 3,
owning_organisation: owning_org,
managing_organisation: owning_org,
startdate: Time.zone.local(2022, 10, 1),
startdate: Time.zone.local(2023, 10, 1),
renewal: 2,
created_by: other_user, # unaffiliated user
declaration: 1,
@ -481,7 +450,8 @@ RSpec.describe BulkUpload::Processor do
end
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
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)

55
spec/services/bulk_upload/sales/log_creator_spec.rb

@ -1,17 +1,28 @@
require "rails_helper"
RSpec.describe BulkUpload::Sales::LogCreator do
subject(:service) { described_class.new(bulk_upload:, path:) }
subject(:service) { described_class.new(bulk_upload:, path: "") }
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(:path) { file_fixture("completed_2022_23_sales_bulk_upload.csv") }
let(:csv_parser) { instance_double(BulkUpload::Sales::Year2023::CsvParser) }
let(:row_parser) { instance_double(BulkUpload::Sales::Year2023::RowParser) }
let(:log) { build(:sales_log, :completed, created_by: user, owning_organisation: owning_org, managing_organisation: owning_org) }
before do
allow(BulkUpload::Sales::Year2023::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)
allow(row_parser).to receive(:valid?).and_return(true)
allow(row_parser).to receive(:blank_row?).and_return(false)
end
describe "#call" do
around do |example|
Timecop.freeze(Time.zone.local(2023, 2, 22)) do
Timecop.freeze(Time.zone.local(2023, 4, 22)) do
Singleton.__init__(FormHandler)
example.run
end
@ -43,15 +54,8 @@ RSpec.describe BulkUpload::Sales::LogCreator do
end
context "when a valid csv with several blank rows" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { SalesLog.new }
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
allow(row_parser).to receive(:blank_row?).and_return(true)
end
it "ignores them and does not create the logs" do
@ -60,22 +64,17 @@ RSpec.describe BulkUpload::Sales::LogCreator do
end
context "when a valid csv with row with one invalid non setup field" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) do
build(
:sales_log,
:completed,
age1: 5,
owning_organisation: owning_org,
created_by: user,
managing_organisation: owning_org,
)
end
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
end
it "creates the log" do
expect { service.call }.to change(SalesLog, :count).by(1)
end
@ -89,8 +88,6 @@ RSpec.describe BulkUpload::Sales::LogCreator do
end
context "when a valid csv with row with compound errors on non setup field" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) do
build(
:sales_log,
@ -100,14 +97,12 @@ RSpec.describe BulkUpload::Sales::LogCreator do
ppcodenk: 0,
postcode_full: "AA11AA",
ppostcode_full: "BB22BB",
owning_organisation: owning_org,
created_by: user,
managing_organisation: owning_org,
)
end
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
end
it "creates the log" do
expect { service.call }.to change(SalesLog, :count).by(1)
end
@ -124,8 +119,6 @@ RSpec.describe BulkUpload::Sales::LogCreator do
end
context "when pre-creating logs" do
subject(:service) { described_class.new(bulk_upload:, path:) }
it "creates a new log" do
expect { service.call }.to change(SalesLog, :count)
end
@ -145,8 +138,6 @@ RSpec.describe BulkUpload::Sales::LogCreator do
end
context "with a valid csv and soft validations" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) do
build(
:sales_log,
@ -156,14 +147,10 @@ RSpec.describe BulkUpload::Sales::LogCreator do
ecstat1: 5,
owning_organisation: owning_org,
created_by: user,
managing_organisation: owning_org,
)
end
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
end
it "creates a new log" do
expect { service.call }.to change(SalesLog, :count)
end

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

@ -31,7 +31,7 @@ RSpec.describe BulkUpload::Sales::Validator do
context "when file has too many columns" do
before do
file.write((%w[a] * 127).join(","))
file.write((%w[a] * (BulkUpload::Sales::Year2023::CsvParser::MAX_COLUMNS + 1)).join(","))
file.rewind
end
@ -74,7 +74,7 @@ RSpec.describe BulkUpload::Sales::Validator do
let(:path) { file.path }
before do
Timecop.freeze(Time.utc(2022, 6, 3))
Timecop.freeze(Time.utc(2022, 10, 3))
file.write(BulkUpload::SalesLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.close
end
@ -92,7 +92,7 @@ RSpec.describe BulkUpload::Sales::Validator do
describe "#call" do
context "when a valid csv" do
let(:path) { file_fixture("2022_23_sales_bulk_upload.csv") }
let(:path) { file_fixture("2023_24_sales_bulk_upload_invalid.csv") }
it "creates validation errors" do
expect { validator.call }.to change(BulkUploadError, :count)
@ -101,19 +101,19 @@ RSpec.describe BulkUpload::Sales::Validator do
it "create validation error with correct values" do
validator.call
error = BulkUploadError.find_by(row: "6", field: "field_92", category: "setup")
error = BulkUploadError.find_by(row: "9", field: "field_1", category: "setup")
expect(error.field).to eql("field_92")
expect(error.field).to eql("field_1")
expect(error.error).to eql("You must answer owning organisation")
expect(error.purchaser_code).to eql("22 test BU")
expect(error.row).to eql("6")
expect(error.cell).to eql("CO6")
expect(error.col).to eql("CO")
expect(error.purchaser_code).to eql("23 test BU")
expect(error.row).to eql("9")
expect(error.cell).to eql("B9")
expect(error.col).to eql("B")
end
end
context "with unix line endings" do
let(:fixture_path) { file_fixture("2022_23_sales_bulk_upload.csv") }
let(:fixture_path) { file_fixture("2023_24_sales_bulk_upload.csv") }
let(:file) { Tempfile.new }
let(:path) { file.path }
@ -135,7 +135,7 @@ RSpec.describe BulkUpload::Sales::Validator do
let(:path) { file.path }
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row)
file.close
end
@ -150,8 +150,8 @@ RSpec.describe BulkUpload::Sales::Validator do
let(:log) { build(:sales_log, :completed) }
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
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.close
end
@ -163,7 +163,7 @@ RSpec.describe BulkUpload::Sales::Validator do
describe "#create_logs?" do
around do |example|
Timecop.freeze(Time.zone.local(2023, 2, 22)) do
Timecop.freeze(Time.zone.local(2023, 10, 22)) do
Singleton.__init__(FormHandler)
example.run
end
@ -172,15 +172,7 @@ RSpec.describe BulkUpload::Sales::Validator do
end
context "when all logs are valid" do
let(:target_path) { file_fixture("completed_2022_23_sales_bulk_upload.csv") }
before do
target_array = File.open(target_path).readlines
target_array[0..118].each do |line|
file.write line
end
file.rewind
end
let(:target_path) { file_fixture("2023_24_sales_bulk_upload.csv") }
it "returns truthy" do
validator.call
@ -189,7 +181,7 @@ RSpec.describe BulkUpload::Sales::Validator do
end
context "when there is an invalid log" do
let(:path) { file_fixture("2022_23_sales_bulk_upload.csv") }
let(:path) { file_fixture("2023_24_sales_bulk_upload_invalid.csv") }
it "returns falsey" do
validator.call
@ -202,8 +194,8 @@ RSpec.describe BulkUpload::Sales::Validator do
let(:log_2) { build(:sales_log, :completed, created_by: user) }
before do
file.write(BulkUpload::SalesLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log: log_2, line_ending: "\r\n", col_offset: 0, overrides: { organisation_id: "random" }).to_2022_csv_row)
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
@ -214,14 +206,7 @@ RSpec.describe BulkUpload::Sales::Validator do
end
context "when all logs valid?" do
let(:log_1) { build(:sales_log, :completed, created_by: user) }
let(:log_2) { build(:sales_log, :completed, created_by: user) }
before do
file.write(BulkUpload::SalesLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log: log_2, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.close
end
let(:path) { file_fixture("2023_24_sales_bulk_upload.csv") }
it "returns true" do
validator.call
@ -235,7 +220,7 @@ RSpec.describe BulkUpload::Sales::Validator do
let(:log_1) { build(:sales_log, :completed, created_by: user, owning_organisation: unaffiliated_org) }
before do
file.write(BulkUpload::SalesLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_2023_csv_row)
file.close
end
@ -249,7 +234,7 @@ RSpec.describe BulkUpload::Sales::Validator do
let(:log) { build(:sales_log, created_by: user, saledate: Time.zone.local(2022, 5, 1)) }
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2022_csv_row)
file.write(BulkUpload::SalesLogToCsv.new(log:, line_ending: "\r\n", col_offset: 0).to_2023_csv_row)
file.close
end
@ -262,7 +247,7 @@ RSpec.describe BulkUpload::Sales::Validator do
describe "#total_logs_count?" do
around do |example|
Timecop.freeze(Time.zone.local(2023, 2, 22)) do
Timecop.freeze(Time.zone.local(2023, 10, 22)) do
Singleton.__init__(FormHandler)
example.run
end
@ -271,7 +256,7 @@ RSpec.describe BulkUpload::Sales::Validator do
end
context "when all logs are valid" do
let(:target_path) { file_fixture("completed_2022_23_sales_bulk_upload.csv") }
let(:target_path) { file_fixture("2023_24_sales_bulk_upload.csv") }
before do
target_array = File.open(target_path).readlines

150
spec/services/bulk_upload/sales/year2022/csv_parser_spec.rb

@ -1,150 +0,0 @@
require "rails_helper"
RSpec.describe BulkUpload::Sales::Year2022::CsvParser do
subject(:service) { described_class.new(path:) }
let(:path) { file_fixture("completed_2022_23_sales_bulk_upload.csv") }
context "when parsing csv with headers" do
it "returns correct offsets" do
expect(service.row_offset).to eq(5)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_7.to_i).to eq(32)
end
end
context "when parsing csv without headers" 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_2022_csv_row)
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(0)
expect(service.col_offset).to eq(0)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_7.to_i).to eql(log.age1)
end
end
context "when parsing with BOM aka byte order mark" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed) }
let(:bom) { "\uFEFF" }
before do
file.write(bom)
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.close
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_7.to_i).to eql(log.age1)
end
end
context "when an invalid byte sequence" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed) }
let(:invalid_sequence) { "\x81" }
before do
file.write(invalid_sequence)
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.close
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_7.to_i).to eql(log.age1)
end
end
describe "#column_for_field", aggregate_failures: true do
context "when headers present" do
it "returns correct column" do
expect(service.column_for_field("field_1")).to eql("B")
expect(service.column_for_field("field_125")).to eql("DV")
end
end
context "when no headers" 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_2022_csv_row)
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_1")).to eql("A")
expect(service.column_for_field("field_125")).to eql("DU")
end
end
end
context "when parsing csv with carriage returns" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed) }
before do
file.write("Question\r\n")
file.write("Additional info\r")
file.write("Values\r\n")
file.write("Can be empty?\r")
file.write("Type of letting the question applies to\r\n")
file.write("Duplicate check field?\r")
file.write(BulkUpload::SalesLogToCsv.new(log:).to_2022_csv_row)
file.rewind
end
it "parses csv correctly" do
expect(service.column_for_field("field_1")).to eql("A")
expect(service.column_for_field("field_125")).to eql("DU")
end
end
describe "#wrong_template_for_year?" do
let(:file) { Tempfile.new }
let(:path) { file.path }
context "when 23/24 file with 23/24 data" do
let(:log) { build(:sales_log, :completed, saledate: Date.new(2024, 1, 1)) }
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2023_csv_row)
file.rewind
end
it "returns true" do
expect(service).to be_wrong_template_for_year
end
end
context "when 22/23 file with 22/23 data" do
let(:log) { build(:sales_log, :completed, saledate: Date.new(2022, 10, 1)) }
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_2022_csv_row)
file.rewind
end
it "returns false" do
expect(service).not_to be_wrong_template_for_year
end
end
end
end

921
spec/services/bulk_upload/sales/year2022/row_parser_spec.rb

@ -1,921 +0,0 @@
require "rails_helper"
RSpec.describe BulkUpload::Sales::Year2022::RowParser do
subject(:parser) { described_class.new(attributes) }
let(:now) { Time.zone.parse("01/03/2023") }
let(:attributes) { { bulk_upload: } }
let(:bulk_upload) { create(:bulk_upload, :sales, user:) }
let(:user) { create(:user, organisation: owning_org) }
let(:owning_org) { create(:organisation, :with_old_visible_id) }
let(:setup_section_params) do
{
bulk_upload:,
field_1: "test id", # purchase id
field_92: owning_org.old_visible_id, # organisation
field_93: user.email, # user
field_2: now.day.to_s, # sale day
field_3: now.month.to_s, # sale month
field_4: now.strftime("%g"), # sale year
field_113: "1", # owhershipsch
field_57: "2", # shared ownership sale type
field_116: "2", # joint purchase
field_115: "1", # will the buyers live in the property
}
end
let(:valid_attributes) do
{
bulk_upload:,
field_1: "test id",
field_2: "22",
field_3: "2",
field_4: "23",
field_6: "1",
field_7: "32",
field_8: "32",
field_13: "M",
field_14: "F",
field_19: "R",
field_24: "1",
field_25: "2",
field_30: "12",
field_31: "18",
field_32: "30000",
field_33: "15000",
field_34: "1",
field_35: "1",
field_36: "20000",
field_37: "3",
field_39: "1",
field_40: "E09000008",
field_41: "A1",
field_42: "1AA",
field_43: "1",
field_45: "1",
field_46: "1",
field_48: "3",
field_49: "3",
field_50: "2",
field_51: "1",
field_52: "1",
field_53: "E09000008",
field_54: "CR0",
field_55: "4BB",
field_56: "3",
field_57: "2",
field_58: "2",
field_59: "23",
field_60: "3",
field_61: "22",
field_62: "30",
field_63: "3",
field_64: "22",
field_65: "3",
field_66: "1",
field_67: "1",
field_68: "250000",
field_69: "25",
field_70: "42500",
field_71: "3",
field_72: "20000",
field_74: "800",
field_75: "200",
field_92: owning_org.old_visible_id,
field_95: "3",
field_97: "5",
field_98: "1",
field_104: "4",
field_105: "20",
field_109: "2",
field_110: "5",
field_111: "1",
field_112: "1",
field_113: "1",
field_115: "1",
field_116: "1",
field_117: "1",
field_118: "1",
field_119: "0",
field_120: "10",
field_121: "10",
field_122: "1",
field_123: "1",
}
end
around do |example|
Timecop.freeze(Time.zone.local(2023, 2, 22)) do
Singleton.__init__(FormHandler)
example.run
end
end
describe "#blank_row?" do
context "when a new object" do
it "returns true" do
expect(parser).to be_blank_row
end
end
context "when any field is populated" do
before do
parser.field_1 = "1"
end
it "returns false" do
expect(parser).not_to be_blank_row
end
end
end
describe "purchaser_code" do
before do
def purch_id_field
described_class::QUESTIONS.key("What is the purchaser code?").to_s
end
end
let(:attributes) do
{
bulk_upload:,
purch_id_field => "some purchaser code",
}
end
it "is linked to the correct field" do
expect(parser.purchaser_code).to eq("some purchaser code")
end
end
describe "previous postcode known" do
context "when field_43 is 1" do
let(:attributes) do
{
bulk_upload:,
field_43: 1,
}
end
it "sets previous postcode known to yes" do
expect(parser.log.ppcodenk).to eq(0)
end
end
context "when field_43 is nil" do
let(:attributes) do
{
bulk_upload:,
field_43: nil,
}
end
it "sets previous postcode known to no" do
expect(parser.log.ppcodenk).to eq(1)
end
end
end
describe "validations" do
before do
stub_request(:get, /api.postcodes.io/)
.to_return(status: 200, body: "{\"status\":200,\"result\":{\"admin_district\":\"Manchester\", \"codes\":{\"admin_district\": \"E08000003\"}}}", headers: {})
parser.valid?
end
describe "#valid?" do
context "when the row is blank" do
let(:attributes) { { bulk_upload: } }
it "returns true" do
expect(parser).to be_valid
end
end
context "when calling the method multiple times" do
let(:attributes) { { bulk_upload:, field_7: 2 } }
it "does not add keep adding errors to the pile" do
expect { parser.valid? }.not_to change(parser.errors, :count)
end
end
context "when valid row" do
let(:attributes) { valid_attributes }
around do |example|
Timecop.freeze(Date.new(2023, 2, 22)) do
example.run
end
Timecop.return
end
it "returns true" do
expect(parser).to be_valid
end
it "instantiates a log with everything completed", aggregate_failures: true do
questions = parser.send(:questions).reject do |q|
parser.send(:log).optional_fields.include?(q.id) || q.completed?(parser.send(:log))
end
expect(questions.map(&:id).size).to eq(0)
expect(questions.map(&:id)).to eql([])
end
end
end
context "when setup section not complete and type is not given" do
let(:attributes) do
{
bulk_upload:,
field_1: "test id",
}
end
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute)
expect(errors).to eql(%i[field_2 field_3 field_4 field_113 field_92 field_112])
end
end
context "when setup section not complete and type is shared ownership" do
let(:attributes) do
{
bulk_upload:,
field_1: "test id",
field_113: "1",
}
end
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort
expect(errors).to eql(%i[field_112 field_116 field_2 field_3 field_4 field_57 field_92])
end
end
context "when setup section not complete it's shared ownership joint purchase" do
let(:attributes) do
{
bulk_upload:,
field_1: "test id",
field_113: "1",
field_57: "2",
field_116: "1",
}
end
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute)
expect(errors).to eql(%i[field_2 field_3 field_4 field_109 field_92 field_112])
end
end
context "when setup section not complete and type is discounted ownership" do
let(:attributes) do
{
bulk_upload:,
field_1: "test id",
field_113: "2",
}
end
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort
expect(errors).to eql(%i[field_112 field_116 field_2 field_3 field_4 field_76 field_92])
end
end
context "when setup section not complete it's discounted ownership joint purchase" do
let(:attributes) do
{
bulk_upload:,
field_1: "test id",
field_113: "2",
field_76: "8",
field_116: "1",
}
end
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute)
expect(errors).to eql(%i[field_2 field_3 field_4 field_109 field_92 field_112])
end
end
context "when setup section not complete and type is outright sale" do
let(:attributes) do
{
bulk_upload:,
field_1: "test id",
field_113: "3",
}
end
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort
expect(errors).to eql(%i[field_112 field_114 field_115 field_2 field_3 field_4 field_84 field_92])
end
end
context "when setup section not complete outright sale buyer is not company" do
let(:attributes) do
{
bulk_upload:,
field_1: "test id",
field_84: "12",
field_85: "other sale type",
field_113: "3",
field_114: "2",
}
end
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort
expect(errors).to eql(%i[field_2 field_3 field_4 field_115 field_116 field_92 field_112].sort)
end
end
describe "#field_44 - 7" do # buyers organisations
context "when all nil" do
let(:attributes) { setup_section_params.merge(field_44: nil, field_45: nil, field_46: nil, field_47: nil) }
it "returns correct errors" do
expect(parser.errors[:field_44]).to be_present
expect(parser.errors[:field_45]).to be_present
expect(parser.errors[:field_46]).to be_present
expect(parser.errors[:field_47]).to be_present
end
end
end
describe "#field_57" do # type of shared ownership scheme
context "when an invalid option" do
let(:attributes) { setup_section_params.merge(field_57: "100", field_113: "1") }
it "returns setup error" do
expect(parser.errors.where(:field_57, category: :setup).map(&:message)).to include("Enter a valid value for what is the type of shared ownership sale?")
end
end
end
describe "#field_76" do # type of discounted ownership scheme
context "when an invalid option" do
let(:attributes) { setup_section_params.merge({ field_76: "100", field_113: "2" }) }
it "returns setup error" do
expect(parser.errors.where(:field_76, category: :setup).map(&:message)).to eql(["Enter a valid value for what is the type of discounted ownership sale?"])
end
end
end
describe "#field_84" do # type of outright sale
context "when an invalid option" do
let(:attributes) { setup_section_params.merge({ field_84: "100", field_113: "3" }) }
it "returns setup error" do
expect(parser.errors.where(:field_84, category: :setup).map(&:message)).to eql(["Enter a valid value for what is the type of outright sale?"])
end
end
end
describe "#field_85" do # type of other outright sale
context "when cant be blank" do
let(:attributes) { setup_section_params.merge({ field_85: nil, field_84: "12" }) }
it "returns setup error" do
expect(parser.errors.where(:field_85, category: :setup).map(&:message)).to eql(["You must answer type of outright sale"])
end
end
end
describe "#field_92" do # owning org
context "when no data given" do
let(:attributes) { { bulk_upload:, field_92: "" } }
it "is not permitted as setup error" do
setup_errors = parser.errors.select { |e| e.options[:category] == :setup }
expect(setup_errors.find { |e| e.attribute == :field_92 }.message).to eql("You must answer owning organisation")
end
it "blocks log creation" do
expect(parser).to be_block_log_creation
end
end
context "when cannot find owning org" do
let(:attributes) { { bulk_upload:, field_92: "donotexist" } }
it "is not permitted as a setup error" do
setup_errors = parser.errors.select { |e| e.options[:category] == :setup }
expect(setup_errors.find { |e| e.attribute == :field_92 }.message).to eql("You must answer owning organisation")
end
it "blocks log creation" do
expect(parser).to be_block_log_creation
end
end
context "when not affiliated with owning org" do
let(:unaffiliated_org) { create(:organisation, :with_old_visible_id) }
let(:attributes) { { bulk_upload:, field_92: unaffiliated_org.old_visible_id } }
it "is not permitted as setup error" do
setup_errors = parser.errors.select { |e| e.options[:category] == :setup }
expect(setup_errors.find { |e| e.attribute == :field_92 }.message).to eql("You do not have permission to add logs for this owning organisation")
end
it "blocks log creation" do
expect(parser).to be_block_log_creation
end
end
end
context "when type is shared ownership" do
let(:attributes) { valid_attributes.merge({ field_113: 1, field_68: nil }) }
it "has error on correct fields" do
expect(parser.errors).to include(:field_68)
end
end
context "when type is discounted ownership" do
let(:attributes) { valid_attributes.merge({ field_113: 2, field_77: nil }) }
it "has error on correct fields" do
expect(parser.errors).to include(:field_77)
end
end
context "when type is outright sale" do
let(:attributes) { valid_attributes.merge({ field_113: 3, field_87: nil }) }
it "has error on correct fields" do
expect(parser.errors).to include(:field_87)
end
end
describe "#field_93" do # username for created_by
context "when blank" do
let(:attributes) { { bulk_upload:, field_93: "" } }
it "is permitted" do
expect(parser.errors[:field_93]).to be_blank
end
end
context "when user could not be found" do
let(:attributes) { { bulk_upload:, field_93: "idonotexist@example.com" } }
it "is not permitted" do
expect(parser.errors[:field_93]).to be_present
end
end
context "when an unaffiliated user" do
let(:other_user) { create(:user) }
let(:attributes) { { bulk_upload:, field_92: owning_org.old_visible_id, field_93: other_user.email } }
it "is not permitted" do
expect(parser.errors[:field_93]).to be_present
end
it "blocks log creation" do
expect(parser).to be_block_log_creation
end
end
context "when an user part of owning org" do
let(:other_user) { create(:user, organisation: owning_org) }
let(:attributes) { { bulk_upload:, field_92: owning_org.old_visible_id, field_93: other_user.email } }
it "is permitted" do
expect(parser.errors[:field_93]).to be_blank
end
end
context "when email matches other than casing" do
let(:other_user) { create(:user, organisation: owning_org) }
let(:attributes) { { bulk_upload:, field_92: owning_org.old_visible_id, field_93: other_user.email.upcase! } }
it "is permitted" do
expect(parser.errors[:field_93]).to be_blank
end
end
end
[
%w[age1_known age1 field_7],
%w[age2_known age2 field_8],
%w[age3_known age3 field_9],
%w[age4_known age4 field_10],
%w[age5_known age5 field_11],
%w[age6_known age6 field_12],
].each do |known, age, field|
describe "##{known} and ##{age}" do
context "when #{field} is blank" do
let(:attributes) { { bulk_upload:, field.to_s => nil } }
it "sets ##{known} 1" do
expect(parser.log.public_send(known)).to be(1)
end
it "sets ##{age} to nil" do
expect(parser.log.public_send(age)).to be_nil
end
end
context "when #{field} is R" do
let(:attributes) { setup_section_params.merge({ field.to_s => "R", field_6: "1", field_119: "5", field_112: "1" }) }
it "sets ##{known} 1" do
expect(parser.log.public_send(known)).to be(1)
end
it "sets ##{age} to nil" do
expect(parser.log.public_send(age)).to be_nil
end
end
context "when #{field} is a number" do
let(:attributes) { setup_section_params.merge({ field.to_s => "50", field_6: "1", field_119: "5", field_112: "1" }) }
it "sets ##{known} to 0" do
expect(parser.log.public_send(known)).to be(0)
end
it "sets ##{age} to given age" do
expect(parser.log.public_send(age)).to be(50)
end
end
context "when #{field} is a non-sensical value" do
let(:attributes) { setup_section_params.merge({ field.to_s => "A", field_6: "1", field_119: "5", field_112: "1" }) }
it "sets ##{known} to 0" do
expect(parser.log.public_send(known)).to be(0)
end
it "sets ##{age} to nil" do
expect(parser.log.public_send(age)).to be_nil
end
end
end
end
describe "#field_109" do # more that 2 joint purchasers?
context "when an invalid option" do
let(:attributes) { setup_section_params.merge({ field_109: "100", field_116: "1" }) }
it "returns setup error" do
expect(parser.errors.where(:field_109, category: :setup).map(&:message)).to include("Enter a valid value for are there more than two joint purchasers of this property?")
end
end
end
describe "#field_112" do # data protection
context "when not accepted" do
let(:attributes) { setup_section_params.merge(field_112: nil) }
it "returns setup error" do
expect(parser.errors.where(:field_112, category: :setup).map(&:message)).to eql(["You must answer data protection question"])
end
end
end
describe "#field_113" do # purchase made thru ownership scheme?
context "when an invalid option" do
let(:attributes) { setup_section_params.merge({ field_113: "100" }) }
it "returns setup error" do
expect(parser.errors.where(:field_113, category: :setup).map(&:message)).to include("Enter a valid value for was this purchase made through an ownership scheme?")
end
end
end
describe "#field_114" do # is buyer a company?
context "when an invalid option" do
let(:attributes) { setup_section_params.merge({ field_114: "100", field_113: "3" }) }
it "returns setup error" do
expect(parser.errors.where(:field_114, category: :setup).map(&:message)).to include("Enter a valid value for is the buyer a company?")
end
end
end
describe "#field_115" do # will buyers live in property?
context "when an invalid option" do
let(:attributes) { setup_section_params.merge({ field_115: "100", field_113: "3", field_114: "2" }) }
it "returns setup error" do
expect(parser.errors.where(:field_115, category: :setup).map(&:message)).to include("Enter a valid value for will the buyers live in the property?")
end
end
end
describe "#field_116" do # joint purchase?
context "when an invalid option" do
let(:attributes) { setup_section_params.merge({ field_116: "100" }) }
it "returns setup error" do
expect(parser.errors.where(:field_116, category: :setup).map(&:message)).to include("Enter a valid value for is this a joint purchase?")
end
end
end
describe "#field_117" do
context "when not a possible value" do
let(:attributes) { valid_attributes.merge({ field_117: "3" }) }
it "is not valid" do
expect(parser.errors).to include(:field_117)
end
end
end
describe "field_24" do # ecstat1
context "when buyer 1 is marked as a child" do
let(:attributes) { valid_attributes.merge({ field_24: 9 }) }
it "a custom validation is applied" do
validation_message = "Buyer 1 cannot be a child under 16"
expect(parser.errors[:field_24]).to include validation_message
end
end
end
describe "fields 2, 3, 4 => saledate" do
context "when all of these fields are blank" do
let(:attributes) { setup_section_params.merge({ field_2: nil, field_3: nil, field_4: nil }) }
it "returns them as setup errors" do
expect(parser.errors.where(:field_2, category: :setup)).to be_present
expect(parser.errors.where(:field_3, category: :setup)).to be_present
expect(parser.errors.where(:field_4, category: :setup)).to be_present
end
end
context "when one of these fields is blank" do
let(:attributes) { setup_section_params.merge({ field_2: "1", field_3: "1", field_4: nil }) }
it "returns an error only on blank field" do
expect(parser.errors[:field_2]).to be_blank
expect(parser.errors[:field_3]).to be_blank
expect(parser.errors[:field_4]).to be_present
end
end
context "when field 4 is 4 digits instead of 2" do
let(:attributes) { setup_section_params.merge({ bulk_upload:, field_4: "2022" }) }
it "returns an error" do
expect(parser.errors[:field_4]).to include("Sale completion year must be 2 digits")
end
end
context "when invalid date given" do
let(:attributes) { setup_section_params.merge({ field_2: "a", field_3: "12", field_4: "2022" }) }
it "does not raise an error" do
expect { parser.valid? }.not_to raise_error
end
end
context "when inside of collection year" do
let(:attributes) { setup_section_params.merge({ field_2: "1", field_3: "10", field_4: "22" }) }
let(:bulk_upload) { create(:bulk_upload, :sales, user:, year: 2022) }
it "does not return errors" do
expect(parser.errors[:field_2]).not_to be_present
expect(parser.errors[:field_3]).not_to be_present
expect(parser.errors[:field_4]).not_to be_present
end
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) { setup_section_params.merge({ field_2: "1", field_3: "1", field_4: "22" }) }
let(:bulk_upload) { create(:bulk_upload, :sales, user:, year: 2022) }
it "returns setup errors" do
expect(parser.errors.where(:field_2, category: :setup)).to be_present
expect(parser.errors.where(:field_3, category: :setup)).to be_present
expect(parser.errors.where(:field_4, category: :setup)).to be_present
end
end
end
describe "soft validations" do
context "when soft validation is triggered" do
let(:attributes) { valid_attributes.merge({ field_7: 22, field_24: 5 }) }
it "adds an error to the relevant fields" do
expect(parser.errors.where(:field_7, category: :soft_validation)).to be_present
expect(parser.errors.where(:field_24, category: :soft_validation)).to be_present
end
it "populates with correct error message" do
expect(parser.errors.where(:field_7, category: :soft_validation).first.message).to eql("You told us this person is aged 22 years and retired.")
expect(parser.errors.where(:field_24, category: :soft_validation).first.message).to eql("You told us this person is aged 22 years and retired.")
end
end
context "when a soft validation is triggered that relates both to fields that are and are not routed to" do
let(:attributes) { valid_attributes.merge({ field_123: "2" }) }
it "adds errors to fields that are routed to" do
expect(parser.errors.where(:field_123, category: :soft_validation)).to be_present
end
it "does not add errors to fields that are not routed to" do
expect(parser.errors.where(:field_73, category: :soft_validation)).not_to be_present
expect(parser.errors.where(:field_70, category: :soft_validation)).not_to be_present
end
end
end
context "when the log already exists in the db" do
let(:attributes) { valid_attributes }
before do
parser.log.save!
parser.instance_variable_set(:@valid, nil)
end
it "is not a valid row" do
expect(parser).not_to be_valid
end
it "adds an error to all (and only) the fields used to determine duplicates" do
parser.valid?
error_message = "This is a duplicate log"
[
:field_92, # Owning org
:field_2, # Sale completion date
:field_3, # Sale completion date
:field_4, # Sale completion date
:field_41, # Postcode
:field_42, # Postcode
:field_7, # Buyer 1 age
:field_13, # Buyer 1 gender
:field_24, # Buyer 1 working situation
:field_1, # Purchaser code
].each do |field|
expect(parser.errors[field]).to include(error_message)
end
end
end
context "when a hidden log already exists in db" do
before do
parser.log.status = "pending"
parser.log.skip_update_status = true
parser.log.save!
end
it "is a valid row" do
expect(parser).to be_valid
end
it "does not add duplicate errors" do
parser.valid?
[
:field_92, # Owning org
:field_2, # Sale completion date
:field_3, # Sale completion date
:field_4, # Sale completion date
:field_41, # Postcode
:field_42, # Postcode
:field_7, # Buyer 1 age
:field_13, # Buyer 1 gender
:field_24, # Buyer 1 working situation
:field_1, # Purchaser code
].each do |field|
expect(parser.errors[field]).to be_blank
end
end
end
describe "shared ownership sale type" do
context "when 32 is selected for shared ownership type" do
let(:attributes) { valid_attributes.merge(field_113: 1, field_57: "32") }
it "is not permitted as a setup error" do
expect(parser.errors.where(:field_57, category: :setup)).to be_present
end
end
end
end
describe "inferences" do
context "when buyer not interviewed and optional values nil" do
let(:attributes) { valid_attributes.merge(field_6: "1", field_24: nil, field_30: nil, field_31: nil, field_32: nil, field_34: nil, field_36: nil, field_37: nil, field_39: nil, field_48: nil, field_49: nil) }
it "infers correctly" do
log = parser.log
expect(log["noint"]).to eq(1)
expect(log["ecstat1"]).to eq(10)
expect(log["ethnic"]).to eq(nil)
expect(log["ethnic_group"]).to eq(17)
expect(log["national"]).to eq(13)
expect(log["income1nk"]).to eq(1)
expect(log["inc1mort"]).to eq(2)
expect(log["savingsnk"]).to eq(1)
expect(log["prevown"]).to eq(3)
expect(log["prevten"]).to eq(0)
expect(log["disabled"]).to eq(3)
expect(log["wheel"]).to eq(3)
end
end
context "when buyer not interviewed and optional values present" do
let(:attributes) { valid_attributes.merge(field_6: "1", field_24: "1", field_30: "1", field_31: "1", field_32: "1", field_34: "1", field_36: "1", field_37: "1", field_39: "1", field_48: "1", field_49: "1") }
it "does not override variables correctly" do
log = parser.log
expect(log["noint"]).to eq(1)
expect(log["ecstat1"]).to eq(1)
expect(log["ethnic"]).to eq(1)
expect(log["ethnic_group"]).to eq(0)
expect(log["national"]).to eq(1)
expect(log["income1nk"]).to eq(0)
expect(log["inc1mort"]).to eq(1)
expect(log["savingsnk"]).to eq(0)
expect(log["prevown"]).to eq(1)
expect(log["prevten"]).to eq(1)
expect(log["disabled"]).to eq(1)
expect(log["wheel"]).to eq(1)
end
end
context "when mscharge is given, but is set to 0 for shared ownership" do
let(:attributes) { valid_attributes.merge(field_75: "0") }
it "does not override variables correctly" do
log = parser.log
expect(log["has_mscharge"]).to eq(0) # no
expect(log["mscharge"]).to be_nil
end
end
context "when mscharge is given, but is set to 0 for discounted ownership" do
let(:attributes) { valid_attributes.merge(field_113: "2", field_76: "8", field_83: "0") }
it "does not override variables correctly" do
log = parser.log
expect(log["has_mscharge"]).to eq(0) # no
expect(log["mscharge"]).to be_nil
end
end
context "when mscharge is given, but is set to 0 for outright sale" do
let(:attributes) { valid_attributes.merge(field_113: "3", field_91: "0") }
it "does not override variables correctly" do
log = parser.log
expect(log["has_mscharge"]).to eq(0) # no
expect(log["mscharge"]).to be_nil
end
end
end
describe "#spreadsheet_duplicate_hash" do
it "returns a hash" do
expect(parser.spreadsheet_duplicate_hash).to be_a(Hash)
end
end
describe "#add_duplicate_found_in_spreadsheet_errors" do
it "adds errors" do
expect { parser.add_duplicate_found_in_spreadsheet_errors }.to change(parser.errors, :size)
end
end
end
Loading…
Cancel
Save