|
|
|
|
@ -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 |
|
|
|
|
|
|
|
|
|
|