From 8acfc5f38e39644a7ac0cbb0c220621db3059f51 Mon Sep 17 00:00:00 2001 From: Jack S Date: Wed, 15 Mar 2023 11:07:18 +0000 Subject: [PATCH] UPRN questions and flows --- app/helpers/question_view_helper.rb | 6 +- .../derived_variables/sales_log_variables.rb | 9 +++ app/models/form/page.rb | 6 +- app/models/form/question.rb | 5 +- app/models/form/sales/pages/address.rb | 21 ++++++ app/models/form/sales/pages/uprn.rb | 26 +++++++ .../form/sales/pages/uprn_confirmation.rb | 17 +++++ app/models/form/sales/pages/uprn_known.rb | 12 ++++ .../form/sales/questions/address_line1.rb | 35 ++++++++++ .../form/sales/questions/address_line2.rb | 13 ++++ app/models/form/sales/questions/county.rb | 13 ++++ .../questions/postcode_for_full_address.rb | 25 +++++++ .../form/sales/questions/town_or_city.rb | 13 ++++ app/models/form/sales/questions/uprn.rb | 34 ++++++++++ .../form/sales/questions/uprn_confirmation.rb | 34 ++++++++++ app/models/form/sales/questions/uprn_known.rb | 21 ++++++ .../sales/subsections/property_information.rb | 27 +++++++- app/models/log.rb | 18 +++++ app/models/sales_log.rb | 5 ++ .../form/_check_answers_summary_list.html.erb | 15 ++-- .../form/_numeric_output_question.html.erb | 2 +- app/views/form/_radio_question.html.erb | 9 +++ app/views/form/page.html.erb | 5 +- config/locales/en.yml | 4 ++ spec/features/lettings_log_spec.rb | 21 +++--- .../fixtures/files/lettings_logs_download.csv | 4 +- .../lettings_logs_download_codes_only.csv | 4 +- .../lettings_logs_download_non_support.csv | 4 +- spec/helpers/question_view_helper_spec.rb | 5 ++ spec/models/form/sales/pages/address_spec.rb | 37 ++++++++++ .../sales/pages/uprn_confirmation_spec.rb | 37 ++++++++++ .../form/sales/pages/uprn_known_spec.rb | 33 +++++++++ spec/models/form/sales/pages/uprn_spec.rb | 45 ++++++++++++ .../sales/questions/address_line1_spec.rb | 45 ++++++++++++ .../sales/questions/address_line2_spec.rb | 49 +++++++++++++ .../form/sales/questions/county_spec.rb | 49 +++++++++++++ .../postcode_for_full_address_spec.rb | 62 +++++++++++++++++ .../form/sales/questions/town_or_city_spec.rb | 49 +++++++++++++ .../sales/questions/uprn_confirmation_spec.rb | 68 +++++++++++++++++++ .../form/sales/questions/uprn_known_spec.rb | 59 ++++++++++++++++ spec/models/form/sales/questions/uprn_spec.rb | 65 ++++++++++++++++++ .../subsections/property_information_spec.rb | 59 ++++++++++++---- spec/models/sales_log_spec.rb | 51 +++++++++++++- .../csv/lettings_log_csv_service_spec.rb | 9 +++ 44 files changed, 1086 insertions(+), 44 deletions(-) create mode 100644 app/models/form/sales/pages/address.rb create mode 100644 app/models/form/sales/pages/uprn.rb create mode 100644 app/models/form/sales/pages/uprn_confirmation.rb create mode 100644 app/models/form/sales/pages/uprn_known.rb create mode 100644 app/models/form/sales/questions/address_line1.rb create mode 100644 app/models/form/sales/questions/address_line2.rb create mode 100644 app/models/form/sales/questions/county.rb create mode 100644 app/models/form/sales/questions/postcode_for_full_address.rb create mode 100644 app/models/form/sales/questions/town_or_city.rb create mode 100644 app/models/form/sales/questions/uprn.rb create mode 100644 app/models/form/sales/questions/uprn_confirmation.rb create mode 100644 app/models/form/sales/questions/uprn_known.rb create mode 100644 spec/models/form/sales/pages/address_spec.rb create mode 100644 spec/models/form/sales/pages/uprn_confirmation_spec.rb create mode 100644 spec/models/form/sales/pages/uprn_known_spec.rb create mode 100644 spec/models/form/sales/pages/uprn_spec.rb create mode 100644 spec/models/form/sales/questions/address_line1_spec.rb create mode 100644 spec/models/form/sales/questions/address_line2_spec.rb create mode 100644 spec/models/form/sales/questions/county_spec.rb create mode 100644 spec/models/form/sales/questions/postcode_for_full_address_spec.rb create mode 100644 spec/models/form/sales/questions/town_or_city_spec.rb create mode 100644 spec/models/form/sales/questions/uprn_confirmation_spec.rb create mode 100644 spec/models/form/sales/questions/uprn_known_spec.rb create mode 100644 spec/models/form/sales/questions/uprn_spec.rb diff --git a/app/helpers/question_view_helper.rb b/app/helpers/question_view_helper.rb index d40b3cd35..3ff84bc19 100644 --- a/app/helpers/question_view_helper.rb +++ b/app/helpers/question_view_helper.rb @@ -8,14 +8,16 @@ module QuestionViewHelper def legend(question, page_header, conditional) { text: [question.question_number_string(conditional:), question.header.html_safe].compact.join(" - "), - size: label_size(page_header, conditional), + size: label_size(page_header, conditional, question), tag: label_tag(page_header, conditional), } end private - def label_size(page_header, conditional) + def label_size(page_header, conditional, question) + return if question.plain_label.present? + page_header.blank? && !conditional ? "l" : "m" end diff --git a/app/models/derived_variables/sales_log_variables.rb b/app/models/derived_variables/sales_log_variables.rb index 525c12936..56d687f59 100644 --- a/app/models/derived_variables/sales_log_variables.rb +++ b/app/models/derived_variables/sales_log_variables.rb @@ -23,6 +23,15 @@ module DerivedVariables::SalesLogVariables self.totadult = total_adult + total_elder self.hhmemb = number_of_household_members self.hhtype = household_type + + if uprn_known&.zero? + self.uprn = nil + end + + if uprn_confirmed&.zero? + self.uprn = nil + self.uprn_known = 0 + end end private diff --git a/app/models/form/page.rb b/app/models/form/page.rb index ea57bac66..2ac5a716a 100644 --- a/app/models/form/page.rb +++ b/app/models/form/page.rb @@ -1,6 +1,7 @@ class Form::Page attr_accessor :id, :header, :header_partial, :description, :questions, :depends_on, :title_text, - :informative_text, :subsection, :hide_subsection_label, :next_unresolved_page_id + :informative_text, :subsection, :hide_subsection_label, :next_unresolved_page_id, + :skip_text def initialize(id, hsh, subsection) @id = id @@ -15,6 +16,7 @@ class Form::Page @informative_text = hsh["informative_text"] @hide_subsection_label = hsh["hide_subsection_label"] @next_unresolved_page_id = hsh["next_unresolved_page_id"] + @skip_text = hsh["skip_text"] end end @@ -36,6 +38,8 @@ class Form::Page questions.all? { |question| question.type == "interruption_screen" } end + def skip_href(log = nil); end + private def conditional_question_ids diff --git a/app/models/form/question.rb b/app/models/form/question.rb index 9ddacd68b..de77674e6 100644 --- a/app/models/form/question.rb +++ b/app/models/form/question.rb @@ -4,7 +4,7 @@ class Form::Question :conditional_for, :readonly, :answer_options, :page, :check_answer_label, :inferred_answers, :hidden_in_check_answers, :inferred_check_answers_value, :guidance_partial, :prefix, :suffix, :requires_js, :fields_added, :derived, - :check_answers_card_number, :unresolved_hint_text, :question_number + :check_answers_card_number, :unresolved_hint_text, :question_number, :plain_label module GuidancePosition TOP = 1 @@ -41,6 +41,7 @@ class Form::Question @check_answers_card_number = hsh["check_answers_card_number"] || 0 @unresolved_hint_text = hsh["unresolved_hint_text"] @question_number = hsh["question_number"] + @plain_label = hsh["plain_label"] end end @@ -57,6 +58,8 @@ class Form::Question inferred_answer_value(log) || answer_label end + def notification_banner(_log = nil); end + def get_inferred_answers(log) return [] unless inferred_answers diff --git a/app/models/form/sales/pages/address.rb b/app/models/form/sales/pages/address.rb new file mode 100644 index 000000000..dc66ca3fc --- /dev/null +++ b/app/models/form/sales/pages/address.rb @@ -0,0 +1,21 @@ +class Form::Sales::Pages::Address < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "address" + @header = "What is the property's address?" + 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 + + def routed_to?(log, _current_user) + log.uprn_confirmed != 1 || log.uprn_known&.zero? + end +end diff --git a/app/models/form/sales/pages/uprn.rb b/app/models/form/sales/pages/uprn.rb new file mode 100644 index 000000000..38b9a724c --- /dev/null +++ b/app/models/form/sales/pages/uprn.rb @@ -0,0 +1,26 @@ +class Form::Sales::Pages::Uprn < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "uprn" + end + + def questions + @questions ||= [ + Form::Sales::Questions::Uprn.new(nil, nil, self), + ] + end + + def routed_to?(log, _current_user) + log.uprn_known == 1 + end + + def skip_text + "Enter address instead" + end + + def skip_href(log = nil) + return unless log + + "/#{log.model_name.param_key.dasherize}s/#{log.id}/address" + end +end diff --git a/app/models/form/sales/pages/uprn_confirmation.rb b/app/models/form/sales/pages/uprn_confirmation.rb new file mode 100644 index 000000000..b78590d0d --- /dev/null +++ b/app/models/form/sales/pages/uprn_confirmation.rb @@ -0,0 +1,17 @@ +class Form::Sales::Pages::UprnConfirmation < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "uprn_confirmation" + @header = "We found an address that might be this property" + end + + def questions + @questions ||= [ + Form::Sales::Questions::UprnConfirmation.new(nil, nil, self), + ] + end + + def routed_to?(log, _current_user) + log.uprn.present? && log.uprn_known == 1 + end +end diff --git a/app/models/form/sales/pages/uprn_known.rb b/app/models/form/sales/pages/uprn_known.rb new file mode 100644 index 000000000..e2cbfe63f --- /dev/null +++ b/app/models/form/sales/pages/uprn_known.rb @@ -0,0 +1,12 @@ +class Form::Sales::Pages::UprnKnown < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "uprn_known" + end + + def questions + @questions ||= [ + Form::Sales::Questions::UprnKnown.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/questions/address_line1.rb b/app/models/form/sales/questions/address_line1.rb new file mode 100644 index 000000000..18b4f388f --- /dev/null +++ b/app/models/form/sales/questions/address_line1.rb @@ -0,0 +1,35 @@ +class Form::Sales::Questions::AddressLine1 < ::Form::Question + def initialize(id, hsh, page) + super + @id = "address_line1" + @check_answer_label = "Address" + @header = "Address line 1" + @type = "text" + @plain_label = true + end + + def hidden_in_check_answers?(log, _current_user = nil) + return true if log.uprn_known.nil? + return false if log.uprn_known&.zero? + return true if log.uprn_confirmed.nil? && log.uprn.present? + return true if log.uprn_known == 1 && log.uprn.blank? + + log.uprn_confirmed == 1 + end + + def answer_label(log, _current_user = nil) + [ + log.address_line1, + log.address_line2, + log.postcode_full, + log.town_or_city, + log.county, + ].select(&:present?).join("\n") + end + + def get_extra_check_answer_value(log) + la = LocalAuthority.find_by(code: log.la)&.name + + la.presence + end +end diff --git a/app/models/form/sales/questions/address_line2.rb b/app/models/form/sales/questions/address_line2.rb new file mode 100644 index 000000000..0b4ff661c --- /dev/null +++ b/app/models/form/sales/questions/address_line2.rb @@ -0,0 +1,13 @@ +class Form::Sales::Questions::AddressLine2 < ::Form::Question + def initialize(id, hsh, page) + super + @id = "address_line2" + @header = "Address line 2 (optional)" + @type = "text" + @plain_label = true + end + + def hidden_in_check_answers?(_log = nil, _current_user = nil) + true + end +end diff --git a/app/models/form/sales/questions/county.rb b/app/models/form/sales/questions/county.rb new file mode 100644 index 000000000..080ac809f --- /dev/null +++ b/app/models/form/sales/questions/county.rb @@ -0,0 +1,13 @@ +class Form::Sales::Questions::County < ::Form::Question + def initialize(id, hsh, page) + super + @id = "county" + @header = "County (optional)" + @type = "text" + @plain_label = true + end + + def hidden_in_check_answers?(_log = nil, _current_user = nil) + true + end +end diff --git a/app/models/form/sales/questions/postcode_for_full_address.rb b/app/models/form/sales/questions/postcode_for_full_address.rb new file mode 100644 index 000000000..a1e6f8633 --- /dev/null +++ b/app/models/form/sales/questions/postcode_for_full_address.rb @@ -0,0 +1,25 @@ +class Form::Sales::Questions::PostcodeForFullAddress < ::Form::Question + def initialize(id, hsh, page) + super + @id = "postcode_full" + @header = "Postcode" + @type = "text" + @width = 5 + @inferred_check_answers_value = [{ + "condition" => { + "pcodenk" => 1, + }, + "value" => "Not known", + }] + @inferred_answers = { + "la" => { + "is_la_inferred" => true, + }, + } + @plain_label = true + end + + def hidden_in_check_answers?(_log = nil, _current_user = nil) + true + end +end diff --git a/app/models/form/sales/questions/town_or_city.rb b/app/models/form/sales/questions/town_or_city.rb new file mode 100644 index 000000000..9dde3aeb8 --- /dev/null +++ b/app/models/form/sales/questions/town_or_city.rb @@ -0,0 +1,13 @@ +class Form::Sales::Questions::TownOrCity < ::Form::Question + def initialize(id, hsh, page) + super + @id = "town_or_city" + @header = "Town or city" + @type = "text" + @plain_label = true + end + + def hidden_in_check_answers?(_log = nil, _current_user = nil) + true + end +end diff --git a/app/models/form/sales/questions/uprn.rb b/app/models/form/sales/questions/uprn.rb new file mode 100644 index 000000000..ef003bf0c --- /dev/null +++ b/app/models/form/sales/questions/uprn.rb @@ -0,0 +1,34 @@ +class Form::Sales::Questions::Uprn < ::Form::Question + def initialize(id, hsh, page) + super + @id = "uprn" + @check_answer_label = "UPRN" + @header = "What is the property's UPRN" + @type = "text" + @hint_text = "The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355." + @width = 10 + end + + def unanswered_error_message + I18n.t("validations.property.uprn.invalid") + end + + def get_extra_check_answer_value(log) + value = [ + log.address_line1, + log.address_line2, + log.town_or_city, + log.county, + log.postcode_full, + (LocalAuthority.find_by(code: log.uprn)&.name if log.uprn.present?), + ].select(&:present?) + + return unless value.any? + + "\n\n#{value.join("\n")}" + end + + def hidden_in_check_answers?(log, _current_user = nil) + log.uprn_known != 1 + end +end diff --git a/app/models/form/sales/questions/uprn_confirmation.rb b/app/models/form/sales/questions/uprn_confirmation.rb new file mode 100644 index 000000000..38ad9c938 --- /dev/null +++ b/app/models/form/sales/questions/uprn_confirmation.rb @@ -0,0 +1,34 @@ +class Form::Sales::Questions::UprnConfirmation < ::Form::Question + def initialize(id, hsh, page) + super + @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 notification_banner(log = nil) + return unless log&.uprn + + { + title: "UPRN: #{log.uprn}", + heading: [ + log.address_line1, + log.address_line2, + log.postcode_full, + log.town_or_city, + log.county, + ].select(&:present?).join("\n"), + } + end + + def hidden_in_check_answers?(log, _current_user = nil) + log.uprn_known != 1 || log.uprn_confirmed.present? + end +end diff --git a/app/models/form/sales/questions/uprn_known.rb b/app/models/form/sales/questions/uprn_known.rb new file mode 100644 index 000000000..45a944e4e --- /dev/null +++ b/app/models/form/sales/questions/uprn_known.rb @@ -0,0 +1,21 @@ +class Form::Sales::Questions::UprnKnown < ::Form::Question + def initialize(id, hsh, page) + super + @id = "uprn_known" + @check_answer_label = "UPRN known?" + @header = "Do you know the sale UPRN?" + @type = "radio" + @answer_options = ANSWER_OPTIONS + @hint_text = "The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355.

+ You can continue without the UPRN, but it means we will need you to enter the address of the property." + end + + ANSWER_OPTIONS = { + "1" => { "value" => "Yes" }, + "0" => { "value" => "No" }, + }.freeze + + def unanswered_error_message + I18n.t("validations.property.uprn_known.invalid") + end +end diff --git a/app/models/form/sales/subsections/property_information.rb b/app/models/form/sales/subsections/property_information.rb index a43607d7c..cca34a764 100644 --- a/app/models/form/sales/subsections/property_information.rb +++ b/app/models/form/sales/subsections/property_information.rb @@ -8,15 +8,36 @@ class Form::Sales::Subsections::PropertyInformation < ::Form::Subsection def pages @pages ||= [ + uprn_questions, Form::Sales::Pages::PropertyNumberOfBedrooms.new(nil, nil, self), Form::Sales::Pages::AboutPriceValueCheck.new("about_price_bedrooms_value_check", nil, self), Form::Sales::Pages::PropertyUnitType.new(nil, nil, self), Form::Sales::Pages::MonthlyChargesValueCheck.new("monthly_charges_property_type_value_check", nil, self), Form::Sales::Pages::PropertyBuildingType.new(nil, nil, self), - Form::Sales::Pages::Postcode.new(nil, nil, self), - Form::Sales::Pages::PropertyLocalAuthority.new(nil, nil, self), + postcode_and_la_questions, Form::Sales::Pages::AboutPriceValueCheck.new("about_price_la_value_check", nil, self), Form::Sales::Pages::PropertyWheelchairAccessible.new(nil, nil, self), - ] + ].flatten.compact + end + + def uprn_questions + if form.start_date.year >= 2023 + [ + Form::Sales::Pages::UprnKnown.new(nil, nil, self), + 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), + ] + end + end + + def postcode_and_la_questions + if form.start_date.year < 2023 + [ + Form::Sales::Pages::Postcode.new(nil, nil, self), + Form::Sales::Pages::PropertyLocalAuthority.new(nil, nil, self), + ] + end end end diff --git a/app/models/log.rb b/app/models/log.rb index 0cb974d31..256db3612 100644 --- a/app/models/log.rb +++ b/app/models/log.rb @@ -31,6 +31,24 @@ class Log < ApplicationRecord } scope :created_by, ->(user) { where(created_by: user) } + def process_uprn_change! + if uprn.present? + service = UprnClient.new(uprn) + service.call + + return errors.add(:uprn, service.error) if service.error.present? + + presenter = UprnDataPresenter.new(service.result) + + self.uprn_confirmed = nil + self.address_line1 = presenter.address_line1 + self.address_line2 = presenter.address_line2 + self.town_or_city = presenter.town_or_city + self.postcode_full = presenter.postcode + process_postcode_changes! + 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 de1e1e2ba..c7fe68bca 100644 --- a/app/models/sales_log.rb +++ b/app/models/sales_log.rb @@ -31,6 +31,7 @@ class SalesLog < Log before_validation :reset_location_fields!, unless: :postcode_known? before_validation :reset_previous_location_fields!, unless: :previous_postcode_known? before_validation :set_derived_fields! + after_validation :process_uprn_change!, if: :should_process_uprn_change? scope :filter_by_year, ->(year) { where(saledate: Time.zone.local(year.to_i, 4, 1)...Time.zone.local(year.to_i + 1, 4, 1)) } scope :filter_by_purchaser_code, ->(purchid) { where("purchid ILIKE ?", "%#{purchid}%") } @@ -311,4 +312,8 @@ class SalesLog < Log field_value = public_send(field_name) format_as_currency(field_value) end + + def should_process_uprn_change? + uprn_changed? && saledate && saledate.year >= 2023 + end end diff --git a/app/views/form/_check_answers_summary_list.html.erb b/app/views/form/_check_answers_summary_list.html.erb index bb9b1e56b..71fe9cd97 100644 --- a/app/views/form/_check_answers_summary_list.html.erb +++ b/app/views/form/_check_answers_summary_list.html.erb @@ -3,12 +3,19 @@ <% summary_list.row do |row| %> <% row.key { get_question_label(question) } %> <% row.value do %> - <%= get_answer_label(question, @log) %> + <%= simple_format( + get_answer_label(question, @log), + wrapper_tag: "span", + class: "govuk-!-margin-right-4", + ) %> <% extra_value = question.get_extra_check_answer_value(@log) %> - <% if extra_value %> - <%= extra_value %> + <% if extra_value && question.answer_label(lettings_log, current_user).present? %> + <%= simple_format( + extra_value, + wrapper_tag: "span", + class: "govuk-!-font-weight-regular app-!-colour-muted", + ) %> <% end %> -
<% question.get_inferred_answers(@log).each do |inferred_answer| %> <%= inferred_answer %> <% end %> diff --git a/app/views/form/_numeric_output_question.html.erb b/app/views/form/_numeric_output_question.html.erb index b96e7b53d..8892523aa 100644 --- a/app/views/form/_numeric_output_question.html.erb +++ b/app/views/form/_numeric_output_question.html.erb @@ -1,7 +1,7 @@ <%= render partial: "form/guidance/#{question.guidance_partial}" if question.top_guidance? %>
-