From 7a7abc842c9a1581d0d63063a0f63f87e0b24ba3 Mon Sep 17 00:00:00 2001 From: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com> Date: Fri, 17 Jan 2025 08:37:35 +0000 Subject: [PATCH] CLDC-3826 Add LA changes for 2025 (#2888) * Add LA changes for 2025 * Add missing soft validation copy * Add local authority links and update seed * Only display name once in the locations if only Ecode has changed * lint --- app/helpers/locations_helper.rb | 2 +- app/models/log.rb | 36 +++--- .../2025_local_authorities.csv | 5 + .../local_authority_links_2025.csv | 5 + .../2025/lettings/soft_validations.en.yml | 8 ++ db/seeds.rb | 16 ++- spec/helpers/locations_helper_spec.rb | 23 ++++ spec/models/sales_log_spec.rb | 120 +++++++++++++++++- 8 files changed, 187 insertions(+), 28 deletions(-) create mode 100644 config/local_authorities_data/2025_local_authorities.csv create mode 100644 config/local_authorities_data/local_authority_links_2025.csv diff --git a/app/helpers/locations_helper.rb b/app/helpers/locations_helper.rb index fc1008926..60b668cea 100644 --- a/app/helpers/locations_helper.rb +++ b/app/helpers/locations_helper.rb @@ -150,7 +150,7 @@ private def formatted_local_authority_timeline(location) sorted_linked_authorities = location.linked_local_authorities.sort_by(&:start_date) - return sorted_linked_authorities.first["name"] if sorted_linked_authorities.count == 1 + return sorted_linked_authorities.first["name"] if sorted_linked_authorities.count == 1 || sorted_linked_authorities.map(&:name).uniq.count == 1 sorted_linked_authorities.map { |linked_local_authority| formatted_start_date = linked_local_authority.start_date.year == 2021 ? "until" : "#{linked_local_authority.start_date&.to_formatted_s(:govuk_date)} -" diff --git a/app/models/log.rb b/app/models/log.rb index 94f0ff58d..66e996892 100644 --- a/app/models/log.rb +++ b/app/models/log.rb @@ -343,31 +343,27 @@ private PIO = PostcodeService.new LA_CHANGES = { - "E07000027" => "E06000064", # Barrow-in-Furness => Westmorland and Furness - "E07000030" => "E06000064", # Eden => Westmorland and Furness - "E07000031" => "E06000064", # South Lakeland => Westmorland and Furness - "E07000026" => "E06000063", # Allerdale => Cumberland - "E07000028" => "E06000063", # Carlisle => Cumberland - "E07000029" => "E06000063", # Copeland => Cumberland - "E07000163" => "E06000065", # Craven => North Yorkshire - "E07000164" => "E06000065", # Hambleton => North Yorkshire - "E07000165" => "E06000065", # Harrogate => North Yorkshire - "E07000166" => "E06000065", # Richmondshire => North Yorkshire - "E07000167" => "E06000065", # Ryedale => North Yorkshire - "E07000168" => "E06000065", # Scarborough => North Yorkshire - "E07000169" => "E06000065", # Selby => North Yorkshire - "E07000187" => "E06000066", # Mendip => Somerset - "E07000188" => "E06000066", # Sedgemoor => Somerset - "E07000246" => "E06000066", # Somerset West and Taunton => Somerset - "E07000189" => "E06000066", # South Somerset => Somerset + 2025 => { + "E08000016" => "E08000038", # Barnsley + "E08000019" => "E08000039", # Sheffield + }, + }.freeze + + BACKWARDS_LA_CHANGES = { + 2024 => { + "E08000038" => "E08000016", # Barnsley + "E08000039" => "E08000019", # Sheffield + }, }.freeze def get_inferred_la(postcode) result = PIO.lookup(postcode) location_code = result[:location_code] if result - if LA_CHANGES.key?(location_code) && form.start_date.year >= 2023 - LA_CHANGES[location_code] - elsif !(LA_CHANGES.value?(location_code) && form.start_date.year < 2023) + if LA_CHANGES[form.start_date.year]&.key?(location_code) + LA_CHANGES[form.start_date.year][location_code] + elsif BACKWARDS_LA_CHANGES[form.start_date.year]&.key?(location_code) + BACKWARDS_LA_CHANGES[form.start_date.year][location_code] + elsif !LA_CHANGES.value?(location_code) location_code end end diff --git a/config/local_authorities_data/2025_local_authorities.csv b/config/local_authorities_data/2025_local_authorities.csv new file mode 100644 index 000000000..ac5f2e319 --- /dev/null +++ b/config/local_authorities_data/2025_local_authorities.csv @@ -0,0 +1,5 @@ +code,name,start_year,end_year +E08000016,Barnsley,2021,2025 +E08000019,Sheffield,2021,2025 +E08000038,Barnsley,2025, +E08000039,Sheffield,2025, diff --git a/config/local_authorities_data/local_authority_links_2025.csv b/config/local_authorities_data/local_authority_links_2025.csv new file mode 100644 index 000000000..be2eb290a --- /dev/null +++ b/config/local_authorities_data/local_authority_links_2025.csv @@ -0,0 +1,5 @@ +local_authority_code,linked_local_authority_code +E08000038,E08000016 +E08000039,E08000019 +E08000016,E08000038 +E08000019,E08000039 \ No newline at end of file diff --git a/config/locales/forms/2025/lettings/soft_validations.en.yml b/config/locales/forms/2025/lettings/soft_validations.en.yml index 03a3cbb3d..42292bd9e 100644 --- a/config/locales/forms/2025/lettings/soft_validations.en.yml +++ b/config/locales/forms/2025/lettings/soft_validations.en.yml @@ -130,3 +130,11 @@ en: question_text: "Are you sure the property has been vacant for this long?" title_text: "You told us the property has been vacant for 2 years." informative_text: "This is longer than we would expect." + + no_address_found: + page_header: "" + check_answer_label: "No address found" + hint_text: "" + question_text: "We could not find an address that matches your search. You can search again or continue to enter the address manually." + title_text: "No address found" + informative_text: "We could not find an address that matches your search. You can search again or continue to enter the address manually." diff --git a/db/seeds.rb b/db/seeds.rb index f3dcb688d..d3e7beb3f 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -13,9 +13,11 @@ def find_or_create_user(organisation, email, name, role) end if LocalAuthority.count.zero? - la_path = "config/local_authorities_data/initial_local_authorities.csv" - service = Imports::LocalAuthoritiesService.new(path: la_path) - service.call + paths = ["config/local_authorities_data/initial_local_authorities.csv", "config/local_authorities_data/2025_local_authorities.csv"] + paths.each do |path| + service = Imports::LocalAuthoritiesService.new(path:) + service.call + end end unless Rails.env.test? @@ -175,7 +177,9 @@ unless Rails.env.test? end if LocalAuthority.count.zero? - path = "config/local_authorities_data/initial_local_authorities.csv" - service = Imports::LocalAuthoritiesService.new(path:) - service.call + paths = ["config/local_authorities_data/initial_local_authorities.csv", "config/local_authorities_data/2025_local_authorities.csv"] + paths.each do |path| + service = Imports::LocalAuthoritiesService.new(path:) + service.call + end end diff --git a/spec/helpers/locations_helper_spec.rb b/spec/helpers/locations_helper_spec.rb index 5b3a77e61..0a8eed96f 100644 --- a/spec/helpers/locations_helper_spec.rb +++ b/spec/helpers/locations_helper_spec.rb @@ -368,4 +368,27 @@ RSpec.describe LocationsHelper do end end end + + describe "formatted_local_authority_timeline" do + before do + LocalAuthorityLink.create!(local_authority_id: LocalAuthority.find_by(code: "E07000030").id, linked_local_authority_id: LocalAuthority.find_by(code: "E06000063").id) + LocalAuthorityLink.create!(local_authority_id: LocalAuthority.find_by(code: "E08000016").id, linked_local_authority_id: LocalAuthority.find_by(code: "E08000038").id) + end + + context "when the location LA's have changed" do + let(:location) { FactoryBot.create(:location, location_code: "E07000030") } + + it "displays a timeline of LAs" do + expect(formatted_local_authority_timeline(location)).to eq("Eden (until 31 March 2023)\nCumberland (1 April 2023 - present)") + end + end + + context "when the LA name hasn't changed but Ecode has changed" do + let(:location) { FactoryBot.create(:location, location_code: "E08000016") } + + it "only displays the location name once" do + expect(formatted_local_authority_timeline(location)).to eq("Barnsley") + end + end + end end diff --git a/spec/models/sales_log_spec.rb b/spec/models/sales_log_spec.rb index 3e6d6405d..70ac5455f 100644 --- a/spec/models/sales_log_spec.rb +++ b/spec/models/sales_log_spec.rb @@ -571,7 +571,7 @@ RSpec.describe SalesLog, type: :model do before do WebMock.stub_request(:get, /api\.postcodes\.io\/postcodes\/CA101AA/) - .to_return(status: 200, body: '{"status":200,"result":{"admin_district":"Eden","codes":{"admin_district":"E07000030"}}}', headers: {}) + .to_return(status: 200, body: '{"status":200,"result":{"admin_district":"Eden","codes":{"admin_district":"E06000064"}}}', headers: {}) end it "sets previous postcode for discounted sale" do @@ -610,6 +610,124 @@ RSpec.describe SalesLog, type: :model do end end + context "when saving address with LAs that have changed E-codes (LA inferred from postcode)" do + context "when LA is inferred from postcode" do + let(:address_sales_log_24_25) do + create(:sales_log, :shared_ownership_setup_complete, uprn_known: 0, uprn: nil, postcode_full: "CA10 1AA", saledate: Time.zone.local(2024, 5, 2)) + end + + let(:address_sales_log_25_26) do + create(:sales_log, :shared_ownership_setup_complete, postcode_full: "CA10 1AA", saledate: Time.zone.local(2025, 5, 2)) + end + + before do + Timecop.freeze(Time.zone.local(2025, 5, 10)) + Singleton.__init__(FormHandler) + end + + after do + Timecop.return + end + + context "when old(2024) E-code gets returned" do + before do + WebMock.stub_request(:get, /api\.postcodes\.io\/postcodes\/CA101AA/) + .to_return(status: 200, body: '{"status":200,"result":{"admin_district":"Barnsley","codes":{"admin_district":"E08000016"}}}', headers: {}) + end + + context "with 2024 log" do + it "keeps 2024 E-code" do + expect(address_sales_log_24_25.la).to eq("E08000016") + end + end + + context "with 2025 log" do + it "uses new 2025 E-code if" do + expect(address_sales_log_25_26.la).to eq("E08000038") + end + end + end + + context "when new(2025) E-code gets returned" do + before do + WebMock.stub_request(:get, /api\.postcodes\.io\/postcodes\/CA101AA/) + .to_return(status: 200, body: '{"status":200,"result":{"admin_district":"Barnsley","codes":{"admin_district":"E08000038"}}}', headers: {}) + end + + context "with 2024 log" do + it "uses 2024 E-code" do + expect(address_sales_log_24_25.la).to eq("E08000016") + end + end + + context "with 2025 log" do + it "keeps 2025 E-code if new(2025) E-code gets returned" do + expect(address_sales_log_25_26.la).to eq("E08000038") + end + end + end + end + end + + context "when saving address with LAs that have changed E-codes" do + context "when address inferred from uprn - we still get LA from postcode" do + let(:address_sales_log_24_25) do + create(:sales_log, :shared_ownership_setup_complete, uprn_known: 1, uprn: 1, saledate: Time.zone.local(2024, 5, 2)) + end + + let(:address_sales_log_25_26) do + create(:sales_log, :shared_ownership_setup_complete, uprn_known: 1, uprn: 1, saledate: Time.zone.local(2025, 5, 2)) + end + + before do + Timecop.freeze(Time.zone.local(2025, 5, 10)) + Singleton.__init__(FormHandler) + end + + after do + Timecop.return + end + + context "when old(2024) E-code gets returned" do + before do + WebMock.stub_request(:get, /api\.postcodes\.io\/postcodes\/AA11AA/) + .to_return(status: 200, body: '{"status":200,"result":{"admin_district":"Barnsley","codes":{"admin_district":"E08000016"}}}', headers: {}) + end + + context "with 2024 log" do + it "keeps 2024 E-code" do + expect(address_sales_log_24_25.la).to eq("E08000016") + end + end + + context "with 2025 log" do + it "uses new 2025 E-code if" do + expect(address_sales_log_25_26.la).to eq("E08000038") + end + end + end + + context "when new(2025) E-code gets returned" do + before do + WebMock.stub_request(:get, /api\.postcodes\.io\/postcodes\/AA11AA/) + .to_return(status: 200, body: '{"status":200,"result":{"admin_district":"Barnsley","codes":{"admin_district":"E08000038"}}}', headers: {}) + end + + context "with 2024 log" do + it "uses 2024 E-code" do # currently returns nil + expect(address_sales_log_24_25.la).to eq("E08000016") + end + end + + context "with 2025 log" do + it "keeps 2025 E-code if new(2025) E-code gets returned" do + expect(address_sales_log_25_26.la).to eq("E08000038") + end + end + end + end + end + it "errors if the property postcode is emptied" do expect { address_sales_log.update!({ postcode_full: "" }) } .to raise_error(ActiveRecord::RecordInvalid, /#{I18n.t("validations.postcode")}/)