From fedbc6acada4bd3f7c8d49be81917efbf0eb5c86 Mon Sep 17 00:00:00 2001 From: natdeanlewissoftwire <94526761+natdeanlewissoftwire@users.noreply.github.com> Date: Wed, 13 Mar 2024 14:23:33 +0000 Subject: [PATCH] CLDC-2069 Find UPRNs by address (#2278) * feat: mvp commit with address selector from address line 1 and postcode using OS places find endpoint * feat: build out alternative routes through the address lookup flow * refactor: lint * refactor: remove commented lines * feat: make nil safe * feat: test address client * feat: store address input separately * feat: add migration * feat: display inputs in answer label * feat: update data presenter and test * feat: revert precicions schema update * feat: revert precision schema update * feat: migrate new fields to sales logs * feat: update shared log examples tests * feat: use -1 for not listed address for extensibility * feat: add service error to address_selection * feat: handle case when no addresses are found * feat: allow re-entering different uprns * feat: improve error handling and don't accept "no match" precisions * feat: add page tests * feat: confirm uprn on address update * feat: add question tests * feat: don't set minimum match for initial search * feat: mvp commit with address selector from address line 1 and postcode using OS places find endpoint * feat: build out alternative routes through the address lookup flow * refactor: lint * refactor: remove commented lines * feat: make nil safe * feat: test address client * feat: store address input separately * feat: add migration * feat: display inputs in answer label * feat: update data presenter and test * feat: revert precision schema update * feat: migrate new fields to sales logs * feat: update shared log examples tests * feat: use -1 for not listed address for extensibility * feat: add service error to address_selection * feat: handle case when no addresses are found * feat: allow re-entering different uprns * feat: improve error handling and don't accept "no match" precisions * feat: add page tests * feat: confirm uprn on address update * feat: add question tests * feat: don't set minimum match for initial search * feat: add no address found page * feat: allow uprn known to be skipped, and set 0.4 min precision * feat: accept best "good" match in bulk upload * feat: update validations and test * refactor: avoid stubbing using any_instance_of * refactor: use change_table in migrations * feat: add lettings behaviour to sales logs * feat: update sales tests * feat: xit test that is xited in lettings * feat: stub os api in sales row parser * feat: stub os api in sales row parser * feat: add address line 1 to required attributes * feat: update matching details and fix row parser validation * refactor: improve readability * feat: set uprns as option IDs to avoid multiple lookups * feat: add sales uprn_selection * feat: update schema * feat: update tests * feat: remove redundant methods * feat: update error message and fix tests * feat: update tests * feat: update tests and error behaviour * feat: update tests --- .../form/lettings/pages/address_fallback.rb | 25 +++++ .../form/lettings/pages/address_matcher.rb | 19 ++++ .../form/lettings/pages/no_address_found.rb | 26 +++++ app/models/form/lettings/pages/uprn.rb | 12 ++- .../form/lettings/pages/uprn_selection.rb | 28 +++++ .../address_line1_for_address_matcher.rb | 20 ++++ .../lettings/questions/no_address_found.rb | 9 ++ .../questions/postcode_for_address_matcher.rb | 13 +++ .../lettings/questions/uprn_confirmation.rb | 18 +++- .../form/lettings/questions/uprn_selection.rb | 34 ++++++ .../subsections/property_information.rb | 11 +- .../form/sales/pages/address_fallback.rb | 25 +++++ .../form/sales/pages/address_matcher.rb | 19 ++++ .../form/sales/pages/no_address_found.rb | 26 +++++ app/models/form/sales/pages/uprn.rb | 12 ++- app/models/form/sales/pages/uprn_selection.rb | 28 +++++ .../address_line1_for_address_matcher.rb | 20 ++++ .../form/sales/questions/no_address_found.rb | 9 ++ .../questions/postcode_for_address_matcher.rb | 13 +++ .../form/sales/questions/uprn_confirmation.rb | 18 +++- .../form/sales/questions/uprn_selection.rb | 34 ++++++ .../sales/subsections/property_information.rb | 36 +++++-- app/models/lettings_log.rb | 19 +++- app/models/log.rb | 67 +++++++++++- app/models/sales_log.rb | 19 +++- app/services/address_client.rb | 52 +++++++++ app/services/address_data_presenter.rb | 21 ++++ .../lettings/year2024/row_parser.rb | 17 +++ .../bulk_upload/sales/year2024/row_parser.rb | 17 +++ app/services/csv/lettings_log_csv_service.rb | 2 +- config/locales/en.yml | 5 +- ...dd_address_input_fields_to_lettings_log.rb | 8 ++ ...add_address_lookup_fields_to_sales_logs.rb | 8 ++ ...no_address_found_check_to_lettings_logs.rb | 5 + ...ddress_search_value_check_to_sales_logs.rb | 5 + ...4307_add_uprn_selection_to_lettings_log.rb | 5 + ...1102706_add_uprn_selection_to_sales_log.rb | 5 + db/schema.rb | 10 +- .../lettings_log_csv_export_codes_23.csv | 4 +- .../lettings_log_csv_export_codes_24.csv | 4 +- .../lettings_log_csv_export_labels_23.csv | 4 +- .../lettings_log_csv_export_labels_24.csv | 4 +- .../files/sales_logs_csv_export_codes_23.csv | 4 +- .../files/sales_logs_csv_export_codes_24.csv | 4 +- .../files/sales_logs_csv_export_labels_23.csv | 4 +- .../files/sales_logs_csv_export_labels_24.csv | 4 +- .../lettings/pages/address_fallback_spec.rb | 40 +++++++ .../lettings/pages/address_matcher_spec.rb | 33 ++++++ .../lettings/pages/no_address_found_spec.rb | 46 ++++++++ .../lettings/pages/uprn_selection_spec.rb | 44 ++++++++ spec/models/form/lettings/pages/uprn_spec.rb | 42 ++++++-- .../address_line1_for_address_matcher_spec.rb | 62 +++++++++++ .../questions/no_address_found_spec.rb | 44 ++++++++ .../postcode_for_address_matcher_spec.rb | 62 +++++++++++ .../lettings/questions/uprn_selection_spec.rb | 102 ++++++++++++++++++ .../subsections/property_information_spec.rb | 5 +- .../form/sales/pages/address_fallback_spec.rb | 40 +++++++ .../form/sales/pages/address_matcher_spec.rb | 33 ++++++ .../form/sales/pages/no_address_found_spec.rb | 46 ++++++++ .../form/sales/pages/uprn_selection_spec.rb | 44 ++++++++ spec/models/form/sales/pages/uprn_spec.rb | 42 ++++++-- .../address_line1_for_address_matcher_spec.rb | 62 +++++++++++ .../sales/questions/no_address_found_spec.rb | 44 ++++++++ .../postcode_for_address_matcher_spec.rb | 62 +++++++++++ .../sales/questions/uprn_selection_spec.rb | 102 ++++++++++++++++++ .../subsections/property_information_spec.rb | 18 +++- spec/services/address_client_spec.rb | 68 ++++++++++++ spec/services/address_data_presenter_spec.rb | 51 +++++++++ .../lettings/year2024/row_parser_spec.rb | 25 ++++- .../sales/year2024/row_parser_spec.rb | 4 + spec/shared/shared_log_examples.rb | 78 ++++++++++++++ 71 files changed, 1876 insertions(+), 75 deletions(-) create mode 100644 app/models/form/lettings/pages/address_fallback.rb create mode 100644 app/models/form/lettings/pages/address_matcher.rb create mode 100644 app/models/form/lettings/pages/no_address_found.rb create mode 100644 app/models/form/lettings/pages/uprn_selection.rb create mode 100644 app/models/form/lettings/questions/address_line1_for_address_matcher.rb create mode 100644 app/models/form/lettings/questions/no_address_found.rb create mode 100644 app/models/form/lettings/questions/postcode_for_address_matcher.rb create mode 100644 app/models/form/lettings/questions/uprn_selection.rb create mode 100644 app/models/form/sales/pages/address_fallback.rb create mode 100644 app/models/form/sales/pages/address_matcher.rb create mode 100644 app/models/form/sales/pages/no_address_found.rb create mode 100644 app/models/form/sales/pages/uprn_selection.rb create mode 100644 app/models/form/sales/questions/address_line1_for_address_matcher.rb create mode 100644 app/models/form/sales/questions/no_address_found.rb create mode 100644 app/models/form/sales/questions/postcode_for_address_matcher.rb create mode 100644 app/models/form/sales/questions/uprn_selection.rb create mode 100644 app/services/address_client.rb create mode 100644 app/services/address_data_presenter.rb create mode 100644 db/migrate/20240304103216_add_address_input_fields_to_lettings_log.rb create mode 100644 db/migrate/20240304115940_add_address_lookup_fields_to_sales_logs.rb create mode 100644 db/migrate/20240306091659_add_no_address_found_check_to_lettings_logs.rb create mode 100644 db/migrate/20240307161802_add_address_search_value_check_to_sales_logs.rb create mode 100644 db/migrate/20240311094307_add_uprn_selection_to_lettings_log.rb create mode 100644 db/migrate/20240311102706_add_uprn_selection_to_sales_log.rb create mode 100644 spec/models/form/lettings/pages/address_fallback_spec.rb create mode 100644 spec/models/form/lettings/pages/address_matcher_spec.rb create mode 100644 spec/models/form/lettings/pages/no_address_found_spec.rb create mode 100644 spec/models/form/lettings/pages/uprn_selection_spec.rb create mode 100644 spec/models/form/lettings/questions/address_line1_for_address_matcher_spec.rb create mode 100644 spec/models/form/lettings/questions/no_address_found_spec.rb create mode 100644 spec/models/form/lettings/questions/postcode_for_address_matcher_spec.rb create mode 100644 spec/models/form/lettings/questions/uprn_selection_spec.rb create mode 100644 spec/models/form/sales/pages/address_fallback_spec.rb create mode 100644 spec/models/form/sales/pages/address_matcher_spec.rb create mode 100644 spec/models/form/sales/pages/no_address_found_spec.rb create mode 100644 spec/models/form/sales/pages/uprn_selection_spec.rb create mode 100644 spec/models/form/sales/questions/address_line1_for_address_matcher_spec.rb create mode 100644 spec/models/form/sales/questions/no_address_found_spec.rb create mode 100644 spec/models/form/sales/questions/postcode_for_address_matcher_spec.rb create mode 100644 spec/models/form/sales/questions/uprn_selection_spec.rb create mode 100644 spec/services/address_client_spec.rb create mode 100644 spec/services/address_data_presenter_spec.rb diff --git a/app/models/form/lettings/pages/address_fallback.rb b/app/models/form/lettings/pages/address_fallback.rb new file mode 100644 index 000000000..67f8ef5b1 --- /dev/null +++ b/app/models/form/lettings/pages/address_fallback.rb @@ -0,0 +1,25 @@ +class Form::Lettings::Pages::AddressFallback < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "address" + @header = "Q12 - What is the property's address?" + @depends_on = [ + { "is_supported_housing?" => false, "uprn_known" => nil, "uprn_selection" => "uprn_not_listed" }, + { "is_supported_housing?" => false, "uprn_known" => 0, "uprn_selection" => "uprn_not_listed" }, + { "is_supported_housing?" => false, "uprn_confirmed" => 0, "uprn_selection" => "uprn_not_listed" }, + { "is_supported_housing?" => false, "uprn_known" => nil, "address_options_present?" => false }, + { "is_supported_housing?" => false, "uprn_known" => 0, "address_options_present?" => false }, + { "is_supported_housing?" => false, "uprn_confirmed" => 0, "address_options_present?" => false }, + ] + end + + def questions + @questions ||= [ + Form::Lettings::Questions::AddressLine1.new(nil, nil, self), + Form::Lettings::Questions::AddressLine2.new(nil, nil, self), + Form::Lettings::Questions::TownOrCity.new(nil, nil, self), + Form::Lettings::Questions::County.new(nil, nil, self), + Form::Lettings::Questions::PostcodeForFullAddress.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/lettings/pages/address_matcher.rb b/app/models/form/lettings/pages/address_matcher.rb new file mode 100644 index 000000000..2f19519b8 --- /dev/null +++ b/app/models/form/lettings/pages/address_matcher.rb @@ -0,0 +1,19 @@ +class Form::Lettings::Pages::AddressMatcher < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "address_matcher" + @header = "Find an address" + @depends_on = [ + { "is_supported_housing?" => false, "uprn_known" => nil }, + { "is_supported_housing?" => false, "uprn_known" => 0 }, + { "is_supported_housing?" => false, "uprn_confirmed" => 0 }, + ] + end + + def questions + @questions ||= [ + Form::Lettings::Questions::AddressLine1ForAddressMatcher.new(nil, nil, self), + Form::Lettings::Questions::PostcodeForAddressMatcher.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/lettings/pages/no_address_found.rb b/app/models/form/lettings/pages/no_address_found.rb new file mode 100644 index 000000000..23eba8eed --- /dev/null +++ b/app/models/form/lettings/pages/no_address_found.rb @@ -0,0 +1,26 @@ +class Form::Lettings::Pages::NoAddressFound < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "no_address_found" + @type = "interruption_screen" + @title_text = { + "translation" => "soft_validations.no_address_found.title_text", + "arguments" => [], + } + @informative_text = { + "translation" => "soft_validations.no_address_found.informative_text", + "arguments" => [], + } + @depends_on = [{ "address_options_present?" => false }] + end + + def questions + @questions ||= [ + Form::Lettings::Questions::NoAddressFound.new(nil, nil, self), + ] + end + + def interruption_screen_question_ids + %w[address_line1_input] + end +end diff --git a/app/models/form/lettings/pages/uprn.rb b/app/models/form/lettings/pages/uprn.rb index eb59e4a24..83ea11507 100644 --- a/app/models/form/lettings/pages/uprn.rb +++ b/app/models/form/lettings/pages/uprn.rb @@ -13,12 +13,20 @@ class Form::Lettings::Pages::Uprn < ::Form::Page end def skip_text - "Enter address instead" + if form.start_year_after_2024? + "Search for address instead" + else + "Enter address instead" + end end def skip_href(log = nil) return unless log - "/#{log.model_name.param_key.dasherize}s/#{log.id}/address" + if form.start_year_after_2024? + "/#{log.model_name.param_key.dasherize}s/#{log.id}/address-matcher" + else + "/#{log.model_name.param_key.dasherize}s/#{log.id}/address" + end end end diff --git a/app/models/form/lettings/pages/uprn_selection.rb b/app/models/form/lettings/pages/uprn_selection.rb new file mode 100644 index 000000000..521c1e270 --- /dev/null +++ b/app/models/form/lettings/pages/uprn_selection.rb @@ -0,0 +1,28 @@ +class Form::Lettings::Pages::UprnSelection < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "uprn_selection" + @header = "We found some addresses that might be this property" + @depends_on = [{ "address_options_present?" => true }] + end + + def questions + @questions ||= [ + Form::Lettings::Questions::UprnSelection.new(nil, nil, self), + ] + end + + def routed_to?(log, _current_user = nil) + (log.uprn_known.nil? || log.uprn_known.zero?) && log.address_line1_input.present? && log.postcode_full_input.present? && (1..10).cover?(log.address_options&.count) + end + + def skip_text + "Search for address again" + end + + def skip_href(log = nil) + return unless log + + "/#{log.model_name.param_key.dasherize}s/#{log.id}/address-matcher" + end +end diff --git a/app/models/form/lettings/questions/address_line1_for_address_matcher.rb b/app/models/form/lettings/questions/address_line1_for_address_matcher.rb new file mode 100644 index 000000000..b2247a8f0 --- /dev/null +++ b/app/models/form/lettings/questions/address_line1_for_address_matcher.rb @@ -0,0 +1,20 @@ +class Form::Lettings::Questions::AddressLine1ForAddressMatcher < ::Form::Question + def initialize(id, hsh, page) + super + @id = "address_line1_input" + @header = "Address line 1" + @error_label = "Address line 1" + @type = "text" + @plain_label = true + @check_answer_label = "Find address" + @disable_clearing_if_not_routed_or_dynamic_answer_options = true + @hide_question_number_on_page = true + end + + def answer_label(log, _current_user = nil) + [ + log.address_line1_input, + log.postcode_full_input, + ].select(&:present?).join("\n") + end +end diff --git a/app/models/form/lettings/questions/no_address_found.rb b/app/models/form/lettings/questions/no_address_found.rb new file mode 100644 index 000000000..6f3008d0a --- /dev/null +++ b/app/models/form/lettings/questions/no_address_found.rb @@ -0,0 +1,9 @@ +class Form::Lettings::Questions::NoAddressFound < ::Form::Question + def initialize(id, hsh, page) + super + @id = "address_search_value_check" + @header = "No address found" + @type = "interruption_screen" + @hidden_in_check_answers = true + end +end diff --git a/app/models/form/lettings/questions/postcode_for_address_matcher.rb b/app/models/form/lettings/questions/postcode_for_address_matcher.rb new file mode 100644 index 000000000..2cac3ce92 --- /dev/null +++ b/app/models/form/lettings/questions/postcode_for_address_matcher.rb @@ -0,0 +1,13 @@ +class Form::Lettings::Questions::PostcodeForAddressMatcher < ::Form::Question + def initialize(id, hsh, page) + super + @id = "postcode_full_input" + @header = "Postcode" + @type = "text" + @width = 5 + @plain_label = true + @disable_clearing_if_not_routed_or_dynamic_answer_options = true + @hide_question_number_on_page = true + @hidden_in_check_answers = true + end +end diff --git a/app/models/form/lettings/questions/uprn_confirmation.rb b/app/models/form/lettings/questions/uprn_confirmation.rb index 5b7bbd535..1c31485b6 100644 --- a/app/models/form/lettings/questions/uprn_confirmation.rb +++ b/app/models/form/lettings/questions/uprn_confirmation.rb @@ -4,14 +4,22 @@ class Form::Lettings::Questions::UprnConfirmation < ::Form::Question @id = "uprn_confirmed" @header = "Is this the property address?" @type = "radio" - @answer_options = ANSWER_OPTIONS @check_answer_label = "Is this the right address?" end - ANSWER_OPTIONS = { - "1" => { "value" => "Yes" }, - "0" => { "value" => "No, I want to enter the address manually" }, - }.freeze + def answer_options + if form.start_year_after_2024? + { + "1" => { "value" => "Yes" }, + "0" => { "value" => "No, I want to search for the address instead" }, + }.freeze + else + { + "1" => { "value" => "Yes" }, + "0" => { "value" => "No, I want to enter the address manually" }, + }.freeze + end + end def notification_banner(log = nil) return unless log&.uprn diff --git a/app/models/form/lettings/questions/uprn_selection.rb b/app/models/form/lettings/questions/uprn_selection.rb new file mode 100644 index 000000000..d7f412c66 --- /dev/null +++ b/app/models/form/lettings/questions/uprn_selection.rb @@ -0,0 +1,34 @@ +class Form::Lettings::Questions::UprnSelection < ::Form::Question + def initialize(id, hsh, page) + super + @id = "uprn_selection" + @header = "Select the correct address" + @type = "radio" + @check_answer_label = "Select the correct address" + @disable_clearing_if_not_routed_or_dynamic_answer_options = true + end + + def answer_options(log = nil, _user = nil) + answer_opts = { "uprn_not_listed" => { "value" => "The address is not listed, I want to enter the address manually" } } + return answer_opts unless ActiveRecord::Base.connected? + return answer_opts unless log&.address_options + + answer_opts = {} + + (0...[log.address_options.count, 10].min).each do |i| + answer_opts[log.address_options[i][:uprn]] = { "value" => log.address_options[i][:address] } + end + + answer_opts["divider"] = { "value" => true } + answer_opts["uprn_not_listed"] = { "value" => "The address is not listed, I want to enter the address manually" } + answer_opts + end + + def displayed_answer_options(log, user = nil) + answer_options(log, user) + end + + def hidden_in_check_answers?(log, _current_user = nil) + (log.uprn_known == 1 || log.uprn_confirmed == 1) || !(1..10).cover?(log.address_options&.count) + end +end diff --git a/app/models/form/lettings/subsections/property_information.rb b/app/models/form/lettings/subsections/property_information.rb index 4600d5e95..67a22c7f5 100644 --- a/app/models/form/lettings/subsections/property_information.rb +++ b/app/models/form/lettings/subsections/property_information.rb @@ -31,7 +31,16 @@ class Form::Lettings::Subsections::PropertyInformation < ::Form::Subsection end def uprn_questions - if form.start_date.year >= 2023 + if form.start_year_after_2024? + [ + Form::Lettings::Pages::Uprn.new(nil, nil, self), + Form::Lettings::Pages::UprnConfirmation.new(nil, nil, self), + Form::Lettings::Pages::AddressMatcher.new(nil, nil, self), + Form::Lettings::Pages::NoAddressFound.new(nil, nil, self), + Form::Lettings::Pages::UprnSelection.new(nil, nil, self), + Form::Lettings::Pages::AddressFallback.new(nil, nil, self), + ] + elsif form.start_date.year == 2023 [ Form::Lettings::Pages::Uprn.new(nil, nil, self), Form::Lettings::Pages::UprnConfirmation.new(nil, nil, self), diff --git a/app/models/form/sales/pages/address_fallback.rb b/app/models/form/sales/pages/address_fallback.rb new file mode 100644 index 000000000..3a69dabba --- /dev/null +++ b/app/models/form/sales/pages/address_fallback.rb @@ -0,0 +1,25 @@ +class Form::Sales::Pages::AddressFallback < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "address" + @header = "Q12 - What is the property's address?" + @depends_on = [ + { "uprn_known" => nil, "uprn_selection" => "uprn_not_listed" }, + { "uprn_known" => 0, "uprn_selection" => "uprn_not_listed" }, + { "uprn_confirmed" => 0, "uprn_selection" => "uprn_not_listed" }, + { "uprn_known" => nil, "address_options_present?" => false }, + { "uprn_known" => 0, "address_options_present?" => false }, + { "uprn_confirmed" => 0, "address_options_present?" => false }, + ] + end + + def questions + @questions ||= [ + Form::Sales::Questions::AddressLine1.new(nil, nil, self), + Form::Sales::Questions::AddressLine2.new(nil, nil, self), + Form::Sales::Questions::TownOrCity.new(nil, nil, self), + Form::Sales::Questions::County.new(nil, nil, self), + Form::Sales::Questions::PostcodeForFullAddress.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/pages/address_matcher.rb b/app/models/form/sales/pages/address_matcher.rb new file mode 100644 index 000000000..f4a02972c --- /dev/null +++ b/app/models/form/sales/pages/address_matcher.rb @@ -0,0 +1,19 @@ +class Form::Sales::Pages::AddressMatcher < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "address_matcher" + @header = "Find an address" + @depends_on = [ + { "uprn_known" => nil }, + { "uprn_known" => 0 }, + { "uprn_confirmed" => 0 }, + ] + end + + def questions + @questions ||= [ + Form::Sales::Questions::AddressLine1ForAddressMatcher.new(nil, nil, self), + Form::Sales::Questions::PostcodeForAddressMatcher.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/pages/no_address_found.rb b/app/models/form/sales/pages/no_address_found.rb new file mode 100644 index 000000000..a37408379 --- /dev/null +++ b/app/models/form/sales/pages/no_address_found.rb @@ -0,0 +1,26 @@ +class Form::Sales::Pages::NoAddressFound < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "no_address_found" + @type = "interruption_screen" + @title_text = { + "translation" => "soft_validations.no_address_found.title_text", + "arguments" => [], + } + @informative_text = { + "translation" => "soft_validations.no_address_found.informative_text", + "arguments" => [], + } + @depends_on = [{ "address_options_present?" => false }] + end + + def questions + @questions ||= [ + Form::Sales::Questions::NoAddressFound.new(nil, nil, self), + ] + end + + def interruption_screen_question_ids + %w[address_line1_input] + end +end diff --git a/app/models/form/sales/pages/uprn.rb b/app/models/form/sales/pages/uprn.rb index c4ae5b357..05727878e 100644 --- a/app/models/form/sales/pages/uprn.rb +++ b/app/models/form/sales/pages/uprn.rb @@ -12,12 +12,20 @@ class Form::Sales::Pages::Uprn < ::Form::Page end def skip_text - "Enter address instead" + if form.start_year_after_2024? + "Search for address instead" + else + "Enter address instead" + end end def skip_href(log = nil) return unless log - "/#{log.model_name.param_key.dasherize}s/#{log.id}/address" + if form.start_year_after_2024? + "/#{log.model_name.param_key.dasherize}s/#{log.id}/address-matcher" + else + "/#{log.model_name.param_key.dasherize}s/#{log.id}/address" + end end end diff --git a/app/models/form/sales/pages/uprn_selection.rb b/app/models/form/sales/pages/uprn_selection.rb new file mode 100644 index 000000000..71ab3c5ac --- /dev/null +++ b/app/models/form/sales/pages/uprn_selection.rb @@ -0,0 +1,28 @@ +class Form::Sales::Pages::UprnSelection < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "uprn_selection" + @header = "We found some addresses that might be this property" + @depends_on = [{ "address_options_present?" => true }] + end + + def questions + @questions ||= [ + Form::Sales::Questions::UprnSelection.new(nil, nil, self), + ] + end + + def routed_to?(log, _current_user = nil) + (log.uprn_known.nil? || log.uprn_known.zero?) && log.address_line1_input.present? && log.postcode_full_input.present? && (1..10).cover?(log.address_options&.count) + end + + def skip_text + "Search for address again" + end + + def skip_href(log = nil) + return unless log + + "/#{log.model_name.param_key.dasherize}s/#{log.id}/address-matcher" + end +end diff --git a/app/models/form/sales/questions/address_line1_for_address_matcher.rb b/app/models/form/sales/questions/address_line1_for_address_matcher.rb new file mode 100644 index 000000000..fd1211b69 --- /dev/null +++ b/app/models/form/sales/questions/address_line1_for_address_matcher.rb @@ -0,0 +1,20 @@ +class Form::Sales::Questions::AddressLine1ForAddressMatcher < ::Form::Question + def initialize(id, hsh, page) + super + @id = "address_line1_input" + @header = "Address line 1" + @error_label = "Address line 1" + @type = "text" + @plain_label = true + @check_answer_label = "Find address" + @disable_clearing_if_not_routed_or_dynamic_answer_options = true + @hide_question_number_on_page = true + end + + def answer_label(log, _current_user = nil) + [ + log.address_line1_input, + log.postcode_full_input, + ].select(&:present?).join("\n") + end +end diff --git a/app/models/form/sales/questions/no_address_found.rb b/app/models/form/sales/questions/no_address_found.rb new file mode 100644 index 000000000..0db041111 --- /dev/null +++ b/app/models/form/sales/questions/no_address_found.rb @@ -0,0 +1,9 @@ +class Form::Sales::Questions::NoAddressFound < ::Form::Question + def initialize(id, hsh, page) + super + @id = "address_search_value_check" + @header = "No address found" + @type = "interruption_screen" + @hidden_in_check_answers = true + end +end diff --git a/app/models/form/sales/questions/postcode_for_address_matcher.rb b/app/models/form/sales/questions/postcode_for_address_matcher.rb new file mode 100644 index 000000000..421cdc4fc --- /dev/null +++ b/app/models/form/sales/questions/postcode_for_address_matcher.rb @@ -0,0 +1,13 @@ +class Form::Sales::Questions::PostcodeForAddressMatcher < ::Form::Question + def initialize(id, hsh, page) + super + @id = "postcode_full_input" + @header = "Postcode" + @type = "text" + @width = 5 + @plain_label = true + @disable_clearing_if_not_routed_or_dynamic_answer_options = true + @hide_question_number_on_page = true + @hidden_in_check_answers = true + end +end diff --git a/app/models/form/sales/questions/uprn_confirmation.rb b/app/models/form/sales/questions/uprn_confirmation.rb index 38ad9c938..6954a6ea5 100644 --- a/app/models/form/sales/questions/uprn_confirmation.rb +++ b/app/models/form/sales/questions/uprn_confirmation.rb @@ -4,14 +4,22 @@ class Form::Sales::Questions::UprnConfirmation < ::Form::Question @id = "uprn_confirmed" @header = "Is this the property address?" @type = "radio" - @answer_options = ANSWER_OPTIONS @check_answer_label = "Is this the right address?" end - ANSWER_OPTIONS = { - "1" => { "value" => "Yes" }, - "0" => { "value" => "No, I want to enter the address manually" }, - }.freeze + def answer_options + if form.start_year_after_2024? + { + "1" => { "value" => "Yes" }, + "0" => { "value" => "No, I want to search for the address instead" }, + }.freeze + else + { + "1" => { "value" => "Yes" }, + "0" => { "value" => "No, I want to enter the address manually" }, + }.freeze + end + end def notification_banner(log = nil) return unless log&.uprn diff --git a/app/models/form/sales/questions/uprn_selection.rb b/app/models/form/sales/questions/uprn_selection.rb new file mode 100644 index 000000000..2ffb679db --- /dev/null +++ b/app/models/form/sales/questions/uprn_selection.rb @@ -0,0 +1,34 @@ +class Form::Sales::Questions::UprnSelection < ::Form::Question + def initialize(id, hsh, page) + super + @id = "uprn_selection" + @header = "Select the correct address" + @type = "radio" + @check_answer_label = "Select the correct address" + @disable_clearing_if_not_routed_or_dynamic_answer_options = true + end + + def answer_options(log = nil, _user = nil) + answer_opts = { "uprn_not_listed" => { "value" => "The address is not listed, I want to enter the address manually" } } + return answer_opts unless ActiveRecord::Base.connected? + return answer_opts unless log&.address_options + + answer_opts = {} + + (0...[log.address_options.count, 10].min).each do |i| + answer_opts[log.address_options[i][:uprn]] = { "value" => log.address_options[i][:address] } + end + + answer_opts["divider"] = { "value" => true } + answer_opts["uprn_not_listed"] = { "value" => "The address is not listed, I want to enter the address manually" } + answer_opts + end + + def displayed_answer_options(log, user = nil) + answer_options(log, user) + end + + def hidden_in_check_answers?(log, _current_user = nil) + (log.uprn_known == 1 || log.uprn_confirmed == 1) || !(1..10).cover?(log.address_options&.count) + end +end diff --git a/app/models/form/sales/subsections/property_information.rb b/app/models/form/sales/subsections/property_information.rb index 302dfa7c7..2c530ab60 100644 --- a/app/models/form/sales/subsections/property_information.rb +++ b/app/models/form/sales/subsections/property_information.rb @@ -22,16 +22,32 @@ class Form::Sales::Subsections::PropertyInformation < ::Form::Subsection end def uprn_questions - [ - Form::Sales::Pages::Uprn.new(nil, nil, self), - Form::Sales::Pages::UprnConfirmation.new(nil, nil, self), - Form::Sales::Pages::Address.new(nil, nil, self), - Form::Sales::Pages::PropertyLocalAuthority.new(nil, nil, self), - Form::Sales::Pages::Buyer1IncomeMaxValueCheck.new("local_authority_buyer_1_income_max_value_check", nil, self, check_answers_card_number: nil), - Form::Sales::Pages::Buyer2IncomeMaxValueCheck.new("local_authority_buyer_2_income_max_value_check", nil, self, check_answers_card_number: nil), - Form::Sales::Pages::CombinedIncomeMaxValueCheck.new("local_authority_combined_income_max_value_check", nil, self, check_answers_card_number: nil), - Form::Sales::Pages::AboutPriceValueCheck.new("about_price_la_value_check", nil, self), - ] + if form.start_year_after_2024? + [ + Form::Sales::Pages::Uprn.new(nil, nil, self), + Form::Sales::Pages::UprnConfirmation.new(nil, nil, self), + Form::Sales::Pages::AddressMatcher.new(nil, nil, self), + Form::Sales::Pages::NoAddressFound.new(nil, nil, self), + Form::Sales::Pages::UprnSelection.new(nil, nil, self), + Form::Sales::Pages::AddressFallback.new(nil, nil, self), + Form::Sales::Pages::PropertyLocalAuthority.new(nil, nil, self), + Form::Sales::Pages::Buyer1IncomeMaxValueCheck.new("local_authority_buyer_1_income_max_value_check", nil, self, check_answers_card_number: nil), + Form::Sales::Pages::Buyer2IncomeMaxValueCheck.new("local_authority_buyer_2_income_max_value_check", nil, self, check_answers_card_number: nil), + Form::Sales::Pages::CombinedIncomeMaxValueCheck.new("local_authority_combined_income_max_value_check", nil, self, check_answers_card_number: nil), + Form::Sales::Pages::AboutPriceValueCheck.new("about_price_la_value_check", nil, self), + ] + else + [ + Form::Sales::Pages::Uprn.new(nil, nil, self), + Form::Sales::Pages::UprnConfirmation.new(nil, nil, self), + Form::Sales::Pages::Address.new(nil, nil, self), + Form::Sales::Pages::PropertyLocalAuthority.new(nil, nil, self), + Form::Sales::Pages::Buyer1IncomeMaxValueCheck.new("local_authority_buyer_1_income_max_value_check", nil, self, check_answers_card_number: nil), + Form::Sales::Pages::Buyer2IncomeMaxValueCheck.new("local_authority_buyer_2_income_max_value_check", nil, self, check_answers_card_number: nil), + Form::Sales::Pages::CombinedIncomeMaxValueCheck.new("local_authority_combined_income_max_value_check", nil, self, check_answers_card_number: nil), + Form::Sales::Pages::AboutPriceValueCheck.new("about_price_la_value_check", nil, self), + ] + end end def postcode_and_la_questions diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb index 88bc5a43e..c8ab06b3d 100644 --- a/app/models/lettings_log.rb +++ b/app/models/lettings_log.rb @@ -34,6 +34,7 @@ class LettingsLog < Log before_validation :reset_previous_location_fields!, unless: :previous_postcode_known? before_validation :set_derived_fields! before_validation :process_uprn_change!, if: :should_process_uprn_change? + before_validation :process_address_change!, if: :should_process_address_change? belongs_to :scheme, optional: true belongs_to :location, optional: true @@ -845,6 +846,22 @@ private end def should_process_uprn_change? - uprn && startdate && (uprn_changed? || startdate_changed?) && collection_start_year_for_date(startdate) >= 2023 + return unless uprn + return unless startdate + return unless collection_start_year_for_date(startdate) >= 2023 + + uprn_changed? || startdate_changed? + end + + def should_process_address_change? + return unless uprn_selection || select_best_address_match + return unless startdate + return unless form.start_year_after_2024? + + if select_best_address_match + address_line1_input.present? && postcode_full_input.present? + else + uprn_selection_changed? || startdate_changed? + end end end diff --git a/app/models/log.rb b/app/models/log.rb index e15869634..8847812d3 100644 --- a/app/models/log.rb +++ b/app/models/log.rb @@ -53,19 +53,26 @@ class Log < ApplicationRecord scope :filter_by_owning_organisation, ->(owning_organisation, _user = nil) { where(owning_organisation:) } scope :filter_by_managing_organisation, ->(managing_organisation, _user = nil) { where(managing_organisation:) } - attr_accessor :skip_update_status, :skip_update_uprn_confirmed, :skip_dpo_validation + attr_accessor :skip_update_status, :skip_update_uprn_confirmed, :select_best_address_match, :skip_dpo_validation + + delegate :present?, to: :address_options, prefix: true def process_uprn_change! if uprn.present? service = UprnClient.new(uprn) service.call - return errors.add(:uprn, :uprn_error, message: service.error) if service.error.present? + if service.error.present? + errors.add(:uprn, :uprn_error, message: service.error) + errors.add(:uprn_selection, :uprn_error, message: service.error) + return + end presenter = UprnDataPresenter.new(service.result) self.uprn_known = 1 self.uprn_confirmed = nil unless skip_update_uprn_confirmed + self.uprn_selection = nil self.address_line1 = presenter.address_line1 self.address_line2 = presenter.address_line2 self.town_or_city = presenter.town_or_city @@ -75,6 +82,62 @@ class Log < ApplicationRecord end end + def process_address_change! + if uprn_selection.present? || select_best_address_match.present? + if select_best_address_match + service = AddressClient.new(address_string) + service.call + return nil if service.result.blank? || service.error.present? + + presenter = AddressDataPresenter.new(service.result.first) + os_match_threshold_for_bulk_upload = 0.7 + if presenter.match >= os_match_threshold_for_bulk_upload + self.uprn_selection = presenter.uprn + else + return nil + end + end + + if uprn_selection == "uprn_not_listed" + self.uprn_known = 0 + self.uprn_confirmed = nil + self.uprn = nil + self.address_line1 = address_line1_input + self.address_line2 = nil + self.town_or_city = nil + self.county = nil + self.postcode_full = postcode_full_input + else + self.uprn = uprn_selection + self.uprn_confirmed = 1 + self.skip_update_uprn_confirmed = true + process_uprn_change! + end + end + end + + def address_string + "#{address_line1_input}, #{postcode_full_input}" + end + + def address_options + return @address_options if @address_options + + if [address_line1_input, postcode_full_input].all?(&:present?) + service = AddressClient.new(address_string) + service.call + return nil if service.result.blank? || service.error.present? + + address_opts = [] + service.result.first(10).each do |result| + presenter = AddressDataPresenter.new(result) + address_opts.append({ address: presenter.address, uprn: presenter.uprn }) + end + + @address_options = address_opts + end + end + def collection_start_year return @start_year if @start_year diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb index c22575aa5..e75e4bb55 100644 --- a/app/models/sales_log.rb +++ b/app/models/sales_log.rb @@ -32,6 +32,7 @@ class SalesLog < Log before_validation :reset_previous_location_fields!, unless: :previous_postcode_known? before_validation :set_derived_fields! before_validation :process_uprn_change!, if: :should_process_uprn_change? + before_validation :process_address_change!, if: :should_process_address_change? belongs_to :managing_organisation, class_name: "Organisation", optional: true @@ -429,7 +430,23 @@ class SalesLog < Log end def should_process_uprn_change? - uprn && saledate && (uprn_changed? || saledate_changed?) && collection_start_year_for_date(saledate) >= 2023 + return unless uprn + return unless saledate + return unless collection_start_year_for_date(saledate) >= 2023 + + uprn_changed? || saledate_changed? + end + + def should_process_address_change? + return unless uprn_selection || select_best_address_match + return unless saledate + return unless form.start_year_after_2024? + + if select_best_address_match + address_line1_input.present? && postcode_full_input.present? + else + uprn_selection_changed? || saledate_changed? + end end def value_with_discount diff --git a/app/services/address_client.rb b/app/services/address_client.rb new file mode 100644 index 000000000..670fbe643 --- /dev/null +++ b/app/services/address_client.rb @@ -0,0 +1,52 @@ +require "net/http" + +class AddressClient + attr_reader :address + attr_accessor :error + + ADDRESS = "api.os.uk".freeze + PATH = "/search/places/v1/find".freeze + + def initialize(address) + @address = address + end + + def call + unless response.is_a?(Net::HTTPSuccess) && result.present? + @error = "Address is not recognised. Check the address, or enter the UPRN" + end + rescue JSON::ParserError + @error = "Address is not recognised. Check the address, or enter the UPRN" + end + + def result + @result ||= JSON.parse(response.body)["results"]&.map { |address| address["DPA"] } + end + +private + + def http_client + client = Net::HTTP.new(ADDRESS, 443) + client.use_ssl = true + client.verify_mode = OpenSSL::SSL::VERIFY_PEER + client.max_retries = 3 + client.read_timeout = 10 # seconds + client + end + + def endpoint_uri + uri = URI(PATH) + params = { + query: address, + key: ENV["OS_DATA_KEY"], + maxresults: 10, + minmatch: 0.4, + } + uri.query = URI.encode_www_form(params) + uri.to_s + end + + def response + @response ||= http_client.request_get(endpoint_uri) + end +end diff --git a/app/services/address_data_presenter.rb b/app/services/address_data_presenter.rb new file mode 100644 index 000000000..c72f32f43 --- /dev/null +++ b/app/services/address_data_presenter.rb @@ -0,0 +1,21 @@ +require "net/http" + +class AddressDataPresenter + attr_reader :data + + def initialize(data) + @data = data + end + + def uprn + data["UPRN"] + end + + def address + data["ADDRESS"] + end + + def match + data["MATCH"] + end +end diff --git a/app/services/bulk_upload/lettings/year2024/row_parser.rb b/app/services/bulk_upload/lettings/year2024/row_parser.rb index b23a6b57d..e03fd4817 100644 --- a/app/services/bulk_upload/lettings/year2024/row_parser.rb +++ b/app/services/bulk_upload/lettings/year2024/row_parser.rb @@ -409,6 +409,7 @@ class BulkUpload::Lettings::Year2024::RowParser validate :validate_created_by_exists, on: :after_log validate :validate_created_by_related, on: :after_log validate :validate_all_charges_given, on: :after_log, if: proc { is_carehome.zero? } + validate :validate_address_option_found, on: :after_log validate :validate_nulls, on: :after_log @@ -572,6 +573,14 @@ private end end + def validate_address_option_found + if !log.address_options_present? && field_16.blank? && (field_17.present? || field_19.present?) + %i[field_17 field_18 field_19 field_20 field_21 field_22].each do |field| + errors.add(field, I18n.t("validations.no_address_found")) + end + end + end + def validate_incomplete_soft_validations routed_to_soft_validation_questions = log.form.questions.filter { |q| q.type == "interruption_screen" && q.page.routed_to?(log, nil) }.compact routed_to_soft_validation_questions.each do |question| @@ -1065,6 +1074,7 @@ private address_line2: [:field_18], town_or_city: [:field_19], county: [:field_20], + uprn_selection: [:field_17], }.compact end @@ -1261,10 +1271,17 @@ private attributes["address_line2"] = field_18 attributes["town_or_city"] = field_19 attributes["county"] = field_20 + attributes["address_line1_input"] = address_line1_input + attributes["postcode_full_input"] = postcode_full + attributes["select_best_address_match"] = true if field_16.blank? attributes end + def address_line1_input + [field_17, field_18, field_19].compact.join(", ") + end + def postcode_known if postcode_full.present? 1 diff --git a/app/services/bulk_upload/sales/year2024/row_parser.rb b/app/services/bulk_upload/sales/year2024/row_parser.rb index 48f451843..7a1481300 100644 --- a/app/services/bulk_upload/sales/year2024/row_parser.rb +++ b/app/services/bulk_upload/sales/year2024/row_parser.rb @@ -450,6 +450,7 @@ class BulkUpload::Sales::Year2024::RowParser on: :after_log validate :validate_buyer1_economic_status, on: :before_log + validate :validate_address_option_found, on: :after_log validate :validate_nulls, on: :after_log validate :validate_valid_radio_option, on: :before_log @@ -597,6 +598,14 @@ private end end + def validate_address_option_found + if !log.address_options_present? && field_22.blank? && (field_23.present? || field_25.present?) + %i[field_23 field_24 field_25 field_26 field_27 field_28].each do |field| + errors.add(field, I18n.t("validations.no_address_found")) + end + end + end + def validate_address_fields if field_22.blank? || log.errors.attribute_names.include?(:uprn) if field_23.blank? @@ -758,6 +767,7 @@ private address_line2: %i[field_24], town_or_city: %i[field_25], county: %i[field_26], + uprn_selection: [:field_23], ethnic_group2: %i[field_40], ethnicbuy2: %i[field_40], @@ -932,6 +942,9 @@ private attributes["address_line2"] = field_24 attributes["town_or_city"] = field_25 attributes["county"] = field_26 + attributes["address_line1_input"] = address_line1_input + attributes["postcode_full_input"] = postcode_full + attributes["select_best_address_match"] = true if field_22.blank? attributes["ethnic_group2"] = infer_buyer2_ethnic_group_from_ethnic attributes["ethnicbuy2"] = field_40 @@ -948,6 +961,10 @@ private attributes end + def address_line1_input + [field_23, field_24, field_25].compact.join(", ") + end + def saledate Date.new(field_6 + 2000, field_5, field_4) if field_6.present? && field_5.present? && field_4.present? rescue Date::Error diff --git a/app/services/csv/lettings_log_csv_service.rb b/app/services/csv/lettings_log_csv_service.rb index e67363188..2dd817ebe 100644 --- a/app/services/csv/lettings_log_csv_service.rb +++ b/app/services/csv/lettings_log_csv_service.rb @@ -296,7 +296,7 @@ module Csv "letting_allocation_unknown" => %w[letting_allocation_none], }.freeze - SUPPORT_ONLY_ATTRIBUTES = %w[net_income_value_check first_time_property_let_as_social_housing postcode_known is_la_inferred totchild totelder totadult net_income_known previous_la_known is_previous_la_inferred age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 wrent wscharge wpschrge wsupchrg wtcharge wtshortfall rent_value_check old_form_id old_id retirement_value_check tshortfall_known pregnancy_value_check hhtype new_old la prevloc updated_by_id bulk_upload_id uprn_confirmed reasonother_value_check].freeze + SUPPORT_ONLY_ATTRIBUTES = %w[net_income_value_check first_time_property_let_as_social_housing postcode_known is_la_inferred totchild totelder totadult net_income_known previous_la_known is_previous_la_inferred age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 wrent wscharge wpschrge wsupchrg wtcharge wtshortfall rent_value_check old_form_id old_id retirement_value_check tshortfall_known pregnancy_value_check hhtype new_old la prevloc updated_by_id bulk_upload_id uprn_confirmed address_line1_input postcode_full_input address_search_value_check uprn_selection reasonother_value_check].freeze def lettings_log_attributes ordered_questions = FormHandler.instance.ordered_lettings_questions_for_all_years diff --git a/config/locales/en.yml b/config/locales/en.yml index f30de4119..8612e0367 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -213,6 +213,7 @@ en: not_answered: "You must answer %{question}" invalid_option: "Enter a valid value for %{question}" invalid_number: "Enter a number for %{question}" + no_address_found: "We could not find this address. Edit the address data or fix this error on the CORE site." other_field_missing: "If %{main_field_label} is other then %{other_field_label} must be provided" other_field_not_required: "%{other_field_label} must not be provided if %{main_field_label} was not other" @@ -759,7 +760,9 @@ Make sure these answers are correct." must_be_less_than_3_years_from_saledate: "You told us practical completion or handover date is more than 3 years before sale completion date" saledate: must_be_less_than_3_years_from_hodate: "You told us sale completion date is more than 3 years after practical completion or handover date" - + no_address_found: + 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." devise: email: diff --git a/db/migrate/20240304103216_add_address_input_fields_to_lettings_log.rb b/db/migrate/20240304103216_add_address_input_fields_to_lettings_log.rb new file mode 100644 index 000000000..671304569 --- /dev/null +++ b/db/migrate/20240304103216_add_address_input_fields_to_lettings_log.rb @@ -0,0 +1,8 @@ +class AddAddressInputFieldsToLettingsLog < ActiveRecord::Migration[7.0] + def change + change_table :lettings_logs, bulk: true do |t| + t.string :address_line1_input + t.string :postcode_full_input + end + end +end diff --git a/db/migrate/20240304115940_add_address_lookup_fields_to_sales_logs.rb b/db/migrate/20240304115940_add_address_lookup_fields_to_sales_logs.rb new file mode 100644 index 000000000..3a2bb77d7 --- /dev/null +++ b/db/migrate/20240304115940_add_address_lookup_fields_to_sales_logs.rb @@ -0,0 +1,8 @@ +class AddAddressLookupFieldsToSalesLogs < ActiveRecord::Migration[7.0] + def change + change_table :sales_logs, bulk: true do |t| + t.string :address_line1_input + t.string :postcode_full_input + end + end +end diff --git a/db/migrate/20240306091659_add_no_address_found_check_to_lettings_logs.rb b/db/migrate/20240306091659_add_no_address_found_check_to_lettings_logs.rb new file mode 100644 index 000000000..5d23a1657 --- /dev/null +++ b/db/migrate/20240306091659_add_no_address_found_check_to_lettings_logs.rb @@ -0,0 +1,5 @@ +class AddNoAddressFoundCheckToLettingsLogs < ActiveRecord::Migration[7.0] + def change + add_column :lettings_logs, :address_search_value_check, :integer + end +end diff --git a/db/migrate/20240307161802_add_address_search_value_check_to_sales_logs.rb b/db/migrate/20240307161802_add_address_search_value_check_to_sales_logs.rb new file mode 100644 index 000000000..84347e309 --- /dev/null +++ b/db/migrate/20240307161802_add_address_search_value_check_to_sales_logs.rb @@ -0,0 +1,5 @@ +class AddAddressSearchValueCheckToSalesLogs < ActiveRecord::Migration[7.0] + def change + add_column :sales_logs, :address_search_value_check, :integer + end +end diff --git a/db/migrate/20240311094307_add_uprn_selection_to_lettings_log.rb b/db/migrate/20240311094307_add_uprn_selection_to_lettings_log.rb new file mode 100644 index 000000000..f2e8f587c --- /dev/null +++ b/db/migrate/20240311094307_add_uprn_selection_to_lettings_log.rb @@ -0,0 +1,5 @@ +class AddUprnSelectionToLettingsLog < ActiveRecord::Migration[7.0] + def change + add_column :lettings_logs, :uprn_selection, :string + end +end diff --git a/db/migrate/20240311102706_add_uprn_selection_to_sales_log.rb b/db/migrate/20240311102706_add_uprn_selection_to_sales_log.rb new file mode 100644 index 000000000..b17419290 --- /dev/null +++ b/db/migrate/20240311102706_add_uprn_selection_to_sales_log.rb @@ -0,0 +1,5 @@ +class AddUprnSelectionToSalesLog < ActiveRecord::Migration[7.0] + def change + add_column :sales_logs, :uprn_selection, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index b9ee98fcd..6f17b99c4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_02_16_163519) do +ActiveRecord::Schema[7.0].define(version: 2024_03_11_102706) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -308,6 +308,10 @@ ActiveRecord::Schema[7.0].define(version: 2024_02_16_163519) do t.integer "nationality_all" t.integer "nationality_all_group" t.integer "reasonother_value_check" + t.string "address_line1_input" + t.string "postcode_full_input" + t.integer "address_search_value_check" + t.string "uprn_selection" t.index ["bulk_upload_id"], name: "index_lettings_logs_on_bulk_upload_id" t.index ["created_by_id"], name: "index_lettings_logs_on_created_by_id" t.index ["location_id"], name: "index_lettings_logs_on_location_id" @@ -661,6 +665,10 @@ ActiveRecord::Schema[7.0].define(version: 2024_02_16_163519) do t.integer "nationality_all_group" t.integer "nationality_all_buyer2" t.integer "nationality_all_buyer2_group" + t.string "address_line1_input" + t.string "postcode_full_input" + t.integer "address_search_value_check" + t.string "uprn_selection" t.index ["bulk_upload_id"], name: "index_sales_logs_on_bulk_upload_id" t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id" t.index ["managing_organisation_id"], name: "index_sales_logs_on_managing_organisation_id" diff --git a/spec/fixtures/files/lettings_log_csv_export_codes_23.csv b/spec/fixtures/files/lettings_log_csv_export_codes_23.csv index 39074143c..6ef3a8c41 100644 --- a/spec/fixtures/files/lettings_log_csv_export_codes_23.csv +++ b/spec/fixtures/files/lettings_log_csv_export_codes_23.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate -,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,1,4,,1,4,0,0,2,35,,F,0,2,,13,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,,2,,0,0,1,268,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,, +id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate +,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,0,,,,,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,1,4,,1,4,0,0,2,35,,F,0,2,,13,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,,2,,0,0,1,268,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/lettings_log_csv_export_codes_24.csv b/spec/fixtures/files/lettings_log_csv_export_codes_24.csv index 591a803bf..acc80f3ae 100644 --- a/spec/fixtures/files/lettings_log_csv_export_codes_24.csv +++ b/spec/fixtures/files/lettings_log_csv_export_codes_24.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate -,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,1,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,4,,1,4,0,0,2,35,,F,0,2,13,,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,0,,2,,0,0,1,268,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,, +id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate +,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,1,0,,,,,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,4,,1,4,0,0,2,35,,F,0,2,13,,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,0,,2,,0,0,1,268,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/lettings_log_csv_export_labels_23.csv b/spec/fixtures/files/lettings_log_csv_export_labels_23.csv index 0f6b4e40d..ea012876b 100644 --- a/spec/fixtures/files/lettings_log_csv_export_labels_23.csv +++ b/spec/fixtures/files/lettings_log_csv_export_labels_23.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate -,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,,Yes,4,0,0,2,35,,Female,White,Irish,,Tenant prefers not to say,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,Yes,No,Weekly,268,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, +id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate +,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,No,,,,,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,,Yes,4,0,0,2,35,,Female,White,Irish,,Tenant prefers not to say,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,Yes,No,Weekly,268,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/lettings_log_csv_export_labels_24.csv b/spec/fixtures/files/lettings_log_csv_export_labels_24.csv index 4234f7619..f196c1045 100644 --- a/spec/fixtures/files/lettings_log_csv_export_labels_24.csv +++ b/spec/fixtures/files/lettings_log_csv_export_labels_24.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate -,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,Yes,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,No,,Tenant applied directly (no referral or nomination),,Yes,No,Weekly,268,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, +id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate +,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,Yes,No,,,,,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,No,,Tenant applied directly (no referral or nomination),,Yes,No,Weekly,268,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/sales_logs_csv_export_codes_23.csv b/spec/fixtures/files/sales_logs_csv_export_codes_23.csv index ae93dd76c..bd2b7b305 100644 --- a/spec/fixtures/files/sales_logs_csv_export_codes_23.csv +++ b/spec/fixtures/files/sales_logs_csv_export_codes_23.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationality_all_buyer2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant -,completed,,2023-12-08T00:00:00+00:00,2024-01-01T00:00:00+00:00,,2023,1,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,2,8,,,,1,1,2,1,1,0,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,1,2,1,30,X,17,17,,18,1,1,P,35,X,17,,,13,1,1,3,C,14,X,9,X,-9,X,3,R,-9,R,10,,,,,1,1,,,0,,,1,1,1,1,,3,,1,4,5,1,1,0,10000,1,0,10000,1,4,1,,1,2,10,,,,,,,,,,,,,,,,,110000.0,,1,20000.0,5,,10,1,80000.0,,,1,100.0,,10000.0 +id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationality_all_buyer2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant +,completed,,2023-12-08T00:00:00+00:00,2024-01-01T00:00:00+00:00,,2023,1,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,2,8,,,,1,1,2,1,1,0,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,1,2,1,30,X,17,17,,18,1,1,P,35,X,17,,,13,1,1,3,C,14,X,9,X,-9,X,3,R,-9,R,10,,,,,1,1,,,0,,,1,1,1,1,,3,,1,4,5,1,1,0,10000,1,0,10000,1,4,1,,1,2,10,,,,,,,,,,,,,,,,,110000.0,,1,20000.0,5,,10,1,80000.0,,,1,100.0,,10000.0 diff --git a/spec/fixtures/files/sales_logs_csv_export_codes_24.csv b/spec/fixtures/files/sales_logs_csv_export_codes_24.csv index cdce0a509..a66f03826 100644 --- a/spec/fixtures/files/sales_logs_csv_export_codes_24.csv +++ b/spec/fixtures/files/sales_logs_csv_export_codes_24.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,noint,privacynotice,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,beds,proptype,builtype,pcodenk,wchair,age1,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,nationality_all_buyer2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant -,completed,,2023-12-08T00:00:00+00:00,2024-05-01T00:00:00+01:00,,2023,1,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,2,8,,,,1,1,2,1,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,2,1,1,0,1,30,X,17,17,18,,1,1,P,35,X,17,,13,,1,1,3,C,14,X,9,X,-9,X,3,R,-9,R,10,,,,,1,1,,,0,,,1,1,1,1,,3,,1,4,5,1,1,0,10000,1,0,10000,1,4,1,,1,2,10,,,,,,,,,,,,,,,,,110000.0,,1,20000.0,5,,10,1,80000.0,,,1,100.0,,10000.0 +id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,noint,privacynotice,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,beds,proptype,builtype,pcodenk,wchair,age1,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,nationality_all_buyer2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant +,completed,,2023-12-08T00:00:00+00:00,2024-05-01T00:00:00+01:00,,2023,1,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,2,8,,,,1,1,2,1,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,2,1,1,0,1,30,X,17,17,18,,1,1,P,35,X,17,,13,,1,1,3,C,14,X,9,X,-9,X,3,R,-9,R,10,,,,,1,1,,,0,,,1,1,1,1,,3,,1,4,5,1,1,0,10000,1,0,10000,1,4,1,,1,2,10,,,,,,,,,,,,,,,,,110000.0,,1,20000.0,5,,10,1,80000.0,,,1,100.0,,10000.0 diff --git a/spec/fixtures/files/sales_logs_csv_export_labels_23.csv b/spec/fixtures/files/sales_logs_csv_export_labels_23.csv index e36609268..44c484d83 100644 --- a/spec/fixtures/files/sales_logs_csv_export_labels_23.csv +++ b/spec/fixtures/files/sales_logs_csv_export_labels_23.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationality_all_buyer2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant -,completed,,2023-12-08T00:00:00+00:00,2024-01-01T00:00:00+00:00,,2023,single log,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,2,Flat or maisonette,Purpose built,0,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,Yes,Yes,1,30,Non-binary,Buyer prefers not to say,17,,United Kingdom,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,Buyer prefers not to say,,,Buyer prefers not to say,Full-time - 30 hours or more,Yes,3,Child,14,Non-binary,Child under 16,Other,Not known,Non-binary,"In government training into work, such as New Deal",Prefers not to say,Not known,Prefers not to say,Prefers not to say,,,,,Local authority tenant,No,,,No,,,1,1,1,1,,Don't know,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,No,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0 +id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationality_all_buyer2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant +,completed,,2023-12-08T00:00:00+00:00,2024-01-01T00:00:00+00:00,,2023,single log,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,2,Flat or maisonette,Purpose built,0,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,Yes,Yes,1,30,Non-binary,Buyer prefers not to say,17,,United Kingdom,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,Buyer prefers not to say,,,Buyer prefers not to say,Full-time - 30 hours or more,Yes,3,Child,14,Non-binary,Child under 16,Other,Not known,Non-binary,"In government training into work, such as New Deal",Prefers not to say,Not known,Prefers not to say,Prefers not to say,,,,,Local authority tenant,No,,,No,,,1,1,1,1,,Don't know,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,No,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0 diff --git a/spec/fixtures/files/sales_logs_csv_export_labels_24.csv b/spec/fixtures/files/sales_logs_csv_export_labels_24.csv index 3c97c4d5f..508b40dac 100644 --- a/spec/fixtures/files/sales_logs_csv_export_labels_24.csv +++ b/spec/fixtures/files/sales_logs_csv_export_labels_24.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,noint,privacynotice,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,beds,proptype,builtype,pcodenk,wchair,age1,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,nationality_all_buyer2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant -,completed,,2023-12-08T00:00:00+00:00,2024-05-01T00:00:00+01:00,,2023,single log,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,Yes,1,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,2,Flat or maisonette,Purpose built,0,Yes,30,Non-binary,Buyer prefers not to say,17,United Kingdom,,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,Buyer prefers not to say,,Buyer prefers not to say,,Full-time - 30 hours or more,Yes,3,Child,14,Non-binary,Child under 16,Other,Not known,Non-binary,"In government training into work, such as New Deal",Prefers not to say,Not known,Prefers not to say,Prefers not to say,,,,,Local authority tenant,No,,,No,,,1,1,1,1,,Don't know,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,No,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0 +id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,noint,privacynotice,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,beds,proptype,builtype,pcodenk,wchair,age1,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,nationality_all_buyer2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant +,completed,,2023-12-08T00:00:00+00:00,2024-05-01T00:00:00+01:00,,2023,single log,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,Yes,1,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,2,Flat or maisonette,Purpose built,0,Yes,30,Non-binary,Buyer prefers not to say,17,United Kingdom,,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,Buyer prefers not to say,,Buyer prefers not to say,,Full-time - 30 hours or more,Yes,3,Child,14,Non-binary,Child under 16,Other,Not known,Non-binary,"In government training into work, such as New Deal",Prefers not to say,Not known,Prefers not to say,Prefers not to say,,,,,Local authority tenant,No,,,No,,,1,1,1,1,,Don't know,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,No,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0 diff --git a/spec/models/form/lettings/pages/address_fallback_spec.rb b/spec/models/form/lettings/pages/address_fallback_spec.rb new file mode 100644 index 000000000..d0b13ca5c --- /dev/null +++ b/spec/models/form/lettings/pages/address_fallback_spec.rb @@ -0,0 +1,40 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Pages::AddressFallback, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date: Time.zone.local(2024, 4, 1))) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[address_line1 address_line2 town_or_city county postcode_full]) + end + + it "has the correct id" do + expect(page.id).to eq("address") + end + + it "has the correct header" do + expect(page.header).to eq("Q12 - What is the property's address?") + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([ + { "is_supported_housing?" => false, "uprn_known" => nil, "uprn_selection" => "uprn_not_listed" }, + { "is_supported_housing?" => false, "uprn_known" => 0, "uprn_selection" => "uprn_not_listed" }, + { "is_supported_housing?" => false, "uprn_confirmed" => 0, "uprn_selection" => "uprn_not_listed" }, + { "is_supported_housing?" => false, "uprn_known" => nil, "address_options_present?" => false }, + { "is_supported_housing?" => false, "uprn_known" => 0, "address_options_present?" => false }, + { "is_supported_housing?" => false, "uprn_confirmed" => 0, "address_options_present?" => false }, + ]) + end +end diff --git a/spec/models/form/lettings/pages/address_matcher_spec.rb b/spec/models/form/lettings/pages/address_matcher_spec.rb new file mode 100644 index 000000000..284e18825 --- /dev/null +++ b/spec/models/form/lettings/pages/address_matcher_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Pages::AddressMatcher, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[address_line1_input postcode_full_input]) + end + + it "has the correct id" do + expect(page.id).to eq("address_matcher") + end + + it "has the correct header" do + expect(page.header).to eq("Find an address") + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "is_supported_housing?" => false, "uprn_known" => nil }, { "is_supported_housing?" => false, "uprn_known" => 0 }, { "is_supported_housing?" => false, "uprn_confirmed" => 0 }]) + end +end diff --git a/spec/models/form/lettings/pages/no_address_found_spec.rb b/spec/models/form/lettings/pages/no_address_found_spec.rb new file mode 100644 index 000000000..34ef22b2a --- /dev/null +++ b/spec/models/form/lettings/pages/no_address_found_spec.rb @@ -0,0 +1,46 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Pages::NoAddressFound, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + let(:log) { create(:lettings_log) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[address_search_value_check]) + end + + it "has the correct id" do + expect(page.id).to eq("no_address_found") + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "address_options_present?" => false }]) + end + + it "is interruption screen page" do + expect(page.interruption_screen?).to eq(true) + end + + it "has the correct title_text" do + expect(page.title_text).to eq({ "arguments" => [], "translation" => "soft_validations.no_address_found.title_text" }) + end + + it "has the correct informative_text" do + expect(page.informative_text).to eq({ "arguments" => [], "translation" => "soft_validations.no_address_found.informative_text" }) + end + + it "has the correct interruption_screen_question_ids" do + expect(page.interruption_screen_question_ids).to eq(%w[address_line1_input]) + end +end diff --git a/spec/models/form/lettings/pages/uprn_selection_spec.rb b/spec/models/form/lettings/pages/uprn_selection_spec.rb new file mode 100644 index 000000000..f9ca20894 --- /dev/null +++ b/spec/models/form/lettings/pages/uprn_selection_spec.rb @@ -0,0 +1,44 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Pages::UprnSelection, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + let(:log) { create(:lettings_log) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[uprn_selection]) + end + + it "has the correct id" do + expect(page.id).to eq("uprn_selection") + end + + it "has the correct header" do + expect(page.header).to eq("We found some addresses that might be this property") + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has the correct skip text" do + "Search for address again" + end + + it "has the correct skip_href" do + expect(page.skip_href(log)).to eq( + "/lettings-logs/#{log.id}/address-matcher", + ) + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "address_options_present?" => true }]) + end +end diff --git a/spec/models/form/lettings/pages/uprn_spec.rb b/spec/models/form/lettings/pages/uprn_spec.rb index 1e7b9b7b4..7d5921444 100644 --- a/spec/models/form/lettings/pages/uprn_spec.rb +++ b/spec/models/form/lettings/pages/uprn_spec.rb @@ -5,7 +5,13 @@ RSpec.describe Form::Lettings::Pages::Uprn, type: :model do let(:page_id) { nil } let(:page_definition) { nil } - let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date: Time.zone.local(2024, 4, 1))) } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form, start_date: Time.zone.local(2023, 4, 1)) } + + before do + allow(form).to receive(:start_year_after_2024?).and_return(false) + allow(subsection).to receive(:form).and_return(form) + end it "has correct subsection" do expect(page.subsection).to eq(subsection) @@ -31,10 +37,6 @@ RSpec.describe Form::Lettings::Pages::Uprn, type: :model do expect(page.depends_on).to eq([{ "is_supported_housing?" => false }]) end - it "has correct skip_text" do - expect(page.skip_text).to eq("Enter address instead") - end - describe "has correct skip_href" do context "when log is nil" do it "is nil" do @@ -45,10 +47,32 @@ RSpec.describe Form::Lettings::Pages::Uprn, type: :model do context "when log is present" do let(:log) { create(:lettings_log) } - it "points to address page" do - expect(page.skip_href(log)).to eq( - "/lettings-logs/#{log.id}/address", - ) + context "with 2023/24 form" do + it "points to address page" do + expect(page.skip_href(log)).to eq( + "/lettings-logs/#{log.id}/address", + ) + end + + it "has correct skip_text" do + expect(page.skip_text).to eq("Enter address instead") + end + end + + context "with 2024/25 form" do + before do + allow(form).to receive(:start_year_after_2024?).and_return(true) + end + + it "points to address search page" do + expect(page.skip_href(log)).to eq( + "/lettings-logs/#{log.id}/address-matcher", + ) + end + + it "has correct skip_text" do + expect(page.skip_text).to eq("Search for address instead") + end end end end diff --git a/spec/models/form/lettings/questions/address_line1_for_address_matcher_spec.rb b/spec/models/form/lettings/questions/address_line1_for_address_matcher_spec.rb new file mode 100644 index 000000000..7c0baa66e --- /dev/null +++ b/spec/models/form/lettings/questions/address_line1_for_address_matcher_spec.rb @@ -0,0 +1,62 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Questions::AddressLine1ForAddressMatcher, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:log) { create(:lettings_log, :in_progress, address_line1_input: "Address line 1", postcode_full_input: "AA1 1AA") } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("address_line1_input") + end + + it "has the correct header" do + expect(question.header).to eq("Address line 1") + end + + it "has the correct error label" do + expect(question.error_label).to eq("Address line 1") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Find address") + end + + it "has the correct question_number" do + expect(question.question_number).to eq(nil) + end + + it "has the correct type" do + expect(question.type).to eq("text") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + end + + it "has the correct answer label" do + expect(question.answer_label(log)).to eq("Address line 1\nAA1 1AA") + end + + it "has the correct inferred check answers value" do + expect(question.inferred_check_answers_value).to be_nil + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to be_nil + end + + it "has the correct disable_clearing_if_not_routed_or_dynamic_answer_options value" do + expect(question.disable_clearing_if_not_routed_or_dynamic_answer_options).to eq(true) + end +end diff --git a/spec/models/form/lettings/questions/no_address_found_spec.rb b/spec/models/form/lettings/questions/no_address_found_spec.rb new file mode 100644 index 000000000..259f0bec1 --- /dev/null +++ b/spec/models/form/lettings/questions/no_address_found_spec.rb @@ -0,0 +1,44 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Questions::NoAddressFound, type: :model do + subject(:question) { described_class.new(nil, question_definition, page) } + + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("address_search_value_check") + end + + it "has the correct header" do + expect(question.header).to eq("No address found") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to be_nil + end + + it "has the correct type" do + expect(question.type).to eq("interruption_screen") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + end + + it "has the correct answer_options" do + expect(question.answer_options).to be_nil + end + + it "has the correct hidden_in_check_answers" do + expect(question.hidden_in_check_answers).to eq(true) + end +end diff --git a/spec/models/form/lettings/questions/postcode_for_address_matcher_spec.rb b/spec/models/form/lettings/questions/postcode_for_address_matcher_spec.rb new file mode 100644 index 000000000..e213e0fc4 --- /dev/null +++ b/spec/models/form/lettings/questions/postcode_for_address_matcher_spec.rb @@ -0,0 +1,62 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Questions::PostcodeForAddressMatcher, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:log) { create(:lettings_log, :in_progress, address_line1_input: "Address line 1", postcode_full_input: "AA1 1AA") } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("postcode_full_input") + end + + it "has the correct header" do + expect(question.header).to eq("Postcode") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq(nil) + end + + it "has the correct question_number" do + expect(question.question_number).to eq(nil) + end + + it "has the correct type" do + expect(question.type).to eq("text") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + end + + it "has the correct answer label" do + expect(question.answer_label(log)).to eq("AA1 1AA") + end + + it "has the correct inferred check answers value" do + expect(question.inferred_check_answers_value).to be_nil + end + + it "has the correct inferred_answers value" do + expect(question.inferred_answers).to be_nil + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to be_nil + end + + it "has the correct disable_clearing_if_not_routed_or_dynamic_answer_options value" do + expect(question.disable_clearing_if_not_routed_or_dynamic_answer_options).to eq(true) + end +end diff --git a/spec/models/form/lettings/questions/uprn_selection_spec.rb b/spec/models/form/lettings/questions/uprn_selection_spec.rb new file mode 100644 index 000000000..de009a8c9 --- /dev/null +++ b/spec/models/form/lettings/questions/uprn_selection_spec.rb @@ -0,0 +1,102 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Questions::UprnSelection, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:log) { create(:lettings_log, :in_progress, address_line1_input: "Address line 1", postcode_full_input: "AA1 1AA") } + let(:address_client_instance) { AddressClient.new(log.address_string) } + + before do + allow(AddressClient).to receive(:new).and_return(address_client_instance) + allow(address_client_instance).to receive(:call) + allow(address_client_instance).to receive(:result).and_return([{ + "UPRN" => "UPRN", + "UDPRN" => "UDPRN", + "ADDRESS" => "full address", + "SUB_BUILDING_NAME" => "0", + "BUILDING_NAME" => "building name", + "THOROUGHFARE_NAME" => "thoroughfare", + "POST_TOWN" => "posttown", + "POSTCODE" => "postcode", + }]) + end + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("uprn_selection") + end + + it "has the correct header" do + expect(question.header).to eq("Select the correct address") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Select the correct address") + end + + it "has the correct question_number" do + expect(question.question_number).to eq(nil) + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + end + + it "has the correct answer options" do + stub_request(:get, /api\.os\.uk/) + .to_return(status: 200, body: "", headers: {}) + + expect(question.answer_options(log)).to eq({ "uprn_not_listed" => { "value" => "The address is not listed, I want to enter the address manually" }, "UPRN" => { "value" => "full address" }, "divider" => { "value" => true } }) + end + + it "has the correct displayed answer options" do + stub_request(:get, /api\.os\.uk/) + .to_return(status: 200, body: "", headers: {}) + + expect(question.displayed_answer_options(log)).to eq({ "uprn_not_listed" => { "value" => "The address is not listed, I want to enter the address manually" }, "UPRN" => { "value" => "full address" }, "divider" => { "value" => true } }) + end + + it "has the correct inferred check answers value" do + expect(question.inferred_check_answers_value).to be_nil + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to be_nil + end + + context "when the log has address options" do + it "has the correct hidden_in_check_answers?" do + stub_request(:get, /api\.os\.uk/) + .to_return(status: 200, body: '{"results": {"0": "address_0", "1": "address_1", "2": "address_2"}}', headers: {}) + + expect(question.hidden_in_check_answers?(log)).to eq(false) + end + end + + context "when the log does not have address options" do + before do + allow(address_client_instance).to receive(:result).and_return(nil) + end + + it "has the correct hidden_in_check_answers?" do + stub_request(:get, /api\.os\.uk/) + .to_return(status: 200, body: "", headers: {}) + + expect(question.hidden_in_check_answers?(log)).to eq(true) + end + end +end diff --git a/spec/models/form/lettings/subsections/property_information_spec.rb b/spec/models/form/lettings/subsections/property_information_spec.rb index 0471db588..7d406d1a7 100644 --- a/spec/models/form/lettings/subsections/property_information_spec.rb +++ b/spec/models/form/lettings/subsections/property_information_spec.rb @@ -10,7 +10,7 @@ RSpec.describe Form::Lettings::Subsections::PropertyInformation, type: :model do end describe "pages" do - let(:section) { instance_double(Form::Sales::Sections::Household, form:) } + let(:section) { instance_double(Form::Lettings::Sections::Household, form:) } let(:form) { instance_double(Form, start_date:) } before do @@ -91,6 +91,9 @@ RSpec.describe Form::Lettings::Subsections::PropertyInformation, type: :model do %w[ uprn uprn_confirmation + address_matcher + no_address_found + uprn_selection address property_local_authority local_authority_min_rent_value_check diff --git a/spec/models/form/sales/pages/address_fallback_spec.rb b/spec/models/form/sales/pages/address_fallback_spec.rb new file mode 100644 index 000000000..395ac1a1b --- /dev/null +++ b/spec/models/form/sales/pages/address_fallback_spec.rb @@ -0,0 +1,40 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::AddressFallback, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date: Time.zone.local(2024, 4, 1))) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[address_line1 address_line2 town_or_city county postcode_full]) + end + + it "has the correct id" do + expect(page.id).to eq("address") + end + + it "has the correct header" do + expect(page.header).to eq("Q12 - What is the property's address?") + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([ + { "uprn_known" => nil, "uprn_selection" => "uprn_not_listed" }, + { "uprn_known" => 0, "uprn_selection" => "uprn_not_listed" }, + { "uprn_confirmed" => 0, "uprn_selection" => "uprn_not_listed" }, + { "uprn_known" => nil, "address_options_present?" => false }, + { "uprn_known" => 0, "address_options_present?" => false }, + { "uprn_confirmed" => 0, "address_options_present?" => false }, + ]) + end +end diff --git a/spec/models/form/sales/pages/address_matcher_spec.rb b/spec/models/form/sales/pages/address_matcher_spec.rb new file mode 100644 index 000000000..bcbfed6c5 --- /dev/null +++ b/spec/models/form/sales/pages/address_matcher_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::AddressMatcher, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[address_line1_input postcode_full_input]) + end + + it "has the correct id" do + expect(page.id).to eq("address_matcher") + end + + it "has the correct header" do + expect(page.header).to eq("Find an address") + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "uprn_known" => nil }, { "uprn_known" => 0 }, { "uprn_confirmed" => 0 }]) + end +end diff --git a/spec/models/form/sales/pages/no_address_found_spec.rb b/spec/models/form/sales/pages/no_address_found_spec.rb new file mode 100644 index 000000000..e275892bf --- /dev/null +++ b/spec/models/form/sales/pages/no_address_found_spec.rb @@ -0,0 +1,46 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::NoAddressFound, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + let(:log) { create(:sales_log) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[address_search_value_check]) + end + + it "has the correct id" do + expect(page.id).to eq("no_address_found") + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "address_options_present?" => false }]) + end + + it "is interruption screen page" do + expect(page.interruption_screen?).to eq(true) + end + + it "has the correct title_text" do + expect(page.title_text).to eq({ "arguments" => [], "translation" => "soft_validations.no_address_found.title_text" }) + end + + it "has the correct informative_text" do + expect(page.informative_text).to eq({ "arguments" => [], "translation" => "soft_validations.no_address_found.informative_text" }) + end + + it "has the correct interruption_screen_question_ids" do + expect(page.interruption_screen_question_ids).to eq(%w[address_line1_input]) + end +end diff --git a/spec/models/form/sales/pages/uprn_selection_spec.rb b/spec/models/form/sales/pages/uprn_selection_spec.rb new file mode 100644 index 000000000..28c904c58 --- /dev/null +++ b/spec/models/form/sales/pages/uprn_selection_spec.rb @@ -0,0 +1,44 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::UprnSelection, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + let(:log) { create(:sales_log) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[uprn_selection]) + end + + it "has the correct id" do + expect(page.id).to eq("uprn_selection") + end + + it "has the correct header" do + expect(page.header).to eq("We found some addresses that might be this property") + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has the correct skip text" do + "Search for address again" + end + + it "has the correct skip_href" do + expect(page.skip_href(log)).to eq( + "/sales-logs/#{log.id}/address-matcher", + ) + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "address_options_present?" => true }]) + end +end diff --git a/spec/models/form/sales/pages/uprn_spec.rb b/spec/models/form/sales/pages/uprn_spec.rb index 48b06a048..092f2dfef 100644 --- a/spec/models/form/sales/pages/uprn_spec.rb +++ b/spec/models/form/sales/pages/uprn_spec.rb @@ -5,7 +5,13 @@ RSpec.describe Form::Sales::Pages::Uprn, type: :model do let(:page_id) { nil } let(:page_definition) { nil } - let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date: Time.zone.local(2023, 4, 1))) } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form, start_date: Time.zone.local(2023, 4, 1)) } + + before do + allow(form).to receive(:start_year_after_2024?).and_return(false) + allow(subsection).to receive(:form).and_return(form) + end it "has correct subsection" do expect(page.subsection).to eq(subsection) @@ -31,10 +37,6 @@ RSpec.describe Form::Sales::Pages::Uprn, type: :model do expect(page.depends_on).to be_nil end - it "has correct skip_text" do - expect(page.skip_text).to eq("Enter address instead") - end - describe "has correct skip_href" do context "when log is nil" do it "is nil" do @@ -45,10 +47,32 @@ RSpec.describe Form::Sales::Pages::Uprn, type: :model do context "when log is present" do let(:log) { create(:sales_log) } - it "points to address page" do - expect(page.skip_href(log)).to eq( - "/sales-logs/#{log.id}/address", - ) + context "with 2023/24 form" do + it "points to address page" do + expect(page.skip_href(log)).to eq( + "/sales-logs/#{log.id}/address", + ) + end + + it "has correct skip_text" do + expect(page.skip_text).to eq("Enter address instead") + end + end + + context "with 2024/25 form" do + before do + allow(form).to receive(:start_year_after_2024?).and_return(true) + end + + it "points to address search page" do + expect(page.skip_href(log)).to eq( + "/sales-logs/#{log.id}/address-matcher", + ) + end + + it "has correct skip_text" do + expect(page.skip_text).to eq("Search for address instead") + end end end end diff --git a/spec/models/form/sales/questions/address_line1_for_address_matcher_spec.rb b/spec/models/form/sales/questions/address_line1_for_address_matcher_spec.rb new file mode 100644 index 000000000..61bd183f0 --- /dev/null +++ b/spec/models/form/sales/questions/address_line1_for_address_matcher_spec.rb @@ -0,0 +1,62 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::AddressLine1ForAddressMatcher, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:log) { create(:sales_log, :in_progress, address_line1_input: "Address line 1", postcode_full_input: "AA1 1AA") } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("address_line1_input") + end + + it "has the correct header" do + expect(question.header).to eq("Address line 1") + end + + it "has the correct error label" do + expect(question.error_label).to eq("Address line 1") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Find address") + end + + it "has the correct question_number" do + expect(question.question_number).to eq(nil) + end + + it "has the correct type" do + expect(question.type).to eq("text") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + end + + it "has the correct answer label" do + expect(question.answer_label(log)).to eq("Address line 1\nAA1 1AA") + end + + it "has the correct inferred check answers value" do + expect(question.inferred_check_answers_value).to be_nil + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to be_nil + end + + it "has the correct disable_clearing_if_not_routed_or_dynamic_answer_options value" do + expect(question.disable_clearing_if_not_routed_or_dynamic_answer_options).to eq(true) + end +end diff --git a/spec/models/form/sales/questions/no_address_found_spec.rb b/spec/models/form/sales/questions/no_address_found_spec.rb new file mode 100644 index 000000000..97881b2d7 --- /dev/null +++ b/spec/models/form/sales/questions/no_address_found_spec.rb @@ -0,0 +1,44 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::NoAddressFound, type: :model do + subject(:question) { described_class.new(nil, question_definition, page) } + + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("address_search_value_check") + end + + it "has the correct header" do + expect(question.header).to eq("No address found") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to be_nil + end + + it "has the correct type" do + expect(question.type).to eq("interruption_screen") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + end + + it "has the correct answer_options" do + expect(question.answer_options).to be_nil + end + + it "has the correct hidden_in_check_answers" do + expect(question.hidden_in_check_answers).to eq(true) + end +end diff --git a/spec/models/form/sales/questions/postcode_for_address_matcher_spec.rb b/spec/models/form/sales/questions/postcode_for_address_matcher_spec.rb new file mode 100644 index 000000000..64a04be1b --- /dev/null +++ b/spec/models/form/sales/questions/postcode_for_address_matcher_spec.rb @@ -0,0 +1,62 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::PostcodeForAddressMatcher, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:log) { create(:sales_log, :in_progress, address_line1_input: "Address line 1", postcode_full_input: "AA1 1AA") } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("postcode_full_input") + end + + it "has the correct header" do + expect(question.header).to eq("Postcode") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq(nil) + end + + it "has the correct question_number" do + expect(question.question_number).to eq(nil) + end + + it "has the correct type" do + expect(question.type).to eq("text") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + end + + it "has the correct answer label" do + expect(question.answer_label(log)).to eq("AA1 1AA") + end + + it "has the correct inferred check answers value" do + expect(question.inferred_check_answers_value).to be_nil + end + + it "has the correct inferred_answers value" do + expect(question.inferred_answers).to be_nil + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to be_nil + end + + it "has the correct disable_clearing_if_not_routed_or_dynamic_answer_options value" do + expect(question.disable_clearing_if_not_routed_or_dynamic_answer_options).to eq(true) + end +end diff --git a/spec/models/form/sales/questions/uprn_selection_spec.rb b/spec/models/form/sales/questions/uprn_selection_spec.rb new file mode 100644 index 000000000..1b9aaba39 --- /dev/null +++ b/spec/models/form/sales/questions/uprn_selection_spec.rb @@ -0,0 +1,102 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::UprnSelection, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:log) { create(:sales_log, :in_progress, address_line1_input: "Address line 1", postcode_full_input: "AA1 1AA") } + let(:address_client_instance) { AddressClient.new(log.address_string) } + + before do + allow(AddressClient).to receive(:new).and_return(address_client_instance) + allow(address_client_instance).to receive(:call) + allow(address_client_instance).to receive(:result).and_return([{ + "UPRN" => "UPRN", + "UDPRN" => "UDPRN", + "ADDRESS" => "full address", + "SUB_BUILDING_NAME" => "0", + "BUILDING_NAME" => "building name", + "THOROUGHFARE_NAME" => "thoroughfare", + "POST_TOWN" => "posttown", + "POSTCODE" => "postcode", + }]) + end + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("uprn_selection") + end + + it "has the correct header" do + expect(question.header).to eq("Select the correct address") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Select the correct address") + end + + it "has the correct question_number" do + expect(question.question_number).to eq(nil) + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + end + + it "has the correct answer options" do + stub_request(:get, /api\.os\.uk/) + .to_return(status: 200, body: "", headers: {}) + + expect(question.answer_options(log)).to eq({ "uprn_not_listed" => { "value" => "The address is not listed, I want to enter the address manually" }, "UPRN" => { "value" => "full address" }, "divider" => { "value" => true } }) + end + + it "has the correct displayed answer options" do + stub_request(:get, /api\.os\.uk/) + .to_return(status: 200, body: "", headers: {}) + + expect(question.displayed_answer_options(log)).to eq({ "uprn_not_listed" => { "value" => "The address is not listed, I want to enter the address manually" }, "UPRN" => { "value" => "full address" }, "divider" => { "value" => true } }) + end + + it "has the correct inferred check answers value" do + expect(question.inferred_check_answers_value).to be_nil + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to be_nil + end + + context "when the log has address options" do + it "has the correct hidden_in_check_answers?" do + stub_request(:get, /api\.os\.uk/) + .to_return(status: 200, body: '{"results": {"0": "address_0", "1": "address_1", "2": "address_2"}}', headers: {}) + + expect(question.hidden_in_check_answers?(log)).to eq(false) + end + end + + context "when the log does not have address options" do + before do + allow(address_client_instance).to receive(:result).and_return(nil) + end + + it "has the correct hidden_in_check_answers?" do + stub_request(:get, /api\.os\.uk/) + .to_return(status: 200, body: "", headers: {}) + + expect(question.hidden_in_check_answers?(log)).to eq(true) + end + end +end diff --git a/spec/models/form/sales/subsections/property_information_spec.rb b/spec/models/form/sales/subsections/property_information_spec.rb index 8d3dce93d..e0bf51e11 100644 --- a/spec/models/form/sales/subsections/property_information_spec.rb +++ b/spec/models/form/sales/subsections/property_information_spec.rb @@ -1,10 +1,8 @@ require "rails_helper" RSpec.describe Form::Sales::Subsections::PropertyInformation, type: :model do - subject(:property_information) { described_class.new(subsection_id, subsection_definition, section) } + subject(:property_information) { described_class.new(nil, nil, section) } - let(:subsection_id) { nil } - let(:subsection_definition) { nil } let(:section) { instance_double(Form::Sales::Sections::PropertyInformation) } it "has correct section" do @@ -12,7 +10,12 @@ RSpec.describe Form::Sales::Subsections::PropertyInformation, type: :model do end describe "pages" do - let(:section) { instance_double(Form::Sales::Sections::Household, form: instance_double(Form, start_date:)) } + let(:section) { instance_double(Form::Sales::Sections::Household, form:) } + let(:form) { instance_double(Form, start_date:) } + + before do + allow(form).to receive(:start_year_after_2024?).and_return(false) + end context "when 2022" do let(:start_date) { Time.utc(2022, 2, 8) } @@ -67,11 +70,18 @@ RSpec.describe Form::Sales::Subsections::PropertyInformation, type: :model do context "when 2024" do let(:start_date) { Time.utc(2024, 2, 8) } + before do + allow(form).to receive(:start_year_after_2024?).and_return(true) + end + it "has correct pages" do expect(property_information.pages.map(&:id)).to eq( %w[ uprn uprn_confirmation + address_matcher + no_address_found + uprn_selection address property_local_authority local_authority_buyer_1_income_max_value_check diff --git a/spec/services/address_client_spec.rb b/spec/services/address_client_spec.rb new file mode 100644 index 000000000..0a222f0c7 --- /dev/null +++ b/spec/services/address_client_spec.rb @@ -0,0 +1,68 @@ +require "rails_helper" + +describe AddressClient do + let(:client) { described_class.new("123") } + + let(:valid_response) do + { results: [{ DPA: { UPRN: "12345" } }] }.to_json + end + + def stub_api_request(body:, status: 200) + stub_request(:get, "https://api.os.uk/search/places/v1/find?key=OS_DATA_KEY&maxresults=10&minmatch=0.4&query=123") + .to_return(status:, body:, headers: {}) + end + + describe "call" do + context "when json parse error" do + before do + stub_api_request(body: "{", status: 200) + + client.call + end + + it "returns error" do + expect(client.error).to eq("Address is not recognised. Check the address, or enter the UPRN") + end + end + + context "when http error" do + before do + stub_api_request(body: valid_response, status: 500) + + client.call + end + + it "returns error" do + expect(client.error).to eq("Address is not recognised. Check the address, or enter the UPRN") + end + end + + context "when results empty" do + before do + stub_api_request(body: {}.to_json) + + client.call + end + + it "returns error" do + expect(client.error).to eq("Address is not recognised. Check the address, or enter the UPRN") + end + end + + context "with results" do + before do + stub_api_request(body: valid_response) + + client.call + end + + it "returns result" do + expect(client.result).to eq([{ "UPRN" => "12345" }]) + end + + it "returns no error" do + expect(client.error).to be_nil + end + end + end +end diff --git a/spec/services/address_data_presenter_spec.rb b/spec/services/address_data_presenter_spec.rb new file mode 100644 index 000000000..d347b74ec --- /dev/null +++ b/spec/services/address_data_presenter_spec.rb @@ -0,0 +1,51 @@ +require "rails_helper" + +describe AddressDataPresenter do + let(:data) do + JSON.parse( + '{ + "UPRN": "UPRN", + "UDPRN": "UDPRN", + "ADDRESS": "full address", + "SUB_BUILDING_NAME": "0", + "BUILDING_NAME": "building name", + "THOROUGHFARE_NAME": "thoroughfare", + "POST_TOWN": "posttown", + "POSTCODE": "postcode", + "STATUS": "APPROVED", + "DOUBLE_DEPENDENT_LOCALITY": "double dependent locality", + "DEPENDENT_LOCALITY": "dependent locality", + "CLASSIFICATION_CODE": "classification code", + "LOCAL_CUSTODIAN_CODE_DESCRIPTION": "LONDON BOROUGH OF HARINGEY", + "BLPU_STATE_CODE": "2", + "BLPU_STATE_CODE_DESCRIPTION": "In use", + "LAST_UPDATE_DATE": "31/07/2020", + "ENTRY_DATE": "30/01/2015", + "BLPU_STATE_DATE": "30/01/2015", + "LANGUAGE": "EN", + "MATCH_DESCRIPTION": "EXACT", + "MATCH": "1.0" + }', + ) + end + + let(:presenter) { described_class.new(data) } + + describe "#uprn" do + it "returns uprn" do + expect(presenter.uprn).to eq("UPRN") + end + end + + describe "#match" do + it "returns match" do + expect(presenter.match).to eq("1.0") + end + end + + describe "#address" do + it "returns address" do + expect(presenter.address).to eq("full address") + end + end +end diff --git a/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb b/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb index 145610889..cd398dabd 100644 --- a/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb +++ b/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb @@ -87,6 +87,24 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do stub_request(:get, /api\.postcodes\.io/) .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: {}) + + 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": "SE2 6RT" + + }}]}', headers: {}) + parser.valid? end @@ -773,12 +791,11 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do describe "#validate_nulls" do context "when non-setup questions are null" do - let(:attributes) { setup_section_params.merge({ field_16: "", field_17: "", field_19: "" }) } + let(:attributes) { setup_section_params.merge({ field_43: "" }) } it "fetches the question's check_answer_label if it exists, otherwise it gets the question's header" do parser.valid? - expect(parser.errors[:field_17]).to eql(["You must answer address line 1"]) - expect(parser.errors[:field_19]).to eql(["You must answer town or city"]) + expect(parser.errors[:field_43]).to eql(["You must answer lead tenant’s gender identity"]) end end end @@ -1444,7 +1461,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do let(:attributes) { setup_section_params.merge({ field_16: "1234567890123" }) } it "adds an appropriate error" do - expect(parser.errors[:field_16]).to eql(["UPRN is not recognised. Check the number, or enter the address"]) + expect(parser.errors[:field_16]).to eql(["UPRN must be 12 digits or less"]) end end diff --git a/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb b/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb index 58d6b2849..ce81300b5 100644 --- a/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb +++ b/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb @@ -50,6 +50,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do field_20: "1", field_21: "1", field_22: "12", + field_23: "Address line 1", field_27: "CR0", field_28: "4BB", field_29: "E09000008", @@ -242,6 +243,9 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do stub_request(:get, /api\.postcodes\.io/) .to_return(status: 200, body: "{\"status\":200,\"result\":{\"admin_district\":\"Manchester\", \"codes\":{\"admin_district\": \"E08000003\"}}}", headers: {}) + stub_request(:get, /api\.os\.uk/) + .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: {}) + parser.valid? end diff --git a/spec/shared/shared_log_examples.rb b/spec/shared/shared_log_examples.rb index 354a8b1ee..ef9ba32e6 100644 --- a/spec/shared/shared_log_examples.rb +++ b/spec/shared/shared_log_examples.rb @@ -103,6 +103,84 @@ RSpec.shared_examples "shared log examples" do |log_type| allow_any_instance_of(UprnClient).to receive(:error).and_return(error_message) expect { log.process_uprn_change! }.to change { log.errors[:uprn] }.from([]).to([error_message]) + .and change { log.errors[:uprn_selection] }.from([]).to([error_message]) + end + end + end + + describe "#process_address_change!" do + context "when address_line1_input and postcode_full_input set to a value" do + let(:log) do + log = build( + log_type, + uprn_selection: "UPRN", + address_line1: "Address line 1", + postcode_full: "AA1 1AA", + county: "county", + ) + log.save!(validate: false) + log + end + + it "updates log fields" do + log.address_line1_input = "New address line 1" + log.postcode_full_input = "BB2 2BB" + + allow_any_instance_of(AddressClient).to receive(:call) + allow_any_instance_of(AddressClient).to receive(:result).and_return([{ + "UPRN" => "UPRN", + "UDPRN" => "UDPRN", + "ADDRESS" => "full address", + "SUB_BUILDING_NAME" => "0", + "BUILDING_NAME" => "building name", + "THOROUGHFARE_NAME" => "thoroughfare", + "POST_TOWN" => "posttown", + "POSTCODE" => "postcode", + }]) + + allow_any_instance_of(UprnClient).to receive(:call) + allow_any_instance_of(UprnClient).to receive(:result).and_return({ + "UPRN" => "UPRN", + "UDPRN" => "UDPRN", + "ADDRESS" => "full address", + "SUB_BUILDING_NAME" => "0", + "BUILDING_NAME" => "building name", + "THOROUGHFARE_NAME" => "thoroughfare", + "POST_TOWN" => "posttown", + "POSTCODE" => "postcode", + }) + + expect { log.process_address_change! }.to change(log, :address_line1).from("Address line 1").to("0, Building Name, Thoroughfare") + .and change(log, :town_or_city).from(nil).to("Posttown") + .and change(log, :postcode_full).from("AA1 1AA").to("POSTCODE") + .and change(log, :uprn_confirmed).from(nil).to(1) + .and change(log, :uprn).from(nil).to("UPRN") + .and change(log, :uprn_known).from(nil).to(1) + .and change(log, :uprn_selection).from("UPRN").to(nil) + .and change(log, :county).from("county").to(nil) + end + end + + context "when address inputs are nil" do + let(:log) { create(log_type, uprn_selection: nil, address_line1_input: nil, postcode_full_input: nil) } + + it "does not update log" do + expect { log.process_address_change! }.not_to change(log, :attributes) + end + end + + context "when service errors" do + let(:log) { build(log_type, :in_progress, uprn_selection: "UPRN", address_line1_input: "123", postcode_full_input: "AA1 1AA") } + let(:error_message) { "error" } + + it "adds error to log" do + allow_any_instance_of(AddressClient).to receive(:call) + allow_any_instance_of(AddressClient).to receive(:error).and_return(error_message) + allow_any_instance_of(UprnClient).to receive(:call) + allow_any_instance_of(UprnClient).to receive(:error).and_return(error_message) + + expect { log.process_address_change! }.to change { log.errors[:uprn_selection] }.from([]).to([error_message]) + .and change { log.errors[:uprn_selection] }.from([]).to([error_message]) end end end