From be87727fdbdea1f262101a82fd9ffdcb25b97e78 Mon Sep 17 00:00:00 2001 From: Samuel Young Date: Mon, 16 Feb 2026 16:38:40 +0000 Subject: [PATCH 1/4] CLDC-4012: Add case-sensitive function for 2025 --- .../lettings/year2025/row_parser.rb | 29 +++++++++++++++++ .../bulk_upload/sales/year2025/row_parser.rb | 32 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/app/services/bulk_upload/lettings/year2025/row_parser.rb b/app/services/bulk_upload/lettings/year2025/row_parser.rb index 0745056d2..ac508f2c2 100644 --- a/app/services/bulk_upload/lettings/year2025/row_parser.rb +++ b/app/services/bulk_upload/lettings/year2025/row_parser.rb @@ -148,6 +148,26 @@ class BulkUpload::Lettings::Year2025::RowParser ERROR_BASE_KEY = "validations.lettings.2025.bulk_upload".freeze + CASE_INSENSITIVE_FIELDS = [ + :field_42, # What is the lead tenant’s age? + :field_48, # What is person 2’s age? + :field_52, # What is person 3’s age? + :field_56, # What is person 4’s age? + :field_60, # What is person 5’s age? + :field_64, # What is person 6’s age? + :field_68, # What is person 7’s age? + :field_72, # What is person 8’s age? + + :field_43, # Which of these best describes the lead tenant’s gender identity? + :field_49, # Which of these best describes person 2’s gender identity? + :field_53, # Which of these best describes person 3’s gender identity? + :field_57, # Which of these best describes person 4’s gender identity? + :field_61, # Which of these best describes person 5’s gender identity? + :field_65, # Which of these best describes person 6’s gender identity? + :field_69, # Which of these best describes person 7’s gender identity? + :field_73, # Which of these best describes person 8’s gender identity? + ].freeze + attribute :bulk_upload attribute :block_log_creation, :boolean, default: -> { false } @@ -459,6 +479,8 @@ class BulkUpload::Lettings::Year2025::RowParser return @valid = true if blank_row? + normalise_case_insensitive_fields + super(:before_log) @before_errors = errors.dup @@ -560,6 +582,13 @@ class BulkUpload::Lettings::Year2025::RowParser private + def normalise_case_insensitive_fields + CASE_INSENSITIVE_FIELDS.each do |field| + value = send(field) + send("#{field}=", value.upcase) if value.present? + end + end + def validate_valid_radio_option log.attributes.each do |question_id, _v| question = log.form.get_question(question_id, log) diff --git a/app/services/bulk_upload/sales/year2025/row_parser.rb b/app/services/bulk_upload/sales/year2025/row_parser.rb index a78b9fe5d..8e406dcd0 100644 --- a/app/services/bulk_upload/sales/year2025/row_parser.rb +++ b/app/services/bulk_upload/sales/year2025/row_parser.rb @@ -139,6 +139,29 @@ class BulkUpload::Sales::Year2025::RowParser ERROR_BASE_KEY = "validations.sales.2025.bulk_upload".freeze + CASE_INSENSITIVE_FIELDS = [ + :field_28, # Age of buyer 1 + :field_35, # Age of person 2 + :field_43, # Age of person 3 + :field_47, # Age of person 4 + :field_51, # Age of person 5 + :field_55, # Age of person 6 + + :field_29, # Gender identity of buyer 1 + :field_36, # Gender identity of person 2 + :field_44, # Gender identity of person 3 + :field_48, # Gender identity of person 4 + :field_52, # Gender identity of person 5 + :field_56, # Gender identity of person 6 + + :field_58, # What was buyer 1’s previous tenure? + :field_64, # What was buyer 2’s previous tenure? + + :field_75, # What is the total amount the buyers had in savings before they paid any deposit for the property? + :field_70, # What is buyer 1’s gross annual income? + :field_72, # What is buyer 2’s gross annual income? + ].freeze + attribute :bulk_upload attribute :block_log_creation, :boolean, default: -> { false } @@ -454,6 +477,8 @@ class BulkUpload::Sales::Year2025::RowParser return true if blank_row? + normalise_case_insensitive_fields + super(:before_log) @before_errors = errors.dup @@ -525,6 +550,13 @@ class BulkUpload::Sales::Year2025::RowParser private + def normalise_case_insensitive_fields + CASE_INSENSITIVE_FIELDS.each do |field| + value = send(field) + send("#{field}=", value.upcase) if value.present? + end + end + def prevtenbuy2 case field_64 when "R" From 7482a0148140f78adefd1760b2ac40f43e1a8be2 Mon Sep 17 00:00:00 2001 From: Samuel Young Date: Mon, 16 Feb 2026 17:24:11 +0000 Subject: [PATCH 2/4] CLDC-4012: Add case-sensitive function for 2026 --- .../lettings/year2026/row_parser.rb | 29 +++++++++++++++++ .../bulk_upload/sales/year2026/row_parser.rb | 32 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/app/services/bulk_upload/lettings/year2026/row_parser.rb b/app/services/bulk_upload/lettings/year2026/row_parser.rb index 02484aafd..6ecf214a6 100644 --- a/app/services/bulk_upload/lettings/year2026/row_parser.rb +++ b/app/services/bulk_upload/lettings/year2026/row_parser.rb @@ -173,6 +173,26 @@ class BulkUpload::Lettings::Year2026::RowParser ERROR_BASE_KEY = "validations.lettings.2026.bulk_upload".freeze + CASE_INSENSITIVE_FIELDS = [ + :field_42, # What is the lead tenant’s age? + :field_48, # What is person 2’s age? + :field_52, # What is person 3’s age? + :field_56, # What is person 4’s age? + :field_60, # What is person 5’s age? + :field_64, # What is person 6’s age? + :field_68, # What is person 7’s age? + :field_72, # What is person 8’s age? + + :field_130, # What is the lead tenant's sex? + :field_131, # What is person 2's sex? + :field_132, # What is person 3's sex? + :field_133, # What is person 4's sex? + :field_134, # What is person 5's sex? + :field_135, # What is person 6's sex? + :field_136, # What is person 7's sex? + :field_137, # What is person 8's sex? + ].freeze + attribute :bulk_upload attribute :block_log_creation, :boolean, default: -> { false } @@ -509,6 +529,8 @@ class BulkUpload::Lettings::Year2026::RowParser return @valid = true if blank_row? + normalise_case_insensitive_fields + super(:before_log) @before_errors = errors.dup @@ -615,6 +637,13 @@ class BulkUpload::Lettings::Year2026::RowParser private + def normalise_case_insensitive_fields + CASE_INSENSITIVE_FIELDS.each do |field| + value = send(field) + send("#{field}=", value.upcase) if value.present? + end + end + def validate_valid_radio_option log.attributes.each do |question_id, _v| question = log.form.get_question(question_id, log) diff --git a/app/services/bulk_upload/sales/year2026/row_parser.rb b/app/services/bulk_upload/sales/year2026/row_parser.rb index adb7cc6a2..7659d0fb6 100644 --- a/app/services/bulk_upload/sales/year2026/row_parser.rb +++ b/app/services/bulk_upload/sales/year2026/row_parser.rb @@ -146,6 +146,29 @@ class BulkUpload::Sales::Year2026::RowParser ERROR_BASE_KEY = "validations.sales.2026.bulk_upload".freeze + CASE_INSENSITIVE_FIELDS = [ + :field_28, # Age of buyer 1 + :field_35, # Age of person 2 + :field_43, # Age of person 3 + :field_47, # Age of person 4 + :field_51, # Age of person 5 + :field_55, # Age of person 6 + + :field_122, # Buyer 1's sex, as registered at birth + :field_123, # Buyer/Person 2's sex, as registered at birth + :field_124, # Person 3's sex, as registered at birth + :field_125, # Person 4's sex, as registered at birth + :field_126, # Person 5's sex, as registered at birth + :field_127, # Person 6's sex, as registered at birth + + :field_58, # What was buyer 1’s previous tenure? + :field_64, # What was buyer 2’s previous tenure? + + :field_75, # What is the total amount the buyers had in savings before they paid any deposit for the property? + :field_70, # What is buyer 1’s gross annual income? + :field_72, # What is buyer 2’s gross annual income? + ].freeze + attribute :bulk_upload attribute :block_log_creation, :boolean, default: -> { false } @@ -468,6 +491,8 @@ class BulkUpload::Sales::Year2026::RowParser return true if blank_row? + normalise_case_insensitive_fields + super(:before_log) @before_errors = errors.dup @@ -540,6 +565,13 @@ class BulkUpload::Sales::Year2026::RowParser private + def normalise_case_insensitive_fields + CASE_INSENSITIVE_FIELDS.each do |field| + value = send(field) + send("#{field}=", value.upcase) if value.present? + end + end + def prevtenbuy2 case field_64 when "R" From 588aba2dad9af7601989666407a07bbaf5c80a1e Mon Sep 17 00:00:00 2001 From: Samuel Young Date: Mon, 16 Feb 2026 17:44:17 +0000 Subject: [PATCH 3/4] CLDC-4012: Add tests --- .../bulk_upload/lettings/year2025/row_parser_spec.rb | 9 +++++++++ .../bulk_upload/lettings/year2026/row_parser_spec.rb | 11 ++++++++++- .../bulk_upload/sales/year2025/row_parser_spec.rb | 9 +++++++++ .../bulk_upload/sales/year2026/row_parser_spec.rb | 9 +++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/spec/services/bulk_upload/lettings/year2025/row_parser_spec.rb b/spec/services/bulk_upload/lettings/year2025/row_parser_spec.rb index 951838e53..6d4bf8b54 100644 --- a/spec/services/bulk_upload/lettings/year2025/row_parser_spec.rb +++ b/spec/services/bulk_upload/lettings/year2025/row_parser_spec.rb @@ -541,6 +541,15 @@ RSpec.describe BulkUpload::Lettings::Year2025::RowParser do end end end + + context "and case insensitive fields are set to lowercase" do + let(:case_insensitive_fields) { %w[field_42 field_48 field_52 field_56 field_60 field_64 field_68 field_72 field_43 field_49 field_53 field_57 field_61 field_65 field_69 field_73] } + let(:attributes) { valid_attributes.merge(case_insensitive_fields.each_with_object({}) { |field, h| h[field.to_sym] = valid_attributes[field.to_sym]&.downcase }) } + + it "is still valid" do + expect(parser).to be_valid + end + end end context "when valid row with valid decimal (integer) field_11" do diff --git a/spec/services/bulk_upload/lettings/year2026/row_parser_spec.rb b/spec/services/bulk_upload/lettings/year2026/row_parser_spec.rb index a85bdebbb..35c62b467 100644 --- a/spec/services/bulk_upload/lettings/year2026/row_parser_spec.rb +++ b/spec/services/bulk_upload/lettings/year2026/row_parser_spec.rb @@ -151,7 +151,7 @@ RSpec.describe BulkUpload::Lettings::Year2026::RowParser do field_15: "1", field_42: "42", - field_48: "41", + field_48: "R", field_52: "17", field_56: "18", field_60: "16", @@ -569,6 +569,15 @@ RSpec.describe BulkUpload::Lettings::Year2026::RowParser do end end end + + context "and case insensitive fields are set to lowercase" do + let(:case_insensitive_fields) { %w[field_42 field_48 field_52 field_56 field_60 field_64 field_68 field_72 field_130 field_131 field_132 field_133 field_134 field_135 field_136 field_137] } + let(:attributes) { valid_attributes.merge(case_insensitive_fields.each_with_object({}) { |field, h| h[field.to_sym] = valid_attributes[field.to_sym]&.downcase }) } + + it "is still valid" do + expect(parser).to be_valid + end + end end context "when valid row with valid decimal (integer) field_11" do diff --git a/spec/services/bulk_upload/sales/year2025/row_parser_spec.rb b/spec/services/bulk_upload/sales/year2025/row_parser_spec.rb index 0074b3712..4b60b1332 100644 --- a/spec/services/bulk_upload/sales/year2025/row_parser_spec.rb +++ b/spec/services/bulk_upload/sales/year2025/row_parser_spec.rb @@ -292,6 +292,15 @@ RSpec.describe BulkUpload::Sales::Year2025::RowParser do expect(questions.map(&:id).size).to eq(0) expect(questions.map(&:id)).to eql([]) end + + context "and case insensitive fields are set to lowercase" do + let(:case_insensitive_fields) { %w[field_28 field_35 field_43 field_47 field_51 field_55 field_29 field_36 field_44 field_48 field_52 field_56 field_58 field_64 field_75 field_70 field_72] } + let(:attributes) { valid_attributes.merge(case_insensitive_fields.each_with_object({}) { |field, h| h[field.to_sym] = valid_attributes[field.to_sym]&.downcase }) } + + it "is still valid" do + expect(parser).to be_valid + end + end end describe "#validate_nulls" do diff --git a/spec/services/bulk_upload/sales/year2026/row_parser_spec.rb b/spec/services/bulk_upload/sales/year2026/row_parser_spec.rb index f9fb2aa2c..ab5e18f9f 100644 --- a/spec/services/bulk_upload/sales/year2026/row_parser_spec.rb +++ b/spec/services/bulk_upload/sales/year2026/row_parser_spec.rb @@ -298,6 +298,15 @@ RSpec.describe BulkUpload::Sales::Year2026::RowParser do expect(questions.map(&:id).size).to eq(0) expect(questions.map(&:id)).to eql([]) end + + context "and case insensitive fields are set to lowercase" do + let(:case_insensitive_fields) { %w[field_28 field_35 field_43 field_47 field_51 field_55 field_122 field_123 field_124 field_125 field_126 field_127 field_58 field_64 field_75 field_70 field_72] } + let(:attributes) { valid_attributes.merge(case_insensitive_fields.each_with_object({}) { |field, h| h[field.to_sym] = valid_attributes[field.to_sym]&.downcase }) } + + it "is still valid" do + expect(parser).to be_valid + end + end end describe "#validate_nulls" do From 65beeee8e90c9f23c41ec56461afefec802a1d2d Mon Sep 17 00:00:00 2001 From: Samuel Young Date: Tue, 17 Feb 2026 09:30:06 +0000 Subject: [PATCH 4/4] CLDC-4012: Remove integer attributes --- app/services/bulk_upload/sales/year2025/row_parser.rb | 1 - app/services/bulk_upload/sales/year2026/row_parser.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/app/services/bulk_upload/sales/year2025/row_parser.rb b/app/services/bulk_upload/sales/year2025/row_parser.rb index 8e406dcd0..dd5a65adf 100644 --- a/app/services/bulk_upload/sales/year2025/row_parser.rb +++ b/app/services/bulk_upload/sales/year2025/row_parser.rb @@ -154,7 +154,6 @@ class BulkUpload::Sales::Year2025::RowParser :field_52, # Gender identity of person 5 :field_56, # Gender identity of person 6 - :field_58, # What was buyer 1’s previous tenure? :field_64, # What was buyer 2’s previous tenure? :field_75, # What is the total amount the buyers had in savings before they paid any deposit for the property? diff --git a/app/services/bulk_upload/sales/year2026/row_parser.rb b/app/services/bulk_upload/sales/year2026/row_parser.rb index 7659d0fb6..c541e0941 100644 --- a/app/services/bulk_upload/sales/year2026/row_parser.rb +++ b/app/services/bulk_upload/sales/year2026/row_parser.rb @@ -161,7 +161,6 @@ class BulkUpload::Sales::Year2026::RowParser :field_126, # Person 5's sex, as registered at birth :field_127, # Person 6's sex, as registered at birth - :field_58, # What was buyer 1’s previous tenure? :field_64, # What was buyer 2’s previous tenure? :field_75, # What is the total amount the buyers had in savings before they paid any deposit for the property?