From 0e62cc517eaf7fb8c1f5dde146de863ce7e2a195 Mon Sep 17 00:00:00 2001 From: Rachael Booth Date: Fri, 9 Feb 2024 16:41:03 +0000 Subject: [PATCH] CLDC-3227: Add soft validation for reason other when it's likely a standard category --- .../lettings/pages/reasonother_value_check.rb | 22 +++++ .../questions/reasonother_value_check.rb | 13 +++ .../subsections/household_situation.rb | 1 + app/models/validations/soft_validations.rb | 34 ++++++++ config/locales/en.yml | 2 + ...easonother_value_check_to_lettings_logs.rb | 5 ++ db/schema.rb | 27 +++--- .../subsections/household_situation_spec.rb | 87 ++++++++++++++----- .../validations/soft_validations_spec.rb | 32 +++++++ 9 files changed, 188 insertions(+), 35 deletions(-) create mode 100644 app/models/form/lettings/pages/reasonother_value_check.rb create mode 100644 app/models/form/lettings/questions/reasonother_value_check.rb create mode 100644 db/migrate/20240209153215_add_reasonother_value_check_to_lettings_logs.rb diff --git a/app/models/form/lettings/pages/reasonother_value_check.rb b/app/models/form/lettings/pages/reasonother_value_check.rb new file mode 100644 index 000000000..e4af8a1f1 --- /dev/null +++ b/app/models/form/lettings/pages/reasonother_value_check.rb @@ -0,0 +1,22 @@ +class Form::Lettings::Pages::ReasonotherValueCheck < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "reasonother_value_check" + @depends_on = [{ "reasonother_might_be_existing_category?" => true }] + @title_text = { + "translation" => "soft_validations.reasonother.title_text", + "arguments" => [{ "key" => "reasonother", "i18n_template" => "reasonother" }], + } + @informative_text = "The reason you have entered looks very similar to one of the existing response categories. + Please check the categories and select the appropriate one. + If the existing categories are not suitable, please confirm here to move onto the next question." + end + + def questions + @questions ||= [Form::Lettings::Questions::ReasonotherValueCheck.new(nil, nil, self)] + end + + def interruption_screen_question_ids + %w[reason reasonother] + end +end diff --git a/app/models/form/lettings/questions/reasonother_value_check.rb b/app/models/form/lettings/questions/reasonother_value_check.rb new file mode 100644 index 000000000..d1ee23b64 --- /dev/null +++ b/app/models/form/lettings/questions/reasonother_value_check.rb @@ -0,0 +1,13 @@ +class Form::Lettings::Questions::ReasonotherValueCheck < ::Form::Question + def initialize(id, hsh, page) + super + @id = "reasonother_value_check" + @check_answer_label = "Reason other confirmation" + @header = "Are you sure this doesn’t fit an existing category?" + @type = "interruption_screen" + @answer_options = ANSWER_OPTIONS + @hidden_in_check_answers = { "depends_on" => [{ "reasonother_value_check" => 0 }, { "reasonother_value_check" => 1 }] } + end + + ANSWER_OPTIONS = { "0" => { "value" => "Yes" }, "1" => { "value" => "No" } }.freeze +end diff --git a/app/models/form/lettings/subsections/household_situation.rb b/app/models/form/lettings/subsections/household_situation.rb index 9db7c1f04..6646d7230 100644 --- a/app/models/form/lettings/subsections/household_situation.rb +++ b/app/models/form/lettings/subsections/household_situation.rb @@ -12,6 +12,7 @@ class Form::Lettings::Subsections::HouseholdSituation < ::Form::Subsection Form::Lettings::Pages::TimeOnWaitingList.new(nil, nil, self), Form::Lettings::Pages::ReasonForLeavingLastSettledHome.new(nil, nil, self), Form::Lettings::Pages::ReasonForLeavingLastSettledHomeRenewal.new(nil, nil, self), + (Form::Lettings::Pages::ReasonotherValueCheck.new(nil, nil, self) if form.start_year_after_2024?), Form::Lettings::Pages::PreviousHousingSituation.new(nil, nil, self), Form::Lettings::Pages::PreviousHousingSituationRenewal.new(nil, nil, self), Form::Lettings::Pages::Homelessness.new("homelessness", nil, self), diff --git a/app/models/validations/soft_validations.rb b/app/models/validations/soft_validations.rb index 92685afe0..ccac2700b 100644 --- a/app/models/validations/soft_validations.rb +++ b/app/models/validations/soft_validations.rb @@ -133,6 +133,40 @@ module Validations::SoftValidations weekly_value(supcharg) > max end + PHRASES_LIKELY_TO_INDICATE_EXISTING_REASON_CATEGORY = [ + "Decant", + "Decanted", + "Refugee", + "Asylum", + "Ukraine", + "Ukrainian", + "Army", + "Military", + "Domestic Abuse", + "Domestic Violence", + "DA", + "DV", + "Relationship breakdown", + "Overcrowding", + "Overcrowded", + "Too small", + "More space", + "Bigger property", + "Damp", + "Mould", + "Fire", + "Repossession", + "Death", + "Deceased", + "Passed away", + "Prison", + "Hospital", + ].freeze + + def reasonother_might_be_existing_category? + Regexp.union(PHRASES_LIKELY_TO_INDICATE_EXISTING_REASON_CATEGORY.map { |phrase| Regexp.new("\\b#{phrase}\\b", Regexp::IGNORECASE) }).match?(reasonother) + end + private def details_known_or_lead_tenant?(tenant_number) diff --git a/config/locales/en.yml b/config/locales/en.yml index 204a20b4e..6f0e6d642 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -731,6 +731,8 @@ Make sure these answers are correct." deposit_and_mortgage: title_text: "You told us the mortgage amount was %{mortgage}, the cash deposit was %{deposit} and the discount was %{discount}." hint_text: "We would expect the mortgage amount and the deposit added together to be the same as the purchase price minus the discount." + reasonother: + title_text: "You told us that the tenant’s main reason for leaving their last settled home was %{reasonother}" devise: email: diff --git a/db/migrate/20240209153215_add_reasonother_value_check_to_lettings_logs.rb b/db/migrate/20240209153215_add_reasonother_value_check_to_lettings_logs.rb new file mode 100644 index 000000000..54486b3ae --- /dev/null +++ b/db/migrate/20240209153215_add_reasonother_value_check_to_lettings_logs.rb @@ -0,0 +1,5 @@ +class AddReasonotherValueCheckToLettingsLogs < ActiveRecord::Migration[7.0] + def change + add_column :lettings_logs, :reasonother_value_check, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index e6f2de905..2402013ad 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_01_30_084707) do +ActiveRecord::Schema[7.0].define(version: 2024_02_09_153215) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -192,14 +192,14 @@ ActiveRecord::Schema[7.0].define(version: 2024_01_30_084707) do t.integer "hb" t.integer "hbrentshortfall" t.integer "property_relet" - t.datetime "mrcdate" + t.datetime "mrcdate", precision: nil t.integer "incref" - t.datetime "startdate" + t.datetime "startdate", precision: nil t.integer "armedforces" t.integer "first_time_property_let_as_social_housing" t.integer "unitletas" t.integer "builtype" - t.datetime "voiddate" + t.datetime "voiddate", precision: nil t.bigint "owning_organisation_id" t.bigint "managing_organisation_id" t.integer "renttype" @@ -305,6 +305,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_01_30_084707) do t.integer "duplicate_set_id" t.integer "nationality_all" t.integer "nationality_all_group" + t.integer "reasonother_value_check" 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" @@ -355,7 +356,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_01_30_084707) do t.string "old_id" t.string "old_visible_id" t.string "mobility_type" - t.datetime "startdate" + t.datetime "startdate", precision: nil t.string "location_admin_district" t.boolean "confirmed" t.boolean "is_la_inferred" @@ -555,7 +556,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_01_30_084707) do t.integer "stairbought" t.integer "stairowned" t.decimal "mrent", precision: 10, scale: 2 - t.datetime "exdate" + t.datetime "exdate", precision: nil t.integer "exday" t.integer "exmonth" t.integer "exyear" @@ -591,7 +592,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_01_30_084707) do t.integer "wchair" t.integer "income2_value_check" t.integer "armedforcesspouse" - t.datetime "hodate" + t.datetime "hodate", precision: nil t.integer "hoday" t.integer "homonth" t.integer "hoyear" @@ -709,8 +710,8 @@ ActiveRecord::Schema[7.0].define(version: 2024_01_30_084707) do t.string "name" t.bigint "organisation_id" t.integer "sign_in_count", default: 0, null: false - t.datetime "current_sign_in_at" - t.datetime "last_sign_in_at" + t.datetime "current_sign_in_at", precision: nil + t.datetime "last_sign_in_at", precision: nil t.string "current_sign_in_ip" t.string "last_sign_in_ip" t.integer "role" @@ -718,7 +719,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_01_30_084707) do t.string "phone" t.integer "failed_attempts", default: 0 t.string "unlock_token" - t.datetime "locked_at" + t.datetime "locked_at", precision: nil t.boolean "is_dpo", default: false t.boolean "is_key_contact", default: false t.integer "second_factor_attempts_count", default: 0 @@ -726,12 +727,12 @@ ActiveRecord::Schema[7.0].define(version: 2024_01_30_084707) do t.string "encrypted_otp_secret_key_iv" t.string "encrypted_otp_secret_key_salt" t.string "direct_otp" - t.datetime "direct_otp_sent_at" + t.datetime "direct_otp_sent_at", precision: nil t.datetime "totp_timestamp", precision: nil t.boolean "active", default: true t.string "confirmation_token" - t.datetime "confirmed_at" - t.datetime "confirmation_sent_at" + t.datetime "confirmed_at", precision: nil + t.datetime "confirmation_sent_at", precision: nil t.string "unconfirmed_email" t.boolean "initial_confirmation_sent" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true diff --git a/spec/models/form/lettings/subsections/household_situation_spec.rb b/spec/models/form/lettings/subsections/household_situation_spec.rb index 803f873f8..640536522 100644 --- a/spec/models/form/lettings/subsections/household_situation_spec.rb +++ b/spec/models/form/lettings/subsections/household_situation_spec.rb @@ -6,35 +6,78 @@ RSpec.describe Form::Lettings::Subsections::HouseholdSituation, type: :model do let(:subsection_id) { nil } let(:subsection_definition) { nil } let(:section) { instance_double(Form::Lettings::Sections::Household) } + let(:form) { instance_double(Form) } + + before do + allow(section).to receive(:form).and_return(form) + end it "has correct section" do expect(household_situation.section).to eq(section) end - it "has correct pages" do - expect(household_situation.pages.map(&:id)).to eq( - %w[ - time_lived_in_local_authority - time_on_waiting_list - reason_for_leaving_last_settled_home - reason_for_leaving_last_settled_home_renewal - previous_housing_situation - previous_housing_situation_renewal - homelessness - previous_postcode - previous_local_authority - reasonable_preference - reasonable_preference_reason - allocation_system - referral - referral_prp - referral_supported_housing - referral_supported_housing_prp - referral_value_check - ], - ) + context "with form year before 2024" do + before do + allow(form).to receive(:start_year_after_2024?).and_return(false) + end + + it "has correct pages" do + expect(household_situation.pages.map(&:id)).to eq( + %w[ + time_lived_in_local_authority + time_on_waiting_list + reason_for_leaving_last_settled_home + reason_for_leaving_last_settled_home_renewal + previous_housing_situation + previous_housing_situation_renewal + homelessness + previous_postcode + previous_local_authority + reasonable_preference + reasonable_preference_reason + allocation_system + referral + referral_prp + referral_supported_housing + referral_supported_housing_prp + referral_value_check + ], + ) + end end + context "with form year >= 2024" do + before do + allow(form).to receive(:start_year_after_2024?).and_return(true) + end + + it "has correct pages" do + expect(household_situation.pages.map(&:id)).to eq( + %w[ + time_lived_in_local_authority + time_on_waiting_list + reason_for_leaving_last_settled_home + reason_for_leaving_last_settled_home_renewal + reasonother_value_check + previous_housing_situation + previous_housing_situation_renewal + homelessness + previous_postcode + previous_local_authority + reasonable_preference + reasonable_preference_reason + allocation_system + referral + referral_prp + referral_supported_housing + referral_supported_housing_prp + referral_value_check + ], + ) + end + end + + it "has the correct id" do expect(household_situation.id).to eq("household_situation") end diff --git a/spec/models/validations/soft_validations_spec.rb b/spec/models/validations/soft_validations_spec.rb index 8f00799ff..cd3a35235 100644 --- a/spec/models/validations/soft_validations_spec.rb +++ b/spec/models/validations/soft_validations_spec.rb @@ -1017,4 +1017,36 @@ RSpec.describe Validations::SoftValidations do end end end + + describe "reasonother_might_be_existing_category?" do + it "returns true if reasonother is exactly in the 'likely existing category' list" do + record.reasonother = "Domestic Abuse" + + expect(record).to be_reasonother_might_be_existing_category + end + + it "returns true if any word of reasonother is exactly in the 'likely existing category' list" do + record.reasonother = "Was decanted from somewhere" + + expect(record).to be_reasonother_might_be_existing_category + end + + it "is not case sensitive when matching" do + record.reasonother = "domestic abuse" + + expect(record).to be_reasonother_might_be_existing_category + end + + it "returns false if no part of reasonother is in the 'likely existing category' list" do + record.reasonother = "other" + + expect(record).not_to be_reasonother_might_be_existing_category + end + + it "returns false if match to the 'likely existing category' list is only part of a word" do + record.reasonother = "wasdecanted" + + expect(record).not_to be_reasonother_might_be_existing_category + end + end end