From 37faca4a120b23af5a2bc278076bd47e990fe5b7 Mon Sep 17 00:00:00 2001 From: samyou-softwire Date: Tue, 10 Mar 2026 16:49:24 +0000 Subject: [PATCH] CLDC-4270: Add an error for fields with the wrong type for 2026 lettings --- .../lettings/year2026/csv_parser.rb | 30 +++++++++++++++++-- .../lettings/year2026/row_parser.rb | 17 +++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/app/services/bulk_upload/lettings/year2026/csv_parser.rb b/app/services/bulk_upload/lettings/year2026/csv_parser.rb index d2f1ab7b1..37182c269 100644 --- a/app/services/bulk_upload/lettings/year2026/csv_parser.rb +++ b/app/services/bulk_upload/lettings/year2026/csv_parser.rb @@ -9,6 +9,8 @@ class BulkUpload::Lettings::Year2026::CsvParser attr_reader :path + ROW_PARSER_CLASS = BulkUpload::Lettings::Year2026::RowParser + def initialize(path:) @path = path end @@ -34,11 +36,35 @@ class BulkUpload::Lettings::Year2026::CsvParser @row_parsers ||= body_rows.map { |row| next if row.empty? + invalid_fields = [] stripped_row = row[col_offset..] - hash = Hash[field_numbers.zip(stripped_row)] + hash_rows = field_numbers + .zip(stripped_row) + .map do |field, value| + # this is needed as a string passed to an int attribute is by default mapped to '0'. + # this is bad as some questions will accept a '0'. so you could enter something invalid and not be told about it + expected_is_integer = ROW_PARSER_CLASS.attribute_types[field].is_a?(ActiveModel::Type::Integer) + # we must be certain that the user entered a string that cannot be coerced to an integer + actual_is_non_empty_string = value.present? && Integer(value, exception: false).nil? && Float(value, exception: false).nil? + field_is_valid = !(expected_is_integer && actual_is_non_empty_string) + + correct_value = field_is_valid ? value : nil + + invalid_fields << field unless field_is_valid + + [field, correct_value] + end + + hash = Hash[hash_rows] + + row_parser = ROW_PARSER_CLASS.new(hash) + + invalid_fields.each do |field| + row_parser.add_invalid_field(field) + end - BulkUpload::Lettings::Year2026::RowParser.new(hash) + row_parser }.compact end diff --git a/app/services/bulk_upload/lettings/year2026/row_parser.rb b/app/services/bulk_upload/lettings/year2026/row_parser.rb index 577a48190..c05bfe667 100644 --- a/app/services/bulk_upload/lettings/year2026/row_parser.rb +++ b/app/services/bulk_upload/lettings/year2026/row_parser.rb @@ -541,6 +541,8 @@ class BulkUpload::Lettings::Year2026::RowParser end end + add_errors_for_invalid_fields + @valid = errors.blank? end @@ -620,6 +622,10 @@ class BulkUpload::Lettings::Year2026::RowParser end end + def add_invalid_field(field) + invalid_fields << field + end + private def normalise_case_insensitive_fields @@ -1098,6 +1104,17 @@ private end end + def invalid_fields + @invalid_fields ||= [] + end + + def add_errors_for_invalid_fields + invalid_fields.each do |field| + errors.delete(field) # take precedence over any other errors as this is a BU format issue + errors.add(field, I18n.t("#{ERROR_BASE_KEY}.invalid_option", question: QUESTIONS[field.to_sym])) + end + end + def field_mapping_for_errors { lettype: [:field_11],