Browse Source
* Remove 2022/23 BU code * Add empty lines to csvs * Update feature tests * More tests * Remove forms and update a test * rebase testspull/2170/head
kosiakkatrina
11 months ago
committed by
GitHub
51 changed files with 229 additions and 7029 deletions
@ -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 |
File diff suppressed because it is too large
Load Diff
@ -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 |
File diff suppressed because it is too large
Load Diff
@ -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> |
@ -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> |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Can't render this file because it has a wrong number of fields in line 72.
|
|
Binary file not shown.
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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 |
File diff suppressed because it is too large
Load Diff
@ -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 |
@ -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…
Reference in new issue