CLDC-4159: Address / UPRN for supported housing - implementation (#3145)
* Ask address and UPRN questions for 2026 and later logs
* Fix page tests
* Fix LA and postcode overrides
* Fix resetting address fields and LA
* Add tests for resetting address fields and LA
* Fix lettings log derived fields tests
* Fix lint
* Fix tests
* Clean up lettings log property overrides
* Add comments
* Fix lint
* Add error to location field
* Add error to location field
* Add tests for error on location field
* Refactor property and location postcode matching validation into own function
* Add test for LA override
* Add test for postcode override
* Added `!record.read_attribute(:la)` guard
* Fix lint
* Fix property validation for checking LA is active/in England
* Fix test
* Minor tweaks
* Fix lint
# TODO: CLDC-4119: Beware! This method may cause issues when testing supported housing log duplicate detection after postcode is added, as it can return `location.postcode` instead of the actual `postcode_full` stored on the log record (`super`). If this happens, investigate why it isn't returning `super`, as it should when `form.start_year_2026_or_later? && super`.
invalid:"Enter a postcode in the correct format, for example AA1 1AA."
not_in_england:"It looks like you have an entered a postcode outside of England. Only create logs for lettings in England."
la_not_valid_for_date:"%{la} does not exist on the tenancy start date, due to a change in local authority names and boundaries. Please enter the local authority name in use on the tenancy start date"
does_not_match_scheme_location_postcode:"The postcode in the address does not match the postcode for the location in the scheme. Please review your answers to the address or UPRN question (whichever you answered) and the location question."
rsnvac:
non_temp_accommodation:"Answer cannot be re-let to tenant who occupied the same property as temporary accommodation as this accommodation is not temporary."
referral_invalid:"Answer cannot be re-let to tenant who occupied the same property as temporary accommodation as a different source of referral for this letting."
@ -24,6 +25,7 @@ en:
invalid:"UPRN must be 12 digits or less."
not_in_england:"It looks like you have entered an address outside of England. Only create logs for lettings in England."
la_not_valid_for_date:"%{la} does not exist on the tenancy start date, due to a change in local authority names and boundaries. Please enter the local authority name in use on the tenancy start date"
postcode_does_not_match_scheme_location_postcode:"The postcode in the address does not match the postcode for the location in the scheme. Please review your answers to the address or UPRN question (whichever you answered) and the location question."
uprn_confirmation:# legacy question
not_in_england:"It looks like you have entered an address outside of England. Only create logs for lettings in England."
uprn_selection:
@ -38,6 +40,7 @@ en:
location_id:
not_in_england:"It looks like you have selected a location outside of England. Only create logs for lettings in England."
la_not_valid_for_date:"%{la} does not exist on the tenancy start date, due to a change in local authority names and boundaries. Please enter the local authority name in use on the tenancy start date"
postcode_does_not_match_scheme_location_postcode:"The postcode in the address does not match the postcode for the location in the scheme. Please review your answers to the address or UPRN question (whichever you answered) and the location question."
startdate:
postcode_not_in_england:"It looks like you have an entered a postcode outside of England. Only create logs for lettings in England."
address_not_in_england:"It looks like you have entered an address outside of England. Only create logs for lettings in England."
# log.read_attribute is used in these tests to read the underlying attribute (which is what
# is being reset) rather than the getter method, which may override the underlying attribute.
let(:uprn){"123456789"}
let(:uprn_known){1}# A value of 1 is necessary for this test as there is separate logic that resets `uprn` if `uprn_known` is 0.
let(:uprn_confirmed){1}# A value of 1 is necessary for this test as there is separate logic that resets the address fields and LA if `uprn_confirmed` is 0 (and `uprn_known` is 1).
let(:address_line1){"1 Test Street"}
let(:address_line2){"Testville"}
let(:town_or_city){"Testford"}
let(:county){"Testshire"}
let(:postcode_full){"SW1 1AA"}
let(:la){"Test LA"}
let(:manual_address_entry_selected){false}# A value of `false` is necessary for this test as there is separate logic that resets some of the UPRN fields if `manual_address_entry_selected` is `false`.
.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:{})
@ -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
@ -293,7 +296,7 @@ RSpec.describe BulkUpload::Lettings::Year2026::RowParser do
:field_13,# tenancycode
:field_23,# postcode_full
:field_24,# postcode_full
:field_25,# postcode_full
:field_25,# LA
:field_42,# age1
:field_43,# sex1
:field_46,# ecstat1
@ -324,7 +327,7 @@ RSpec.describe BulkUpload::Lettings::Year2026::RowParser do
end
end
context"when a supported housing log already exists in the db"do
context"when a supported housing log already exists in the db"do# TODO: CLDC-4119: Beware! The `postcode_full` method in the `LettingsLog` class may cause issues with these supported housing log duplicate detection tests after postcode is added. See comment on the `postcode_full` method for details.
expect(parser.errors[:field_19]).toeql([I18n.t("validations.lettings.2026.bulk_upload.not_answered",question:"address line 1.")])
expect(parser.errors[:field_21]).toeql([I18n.t("validations.lettings.2026.bulk_upload.not_answered",question:"town or city.")])
expect(parser.errors[:field_23]).toeql([I18n.t("validations.lettings.2026.bulk_upload.not_answered",question:"part 1 of postcode.")])
expect(parser.errors[:field_24]).toeql([I18n.t("validations.lettings.2026.bulk_upload.not_answered",question:"part 2 of postcode.")])
end
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"})}
it"adds an error to the UPRN field only"do
parser.valid?
expect(parser.errors[:field_18]).toeql(["UPRN must be 12 digits or less."])
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})}
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