From 36050f4d91fab8083892a230ed15f6a420283767 Mon Sep 17 00:00:00 2001 From: oscar-richardson-softwire Date: Tue, 27 Jan 2026 15:38:20 +0000 Subject: [PATCH] Fix tests --- .../lettings/year2026/row_parser.rb | 65 ++- .../lettings/year2026/row_parser_spec.rb | 471 ++++++++++-------- 2 files changed, 296 insertions(+), 240 deletions(-) diff --git a/app/services/bulk_upload/lettings/year2026/row_parser.rb b/app/services/bulk_upload/lettings/year2026/row_parser.rb index 84f6f57d9..700084724 100644 --- a/app/services/bulk_upload/lettings/year2026/row_parser.rb +++ b/app/services/bulk_upload/lettings/year2026/row_parser.rb @@ -438,8 +438,8 @@ class BulkUpload::Lettings::Year2026::RowParser validate :validate_assigned_to_when_support, on: :after_log validate :validate_all_charges_given, on: :after_log - validate :validate_uprn_exists_if_any_key_address_fields_are_blank, on: :after_log, unless: -> { supported_housing? } - validate :validate_address_fields, on: :after_log, unless: -> { supported_housing? } + validate :validate_uprn_exists_if_any_key_address_fields_are_blank, on: :after_log + validate :validate_address_fields, on: :after_log validate :validate_incomplete_soft_validations, on: :after_log validate :validate_nationality, on: :after_log @@ -536,9 +536,9 @@ class BulkUpload::Lettings::Year2026::RowParser "field_9", # startdate "field_10", # startdate "field_13", # tenancycode - !general_needs? ? :field_6.to_s : nil, # location - !supported_housing? ? "field_23" : nil, # postcode - !supported_housing? ? "field_24" : nil, # postcode + !general_needs? ? :field_6.to_s : nil, # location # TODO: CLDC-4119: remove location from hash + !supported_housing? ? "field_23" : nil, # postcode # TODO: CLDC-4119: add postcode to hash for supported housing + !supported_housing? ? "field_24" : nil, # postcode # TODO: CLDC-4119: add postcode to hash for supported housing "field_42", # age1 "field_43", # sex1 "field_46", # ecstat1 @@ -693,8 +693,8 @@ private "ecstat1", "owning_organisation", "tcharge", - !supported_housing? ? "postcode_full" : nil, - !general_needs? ? "location" : nil, + !supported_housing? ? "postcode_full" : nil, # TODO: CLDC-4119: add postcode to duplicate check fields for supported housing + !general_needs? ? "location" : nil, # TODO: CLDC-4119: remove location from duplicate check fields "tenancycode", log.chcharge.present? ? "chcharge" : nil, ].compact @@ -973,11 +973,11 @@ private errors.add(:field_9, error_message) # startdate errors.add(:field_10, error_message) # startdate errors.add(:field_13, error_message) # tenancycode - errors.add(:field_6, error_message) if !general_needs? && :field_6.present? # location + errors.add(:field_6, error_message) if !general_needs? && :field_6.present? # location # TODO: CLDC-4119: remove location from error fields errors.add(:field_5, error_message) if !general_needs? && :field_6.blank? # add to Scheme field as unclear whether log uses New or Old CORE ids - errors.add(:field_23, error_message) unless supported_housing? # postcode_full - errors.add(:field_24, error_message) unless supported_housing? # postcode_full - errors.add(:field_25, error_message) unless supported_housing? # la + errors.add(:field_23, error_message) unless supported_housing? # postcode_full # TODO: CLDC-4119: add postcode to error fields for supported housing + errors.add(:field_24, error_message) unless supported_housing? # postcode_full # TODO: CLDC-4119: add postcode to error fields for supported housing + errors.add(:field_25, error_message) unless supported_housing? # la # TODO: CLDC-4119: add LA to error fields for supported housing errors.add(:field_42, error_message) # age1 errors.add(:field_43, error_message) # sex1 errors.add(:field_46, error_message) # ecstat1 @@ -1335,29 +1335,26 @@ private attributes["first_time_property_let_as_social_housing"] = first_time_property_let_as_social_housing - if general_needs? - attributes["uprn_known"] = field_18.present? ? 1 : 0 - attributes["uprn_confirmed"] = 1 if field_18.present? - attributes["skip_update_uprn_confirmed"] = true - attributes["uprn"] = field_18 - attributes["address_line1"] = field_19 - attributes["address_line1_as_entered"] = field_19 - attributes["address_line2"] = field_20 - attributes["address_line2_as_entered"] = field_20 - attributes["town_or_city"] = field_21 - attributes["town_or_city_as_entered"] = field_21 - attributes["county"] = field_22 - attributes["county_as_entered"] = field_22 - attributes["postcode_full"] = postcode_full - attributes["postcode_full_as_entered"] = postcode_full - attributes["postcode_known"] = postcode_known - attributes["la"] = field_25 - attributes["la_as_entered"] = field_25 - - attributes["address_line1_input"] = address_line1_input - attributes["postcode_full_input"] = postcode_full - attributes["select_best_address_match"] = true if field_18.blank? - end + attributes["uprn_known"] = field_18.present? ? 1 : 0 + attributes["uprn_confirmed"] = 1 if field_18.present? + attributes["skip_update_uprn_confirmed"] = true + attributes["uprn"] = field_18 + attributes["address_line1"] = field_19 + attributes["address_line1_as_entered"] = field_19 + attributes["address_line2"] = field_20 + attributes["address_line2_as_entered"] = field_20 + attributes["town_or_city"] = field_21 + attributes["town_or_city_as_entered"] = field_21 + attributes["county"] = field_22 + attributes["county_as_entered"] = field_22 + attributes["postcode_full"] = postcode_full + attributes["postcode_full_as_entered"] = postcode_full + attributes["postcode_known"] = postcode_known + attributes["la"] = field_25 + attributes["la_as_entered"] = field_25 + attributes["address_line1_input"] = address_line1_input + attributes["postcode_full_input"] = postcode_full + attributes["select_best_address_match"] = true if field_18.blank? attributes end 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 6e37c82b3..2f282596c 100644 --- a/spec/services/bulk_upload/lettings/year2026/row_parser_spec.rb +++ b/spec/services/bulk_upload/lettings/year2026/row_parser_spec.rb @@ -12,7 +12,10 @@ RSpec.describe BulkUpload::Lettings::Year2026::RowParser do let(:owning_org) { create(:organisation, :with_old_visible_id) } let(:managing_org) { create(:organisation, :with_old_visible_id, rent_periods: [4, 1]) } let(:scheme) { create(:scheme, :with_old_visible_id, owning_organisation: owning_org) } - let(:location) { create(:location, :with_old_visible_id, scheme:) } + let(:postcode_first_part) { "AA1".freeze } + let(:postcode_second_part) { "1AA".freeze } + let(:postcode) { "#{postcode_first_part} #{postcode_second_part}" } + let(:location) { create(:location, :with_old_visible_id, scheme:, postcode:) } let(:setup_section_params) do { @@ -88,7 +91,7 @@ RSpec.describe BulkUpload::Lettings::Year2026::RowParser do .to_return(status: 200, body: "{\"status\":200,\"result\":{\"admin_district\":\"Manchester\", \"codes\":{\"admin_district\": \"E08000003\"}}}", headers: {}) stub_request(:get, /api\.os\.uk\/search\/places\/v1\/find/) - .to_return(status: 200, body: { results: [{ DPA: { MATCH: 0.9, BUILDING_NAME: "result address line 1", POST_TOWN: "result town or city", POSTCODE: "AA1 1AA", UPRN: "12345" } }] }.to_json, headers: {}) + .to_return(status: 200, body: { results: [{ DPA: { MATCH: 0.9, BUILDING_NAME: "result address line 1", POST_TOWN: "result town or city", POSTCODE: postcode, UPRN: "12345" } }] }.to_json, headers: {}) stub_request(:get, /api\.os\.uk\/search\/places\/v1\/uprn/) .to_return(status: 200, body: '{"status":200,"results":[{"DPA":{ @@ -101,7 +104,7 @@ RSpec.describe BulkUpload::Lettings::Year2026::RowParser do "DEPENDENT_THOROUGHFARE_NAME": "data", "THOROUGHFARE_NAME": "thing", "POST_TOWN": "London", - "POSTCODE": "SE2 6RT" + "POSTCODE": "' + postcode + '" }}]}', headers: {}) end @@ -1484,183 +1487,247 @@ RSpec.describe BulkUpload::Lettings::Year2026::RowParser do end describe "UPRN and address fields" do - context "with a general needs log" do - context "when a valid UPRN is given" do - context "and address fields are not given" do - let(:attributes) { setup_section_params.merge({ field_4: 1, field_18: "123456789012" }) } - - it "does not add errors" do - parser.valid? - %i[field_18 field_19 field_20 field_21 field_22 field_23 field_24].each do |field| - expect(parser.errors[field]).to be_empty - end - end - end - end - - context "when an invalid UPRN is given" do - context "and address fields are not given" do - let(:attributes) { setup_section_params.merge({ field_4: 1, field_18: "1234567890123" }) } - - it "adds an appropriate error to the UPRN field" do - parser.valid? - expect(parser.errors[:field_18]).to eql(["UPRN must be 12 digits or less."]) - end - - it "adds errors to missing key address fields" do - parser.valid? - expect(parser.errors[:field_19]).to eql([I18n.t("validations.lettings.2026.bulk_upload.not_answered", question: "address line 1.")]) - expect(parser.errors[:field_21]).to eql([I18n.t("validations.lettings.2026.bulk_upload.not_answered", question: "town or city.")]) - expect(parser.errors[:field_23]).to eql([I18n.t("validations.lettings.2026.bulk_upload.not_answered", question: "part 1 of postcode.")]) - expect(parser.errors[:field_24]).to eql([I18n.t("validations.lettings.2026.bulk_upload.not_answered", question: "part 2 of postcode.")]) - end + %i[ + general_needs + supported_housing + ].each do |needs_type| + context "with a #{needs_type.to_s.tr('_', ' ')} log" do + let(:base_attributes) do + setup_section_params.merge({ + field_4: needs_type == :supported_housing ? 2 : 1, + field_5: needs_type == :supported_housing ? "S#{scheme.id}" : nil, + field_6: needs_type == :supported_housing ? location.old_visible_id : nil, + }.compact) end - context "and address fields are given" do - let(:attributes) { setup_section_params.merge({ field_4: 1, field_18: "1234567890123", field_19: "address line 1", field_21: "town or city", field_23: "AA1", field_24: "1AA" }) } + context "when a valid UPRN is given" do + context "and address fields are not given" do + let(:attributes) { base_attributes.merge({ field_18: "123456789012" }) } - it "adds an error to the UPRN field only" do - parser.valid? - expect(parser.errors[:field_18]).to eql(["UPRN must be 12 digits or less."]) - %i[field_19 field_21 field_23 field_24].each do |field| - expect(parser.errors[field]).to be_empty + it "does not add errors" do + parser.valid? + %i[field_18 field_19 field_20 field_21 field_22 field_23 field_24].each do |field| + expect(parser.errors[field]).to be_empty + end end - end - - it "does not do an address search" do - parser.valid? - expect(a_request(:any, /api\.os\.uk\/search\/places\/v1\/find/)).not_to have_been_made - end - end - end - - context "when no UPRN is given" do - context "and no address fields are given" do - let(:attributes) { setup_section_params.merge({ field_4: 1 }) } - - it "adds appropriate errors to UPRN and key address fields" do - parser.valid? - expect(parser.errors[:field_18]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) - expect(parser.errors[:field_19]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) - expect(parser.errors[:field_21]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) - expect(parser.errors[:field_23]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) - expect(parser.errors[:field_24]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) - end - end - context "and some key address field is missing" do - let(:attributes) { setup_section_params.merge({ field_4: 1, field_21: "town or city", field_23: "AA1", field_24: "1AA" }) } - - it "adds errors to UPRN and the missing key address field" do - parser.valid? - expect(parser.errors[:field_18]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) - expect(parser.errors[:field_19]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) - expect(parser.errors[:field_21]).to be_empty - expect(parser.errors[:field_23]).to be_empty - expect(parser.errors[:field_24]).to be_empty + if needs_type == :supported_housing + context "and the postcode associated with the UPRN does not match the postcode associated with the location" do + before do + stub_request(:get, /api\.os\.uk\/search\/places\/v1\/uprn/) + .to_return(status: 200, body: '{"status":200,"results":[{"DPA":{ + "PO_BOX_NUMBER": "fake", + "ORGANISATION_NAME": "org", + "DEPARTMENT_NAME": "name", + "SUB_BUILDING_NAME": "building", + "BUILDING_NAME": "name", + "BUILDING_NUMBER": "number", + "DEPENDENT_THOROUGHFARE_NAME": "data", + "THOROUGHFARE_NAME": "thing", + "POST_TOWN": "London", + "POSTCODE": "BB2 2BB" + }}]}', headers: {}) + end + + it "adds an appropriate error to the UPRN field" do + parser.valid? + expect(parser.errors[:field_18]).to eql([I18n.t("validations.lettings.property.uprn.postcode_does_not_match_scheme_location_postcode")]) + end + end + end end end - context "and all key address fields are present" do - let(:attributes) { setup_section_params.merge({ field_4: 1, field_18: nil, field_19: "address line 1", field_21: "town or city", field_23: "AA1", field_24: "1AA" }) } - - context "and an address can be found with a high enough match rating" do - before do - stub_request(:get, /api\.os\.uk\/search\/places\/v1\/find/) - .to_return(status: 200, body: { results: [{ DPA: { MATCH: 0.7, BUILDING_NAME: "", POST_TOWN: "", POSTCODE: "AA1 1AA", UPRN: "1" } }] }.to_json, headers: {}) - end + context "when an invalid UPRN is given" do + context "and address fields are not given" do + let(:attributes) { base_attributes.merge({ field_18: "1234567890123" }) } - it "does not add errors" do + it "adds an appropriate error to the UPRN field" do parser.valid? - %i[field_18 field_19 field_20 field_21 field_22 field_23 field_24].each do |field| - expect(parser.errors[field]).to be_empty - end + expect(parser.errors[:field_18]).to eql(["UPRN must be 12 digits or less."]) end - it "does not set manual address input" do + it "adds errors to missing key address fields" do parser.valid? - expect(parser.log.manual_address_entry_selected).to be_falsey + expect(parser.errors[:field_19]).to eql([I18n.t("validations.lettings.2026.bulk_upload.not_answered", question: "address line 1.")]) + expect(parser.errors[:field_21]).to eql([I18n.t("validations.lettings.2026.bulk_upload.not_answered", question: "town or city.")]) + expect(parser.errors[:field_23]).to eql([I18n.t("validations.lettings.2026.bulk_upload.not_answered", question: "part 1 of postcode.")]) + expect(parser.errors[:field_24]).to eql([I18n.t("validations.lettings.2026.bulk_upload.not_answered", question: "part 2 of postcode.")]) end end - context "when no address can be found" do - before do - stub_request(:get, /api\.os\.uk\/search\/places\/v1\/find/) - .to_return(status: 200, body: { results: [] }.to_json, headers: {}) - end + context "and address fields are given" do + let(:attributes) { base_attributes.merge({ field_18: "1234567890123", field_19: "address line 1", field_21: "town or city", field_23: postcode_first_part, field_24: postcode_second_part }) } - it "does not add errors" do + it "adds an error to the UPRN field only" do parser.valid? - %i[field_18 field_19 field_20 field_21 field_22 field_23 field_24].each do |field| + expect(parser.errors[:field_18]).to eql(["UPRN must be 12 digits or less."]) + %i[field_19 field_21 field_23 field_24].each do |field| expect(parser.errors[field]).to be_empty end end - it "sets manual address input" do + it "does not do an address search" do parser.valid? - expect(parser.log.manual_address_entry_selected).to be_truthy - expect(parser.log.address_line1).to eq("address line 1") - expect(parser.log.town_or_city).to eq("town or city") - expect(parser.log.postcode_full).to eq("AA1 1AA") + expect(a_request(:any, /api\.os\.uk\/search\/places\/v1\/find/)).not_to have_been_made end end + end - context "when a single address with not a high enough match rating is returned" do - before do - stub_request(:get, /api\.os\.uk\/search\/places\/v1\/find/) - .to_return(status: 200, body: { results: [{ DPA: { MATCH: 0.6, BUILDING_NAME: "", POST_TOWN: "", POSTCODE: "AA1 1AA", UPRN: "1" } }] }.to_json, headers: {}) - end + context "when no UPRN is given" do + context "and no address fields are given" do + let(:attributes) { base_attributes.merge({ field_4: 1 }) } - it "does not add errors" do + it "adds appropriate errors to UPRN and key address fields" do parser.valid? - %i[field_18 field_19 field_20 field_21 field_22 field_23 field_24].each do |field| - expect(parser.errors[field]).to be_empty - end + expect(parser.errors[:field_18]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) + expect(parser.errors[:field_19]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) + expect(parser.errors[:field_21]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) + expect(parser.errors[:field_23]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) + expect(parser.errors[:field_24]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) end + end + + context "and some key address field is missing" do + let(:attributes) { base_attributes.merge({ field_21: "town or city", field_23: postcode_first_part, field_24: postcode_second_part }) } - it "sets manual address input" do + it "adds errors to UPRN and the missing key address field" do parser.valid? - expect(parser.log.manual_address_entry_selected).to be_truthy - expect(parser.log.address_line1).to eq("address line 1") - expect(parser.log.town_or_city).to eq("town or city") - expect(parser.log.postcode_full).to eq("AA1 1AA") + expect(parser.errors[:field_18]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) + expect(parser.errors[:field_19]).to eql([I18n.t("validations.lettings.2026.bulk_upload.address.not_answered")]) + expect(parser.errors[:field_21]).to be_empty + expect(parser.errors[:field_23]).to be_empty + expect(parser.errors[:field_24]).to be_empty end end - context "when no addresses have a high enough match rating" do - before do - stub_request(:get, /api\.os\.uk\/search\/places\/v1\/find/) - .to_return(status: 200, body: { results: [{ DPA: { MATCH: 0.6, BUILDING_NAME: "", POST_TOWN: "", POSTCODE: "AA1 1AA", UPRN: "1" } }, { DPA: { MATCH: 0.8, BUILDING_NAME: "", POST_TOWN: "", POSTCODE: "BB2 2BB", UPRN: "2" } }] }.to_json, headers: {}) + context "and all key address fields are present" do + let(:attributes) { base_attributes.merge({ field_18: nil, field_19: "address line 1", field_21: "town or city", field_23: postcode_first_part, field_24: postcode_second_part }) } + + context "and an address can be found with a high enough match rating" do + before do + stub_request(:get, /api\.os\.uk\/search\/places\/v1\/find/) + .to_return(status: 200, body: { results: [{ DPA: { MATCH: 0.7, BUILDING_NAME: "", POST_TOWN: "", POSTCODE: postcode, UPRN: "1" } }] }.to_json, headers: {}) + end + + it "does not add errors" do + parser.valid? + %i[field_18 field_19 field_20 field_21 field_22 field_23 field_24].each do |field| + expect(parser.errors[field]).to be_empty + end + end + + it "does not set manual address input" do + parser.valid? + expect(parser.log.manual_address_entry_selected).to be_falsey + end end - it "does not add errors" do - parser.valid? - %i[field_18 field_19 field_20 field_21 field_22 field_23 field_24].each do |field| - expect(parser.errors[field]).to be_empty + context "when no address can be found" do + before do + stub_request(:get, /api\.os\.uk\/search\/places\/v1\/find/) + .to_return(status: 200, body: { results: [] }.to_json, headers: {}) + end + + it "does not add errors" do + parser.valid? + %i[field_18 field_19 field_20 field_21 field_22 field_23 field_24].each do |field| + expect(parser.errors[field]).to be_empty + end + end + + it "sets manual address input" do + parser.valid? + expect(parser.log.manual_address_entry_selected).to be_truthy + expect(parser.log.address_line1).to eq("address line 1") + expect(parser.log.town_or_city).to eq("town or city") + expect(parser.log.postcode_full).to eq(postcode) + end + + if needs_type == :supported_housing + context "and the postcode entered manually does not match the postcode associated with the location" do + let(:attributes) { base_attributes.merge({ field_18: nil, field_19: "address line 1", field_21: "town or city", field_23: "BB2", field_24: "2BB" }) } + + it "adds appropriate errors to postcode and LA fields" do + parser.valid? + expect(parser.errors[:field_23]).to eql([I18n.t("validations.lettings.property.postcode_full.does_not_match_scheme_location_postcode")]) + expect(parser.errors[:field_24]).to eql([I18n.t("validations.lettings.property.postcode_full.does_not_match_scheme_location_postcode")]) + expect(parser.errors[:field_25]).to eql([I18n.t("validations.lettings.property.postcode_full.does_not_match_scheme_location_postcode")]) + end + end end end - it "sets manual address input" do - parser.valid? - expect(parser.log.manual_address_entry_selected).to be_truthy - expect(parser.log.manual_address_entry_selected).to be_truthy - expect(parser.log.address_line1).to eq("address line 1") - expect(parser.log.town_or_city).to eq("town or city") - expect(parser.log.postcode_full).to eq("AA1 1AA") + context "when a single address with not a high enough match rating is returned" do + before do + stub_request(:get, /api\.os\.uk\/search\/places\/v1\/find/) + .to_return(status: 200, body: { results: [{ DPA: { MATCH: 0.6, BUILDING_NAME: "", POST_TOWN: "", POSTCODE: postcode, UPRN: "1" } }] }.to_json, headers: {}) + end + + it "does not add errors" do + parser.valid? + %i[field_18 field_19 field_20 field_21 field_22 field_23 field_24].each do |field| + expect(parser.errors[field]).to be_empty + end + end + + it "sets manual address input" do + parser.valid? + expect(parser.log.manual_address_entry_selected).to be_truthy + expect(parser.log.address_line1).to eq("address line 1") + expect(parser.log.town_or_city).to eq("town or city") + expect(parser.log.postcode_full).to eq(postcode) + end + + if needs_type == :supported_housing + context "and the postcode entered manually does not match the postcode associated with the location" do + let(:attributes) { base_attributes.merge({ field_18: nil, field_19: "address line 1", field_21: "town or city", field_23: "BB2", field_24: "2BB" }) } + + it "adds appropriate errors to postcode and LA fields" do + parser.valid? + expect(parser.errors[:field_23]).to eql([I18n.t("validations.lettings.property.postcode_full.does_not_match_scheme_location_postcode")]) + expect(parser.errors[:field_24]).to eql([I18n.t("validations.lettings.property.postcode_full.does_not_match_scheme_location_postcode")]) + expect(parser.errors[:field_25]).to eql([I18n.t("validations.lettings.property.postcode_full.does_not_match_scheme_location_postcode")]) + end + end + end end - end - end - end - end - context "with a supported housing log" do - context "when neither UPRN nor address fields are provided" do - let(:attributes) { setup_section_params.merge({ field_4: 2, field_5: "S#{scheme.id}", field_6: location.old_visible_id, field_18: nil, field_19: nil, field_21: nil, field_23: nil, field_24: nil }) } + context "when no addresses have a high enough match rating" do + before do + stub_request(:get, /api\.os\.uk\/search\/places\/v1\/find/) + .to_return(status: 200, body: { results: [{ DPA: { MATCH: 0.6, BUILDING_NAME: "", POST_TOWN: "", POSTCODE: postcode, UPRN: "1" } }, { DPA: { MATCH: 0.8, BUILDING_NAME: "", POST_TOWN: "", POSTCODE: "BB2 2BB", UPRN: "2" } }] }.to_json, headers: {}) + end + + it "does not add errors" do + parser.valid? + %i[field_18 field_19 field_20 field_21 field_22 field_23 field_24].each do |field| + expect(parser.errors[field]).to be_empty + end + end - it "does not add missing field errors" do - parser.valid? - %i[field_18 field_19 field_20 field_21 field_22 field_23 field_24].each do |field| - expect(parser.errors[field]).to be_empty + it "sets manual address input" do + parser.valid? + expect(parser.log.manual_address_entry_selected).to be_truthy + expect(parser.log.manual_address_entry_selected).to be_truthy + expect(parser.log.address_line1).to eq("address line 1") + expect(parser.log.town_or_city).to eq("town or city") + expect(parser.log.postcode_full).to eq(postcode) + end + + if needs_type == :supported_housing + context "and the postcode entered manually does not match the postcode associated with the location" do + let(:attributes) { base_attributes.merge({ field_18: nil, field_19: "address line 1", field_21: "town or city", field_23: "BB2", field_24: "2BB" }) } + + it "adds appropriate errors to postcode and LA fields" do + parser.valid? + expect(parser.errors[:field_23]).to eql([I18n.t("validations.lettings.property.postcode_full.does_not_match_scheme_location_postcode")]) + expect(parser.errors[:field_24]).to eql([I18n.t("validations.lettings.property.postcode_full.does_not_match_scheme_location_postcode")]) + expect(parser.errors[:field_25]).to eql([I18n.t("validations.lettings.property.postcode_full.does_not_match_scheme_location_postcode")]) + end + end + end + end end end end @@ -1869,87 +1936,79 @@ RSpec.describe BulkUpload::Lettings::Year2026::RowParser do end end - describe "#uprn" do - let(:attributes) { { bulk_upload:, field_4: 1, field_18: "12" } } + describe "address-related fields" do + %i[ + general_needs + supported_housing + ].each do |needs_type| + context "with a #{needs_type.to_s.tr('_', ' ')} log" do + let(:base_attributes) do + { + bulk_upload:, + field_4: needs_type == :supported_housing ? 2 : 1, + field_5: needs_type == :supported_housing ? "S#{scheme.id}" : nil, + field_6: needs_type == :supported_housing ? location.old_visible_id : nil, + }.compact + end + + describe "#uprn" do + let(:attributes) { base_attributes.merge({ field_18: "12" }) } - it "sets to given value" do - expect(parser.log.uprn).to eql("12") - end - end + it "sets to given value" do + expect(parser.log.uprn).to eql("12") + end + end - describe "#uprn_known" do - context "when uprn specified" do - let(:attributes) { { bulk_upload:, field_4: 1, field_18: "12" } } + describe "#uprn_known" do + context "when uprn specified" do + let(:attributes) { base_attributes.merge({ field_18: "12" }) } - it "sets to 1" do - expect(parser.log.uprn_known).to be(1) - expect(parser.log.uprn_confirmed).to be(1) - end - end + it "sets to 1" do + expect(parser.log.uprn_known).to be(1) + expect(parser.log.uprn_confirmed).to be(1) + end + end - context "when uprn blank" do - let(:attributes) { { bulk_upload:, field_4: 1, field_18: "" } } + context "when uprn blank" do + let(:attributes) { base_attributes.merge({ field_18: "" }) } - it "sets to 0" do - expect(parser.log.uprn_known).to be(0) - end - end - end + it "sets to 0" do + expect(parser.log.uprn_known).to be(0) + end + end + end - describe "#address_line1" do - let(:attributes) { { bulk_upload:, field_4: 1, field_19: "123 Sesame Street" } } + describe "#address_line1" do + let(:attributes) { base_attributes.merge({ field_19: "123 Sesame Street" }) } - it "sets to given value" do - expect(parser.log.address_line1).to eql("123 Sesame Street") - end - end + it "sets to given value" do + expect(parser.log.address_line1).to eql("123 Sesame Street") + end + end - describe "#address_line2" do - let(:attributes) { { bulk_upload:, field_4: 1, field_20: "Cookie Town" } } + describe "#address_line2" do + let(:attributes) { base_attributes.merge({ field_20: "Cookie Town" }) } - it "sets to given value" do - expect(parser.log.address_line2).to eql("Cookie Town") - end - end + it "sets to given value" do + expect(parser.log.address_line2).to eql("Cookie Town") + end + end - describe "#town_or_city" do - let(:attributes) { { bulk_upload:, field_4: 1, field_21: "London" } } + describe "#town_or_city" do + let(:attributes) { base_attributes.merge({ field_21: "London" }) } - it "sets to given value" do - expect(parser.log.town_or_city).to eql("London") - end - end + it "sets to given value" do + expect(parser.log.town_or_city).to eql("London") + end + end - describe "#county" do - let(:attributes) { { bulk_upload:, field_4: 1, field_22: "Greater London" } } + describe "#county" do + let(:attributes) { base_attributes.merge({ field_22: "Greater London" }) } - it "sets to given value" do - expect(parser.log.county).to eql("Greater London") - end - end - - describe "address related fields for supported housing logs" do - context "when address data is provided for a supported housing log" do - let(:attributes) { { bulk_upload:, field_4: 2, field_18: nil, field_19: "Flat 1", field_20: "Example Place", field_21: "London", field_22: "Greater London", field_23: "SW1A", field_24: "1AA" } } - - it "is not set on the log" do - expect(parser.log.uprn).to be_nil - expect(parser.log.uprn_known).to be_nil - expect(parser.log.address_line1).to be_nil - expect(parser.log.address_line1_as_entered).to be_nil - expect(parser.log.address_line2).to be_nil - expect(parser.log.address_line2_as_entered).to be_nil - expect(parser.log.town_or_city).to be_nil - expect(parser.log.town_or_city_as_entered).to be_nil - expect(parser.log.county).to be_nil - expect(parser.log.county_as_entered).to be_nil - expect(parser.log.postcode_full).to be_nil - expect(parser.log.postcode_full_as_entered).to be_nil - expect(parser.log.la).to be_nil - expect(parser.log.la_as_entered).to be_nil - expect(parser.log.address_line1_input).to be_nil - expect(parser.log.postcode_full_input).to be_nil - expect(parser.log.select_best_address_match).to be_nil + it "sets to given value" do + expect(parser.log.county).to eql("Greater London") + end + end end end end