diff --git a/app/models/form/lettings/pages/tenancy_length_periodic.rb b/app/models/form/lettings/pages/tenancy_length_periodic.rb new file mode 100644 index 000000000..9ea6553af --- /dev/null +++ b/app/models/form/lettings/pages/tenancy_length_periodic.rb @@ -0,0 +1,11 @@ +class Form::Lettings::Pages::TenancyLengthPeriodic < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "tenancy_length_periodic" + @depends_on = [{ "tenancy_type_periodic?" => true }] + end + + def questions + @questions ||= [Form::Lettings::Questions::TenancyLengthPeriodic.new(nil, nil, self)] + end +end diff --git a/app/models/form/lettings/questions/starter_tenancy_type.rb b/app/models/form/lettings/questions/starter_tenancy_type.rb index 08fc8e56d..db67bbb7f 100644 --- a/app/models/form/lettings/questions/starter_tenancy_type.rb +++ b/app/models/form/lettings/questions/starter_tenancy_type.rb @@ -2,37 +2,68 @@ class Form::Lettings::Questions::StarterTenancyType < ::Form::Question def initialize(id, hsh, page) super @id = "tenancy" - @check_answer_label = "Type of main tenancy after the starter period has ended?" - @header = "What is the type of tenancy after the starter period has ended?" + @check_answer_label = form.start_year_after_2024? ? "Type of main tenancy after the starter or introductory period has ended" : "Type of main tenancy after the starter period has ended" + @header = form.start_year_after_2024? ? "What is the type of tenancy after the starter or introductory period has ended?" : "What is the type of tenancy after the starter period has ended?" @type = "radio" @check_answers_card_number = 0 - @hint_text = "This is also known as an ‘introductory period’." - @answer_options = ANSWER_OPTIONS + @hint_text = form.start_year_after_2024? ? "" : "This is also known as an ‘introductory period’." @conditional_for = { "tenancyother" => [3] } @question_number = 27 end - ANSWER_OPTIONS = { - "4" => { - "value" => "Assured Shorthold Tenancy (AST) – Fixed term", - "hint" => "Mostly housing associations provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", - }, - "6" => { - "value" => "Secure – fixed term", - "hint" => "Mostly local authorities provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", - }, - "2" => { - "value" => "Assured – lifetime", - }, - "7" => { - "value" => "Secure – lifetime", - }, - "5" => { - "value" => "Licence agreement", - "hint" => "Licence agreements are mostly used for Supported Housing and work on a rolling basis.", - }, - "3" => { - "value" => "Other", - }, - }.freeze + def answer_options + if form.start_year_after_2024? + { + "4" => { + "value" => "Assured Shorthold Tenancy (AST) – Fixed term", + "hint" => "These are mostly provided by housing associations. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "6" => { + "value" => "Secure – fixed term", + "hint" => "These are mostly provided by local authorities. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "2" => { + "value" => "Assured – lifetime", + }, + "7" => { + "value" => "Secure – lifetime", + }, + "8" => { + "value" => "Periodic", + "hint" => "These are rolling tenancies with no fixed end date. They may have an initial fixed term and then become rolling.", + }, + "5" => { + "value" => "Licence agreement", + "hint" => "These are mostly used for Supported Housing and work on a rolling basis.", + }, + "3" => { + "value" => "Other", + }, + }.freeze + else + { + "4" => { + "value" => "Assured Shorthold Tenancy (AST) – Fixed term", + "hint" => "Mostly housing associations provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "6" => { + "value" => "Secure – fixed term", + "hint" => "Mostly local authorities provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "2" => { + "value" => "Assured – lifetime", + }, + "7" => { + "value" => "Secure – lifetime", + }, + "5" => { + "value" => "Licence agreement", + "hint" => "Licence agreements are mostly used for Supported Housing and work on a rolling basis.", + }, + "3" => { + "value" => "Other", + }, + }.freeze + end + end end diff --git a/app/models/form/lettings/questions/tenancy_length_periodic.rb b/app/models/form/lettings/questions/tenancy_length_periodic.rb new file mode 100644 index 000000000..4c0d9a51d --- /dev/null +++ b/app/models/form/lettings/questions/tenancy_length_periodic.rb @@ -0,0 +1,16 @@ +class Form::Lettings::Questions::TenancyLengthPeriodic < ::Form::Question + def initialize(id, hsh, page) + super + @id = "tenancylength" + @check_answer_label = "Length of periodic tenancy" + @header = "What is the length of the periodic tenancy to the nearest year?" + @type = "numeric" + @width = 2 + @check_answers_card_number = 0 + @max = 150 + @min = 0 + @step = 1 + @question_number = 28 + @hint_text = "As this is a periodic tenancy, this question is optional. If you do not have the information available click save and continue" + end +end diff --git a/app/models/form/lettings/questions/tenancy_type.rb b/app/models/form/lettings/questions/tenancy_type.rb index 95beffbca..6a7642123 100644 --- a/app/models/form/lettings/questions/tenancy_type.rb +++ b/app/models/form/lettings/questions/tenancy_type.rb @@ -7,32 +7,63 @@ class Form::Lettings::Questions::TenancyType < ::Form::Question @type = "radio" @check_answers_card_number = 0 @hint_text = "" - @answer_options = ANSWER_OPTIONS @conditional_for = { "tenancyother" => [3] } @question_number = 27 end - ANSWER_OPTIONS = { - "4" => { - "value" => "Assured Shorthold Tenancy (AST) – Fixed term", - "hint" => "Mostly housing associations provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", - }, - "6" => { - "value" => "Secure – fixed term", - "hint" => "Mostly local authorities provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", - }, - "2" => { - "value" => "Assured – lifetime", - }, - "7" => { - "value" => "Secure – lifetime", - }, - "5" => { - "value" => "Licence agreement", - "hint" => "Licence agreements are mostly used for Supported Housing and work on a rolling basis.", - }, - "3" => { - "value" => "Other", - }, - }.freeze + def answer_options + if form.start_year_after_2024? + { + "4" => { + "value" => "Assured Shorthold Tenancy (AST) – Fixed term", + "hint" => "These are mostly provided by housing associations. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "6" => { + "value" => "Secure – fixed term", + "hint" => "These are mostly provided by local authorities. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "2" => { + "value" => "Assured – lifetime", + }, + "7" => { + "value" => "Secure – lifetime", + }, + "8" => { + "value" => "Periodic", + "hint" => "These are rolling tenancies with no fixed end date. They may have an initial fixed term and then become rolling.", + }, + "5" => { + "value" => "Licence agreement", + "hint" => "These are mostly used for Supported Housing and work on a rolling basis.", + }, + "3" => { + "value" => "Other", + }, + }.freeze + else + { + "4" => { + "value" => "Assured Shorthold Tenancy (AST) – Fixed term", + "hint" => "Mostly housing associations provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "6" => { + "value" => "Secure – fixed term", + "hint" => "Mostly local authorities provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "2" => { + "value" => "Assured – lifetime", + }, + "7" => { + "value" => "Secure – lifetime", + }, + "5" => { + "value" => "Licence agreement", + "hint" => "Licence agreements are mostly used for Supported Housing and work on a rolling basis.", + }, + "3" => { + "value" => "Other", + }, + }.freeze + end + end end diff --git a/app/models/form/lettings/subsections/tenancy_information.rb b/app/models/form/lettings/subsections/tenancy_information.rb index f45ce3baa..5525c182f 100644 --- a/app/models/form/lettings/subsections/tenancy_information.rb +++ b/app/models/form/lettings/subsections/tenancy_information.rb @@ -15,7 +15,8 @@ class Form::Lettings::Subsections::TenancyInformation < ::Form::Subsection Form::Lettings::Pages::TenancyLength.new(nil, nil, self), Form::Lettings::Pages::TenancyLengthAffordableRent.new(nil, nil, self), Form::Lettings::Pages::TenancyLengthIntermediateRent.new(nil, nil, self), + (Form::Lettings::Pages::TenancyLengthPeriodic.new(nil, nil, self) if form.start_year_after_2024?), Form::Lettings::Pages::ShelteredAccommodation.new(nil, nil, self), - ].compact + ].flatten.compact end end diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb index cc8c7d58b..497ca5d92 100644 --- a/app/models/lettings_log.rb +++ b/app/models/lettings_log.rb @@ -286,6 +286,10 @@ class LettingsLog < Log [4, 6].include? tenancy end + def tenancy_type_periodic? + tenancy == 8 + end + def is_general_needs? # 1: General Needs needstype == 1 @@ -341,6 +345,11 @@ class LettingsLog < Log tenancy == 4 end + def is_periodic_tenancy? + # 8: Periodic + tenancy == 8 + end + def is_internal_transfer? # 1: Internal Transfer referral == 1 diff --git a/app/models/validations/tenancy_validations.rb b/app/models/validations/tenancy_validations.rb index 01281a931..26cccdd81 100644 --- a/app/models/validations/tenancy_validations.rb +++ b/app/models/validations/tenancy_validations.rb @@ -21,10 +21,17 @@ module Validations::TenancyValidations min_tenancy_length: min_tenancy_length(record), ), }, + { + condition: (record.is_periodic_tenancy? && !is_in_range) && is_present, + error: I18n.t( + "validations.tenancy.length.secure", + min_tenancy_length: min_tenancy_length(record), + ), + }, ] rent_type_independent_conditions = [ { - condition: !(record.is_secure_tenancy? || record.is_assured_shorthold_tenancy?) && is_present, + condition: !(record.is_secure_tenancy? || record.is_assured_shorthold_tenancy? || record.is_periodic_tenancy?) && is_present, error: I18n.t("validations.tenancy.length.fixed_term_not_required"), }, ] @@ -54,6 +61,6 @@ module Validations::TenancyValidations end def min_tenancy_length(record) - record.is_supported_housing? || record.renttype == 3 ? 1 : 2 + record.is_supported_housing? || record.renttype == 3 || record.is_periodic_tenancy? ? 1 : 2 end end diff --git a/spec/models/form/lettings/pages/starter_tenancy_type_spec.rb b/spec/models/form/lettings/pages/starter_tenancy_type_spec.rb index 795dee561..2c5208fd1 100644 --- a/spec/models/form/lettings/pages/starter_tenancy_type_spec.rb +++ b/spec/models/form/lettings/pages/starter_tenancy_type_spec.rb @@ -4,6 +4,12 @@ RSpec.describe Form::Lettings::Pages::StarterTenancyType, type: :model do subject(:page) { described_class.new(nil, nil, subsection) } let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form) } + + 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) diff --git a/spec/models/form/lettings/pages/tenancy_length_periodic_spec.rb b/spec/models/form/lettings/pages/tenancy_length_periodic_spec.rb new file mode 100644 index 000000000..19134110f --- /dev/null +++ b/spec/models/form/lettings/pages/tenancy_length_periodic_spec.rb @@ -0,0 +1,31 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Pages::TenancyLengthPeriodic, type: :model do + subject(:page) { described_class.new(nil, nil, subsection) } + + 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[tenancylength] + end + + it "has the correct id" do + expect(page.id).to eq "tenancy_length_periodic" + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has the correct depends_on" do + expect(page.depends_on).to eq [{ "tenancy_type_periodic?" => true }] + end +end diff --git a/spec/models/form/lettings/questions/starter_tenancy_type_spec.rb b/spec/models/form/lettings/questions/starter_tenancy_type_spec.rb new file mode 100644 index 000000000..3993e1b87 --- /dev/null +++ b/spec/models/form/lettings/questions/starter_tenancy_type_spec.rb @@ -0,0 +1,112 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Questions::StarterTenancyType, 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(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form) } + + before do + allow(page).to receive(:subsection).and_return(subsection) + allow(subsection).to receive(:form).and_return(form) + end + + context "with 2023/24 form" do + before do + allow(form).to receive(:start_year_after_2024?).and_return(false) + end + + it "has the correct check answer label" do + expect(question.check_answer_label).to eq("Type of main tenancy after the starter period has ended") + end + + it "has the correct hint_text" do + expect(question.hint_text).to eq("This is also known as an ‘introductory period’.") + end + + it "has the correct header" do + expect(question.header).to eq("What is the type of tenancy after the starter period has ended?") + end + + it "has the correct answer options" do + expect(question.answer_options).to eq( + { + "4" => { + "value" => "Assured Shorthold Tenancy (AST) – Fixed term", + "hint" => "Mostly housing associations provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "6" => { + "value" => "Secure – fixed term", + "hint" => "Mostly local authorities provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "2" => { + "value" => "Assured – lifetime", + }, + "7" => { + "value" => "Secure – lifetime", + }, + "5" => { + "value" => "Licence agreement", + "hint" => "Licence agreements are mostly used for Supported Housing and work on a rolling basis.", + }, + "3" => { + "value" => "Other", + }, + }, + ) + end + end + + context "with 2024/25 form" do + before do + allow(form).to receive(:start_year_after_2024?).and_return(true) + end + + it "has the correct check answer label" do + expect(question.check_answer_label).to eq("Type of main tenancy after the starter or introductory period has ended") + end + + it "has the correct updated hint_text" do + expect(question.hint_text).to eq("") + end + + it "has the correct header" do + expect(question.header).to eq("What is the type of tenancy after the starter or introductory period has ended?") + end + + it "has the correct answer options" do + expect(question.answer_options).to eq( + { + "4" => { + "value" => "Assured Shorthold Tenancy (AST) – Fixed term", + "hint" => "These are mostly provided by housing associations. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "6" => { + "value" => "Secure – fixed term", + "hint" => "These are mostly provided by local authorities. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "2" => { + "value" => "Assured – lifetime", + }, + "7" => { + "value" => "Secure – lifetime", + }, + "8" => { + "value" => "Periodic", + "hint" => "These are rolling tenancies with no fixed end date. They may have an initial fixed term and then become rolling.", + }, + "5" => { + "value" => "Licence agreement", + "hint" => "These are mostly used for Supported Housing and work on a rolling basis.", + }, + "3" => { + "value" => "Other", + }, + }, + ) + end + end +end diff --git a/spec/models/form/lettings/questions/tenancy_length_periodic_spec.rb b/spec/models/form/lettings/questions/tenancy_length_periodic_spec.rb new file mode 100644 index 000000000..7708ee9d8 --- /dev/null +++ b/spec/models/form/lettings/questions/tenancy_length_periodic_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Questions::TenancyLengthPeriodic, type: :model do + subject(:question) { described_class.new(nil, nil, page) } + + let(:question_id) { nil } + 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("tenancylength") + end + + it "has the correct header" do + expect(question.header).to eq("What is the length of the periodic tenancy to the nearest year?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Length of periodic tenancy") + end + + it "has the correct type" do + expect(question.type).to eq("numeric") + end + + it "has the correct hint_text" do + expect(question.hint_text).to eq("As this is a periodic tenancy, this question is optional. If you do not have the information available click save and continue") + end +end diff --git a/spec/models/form/lettings/questions/tenancy_type_spec.rb b/spec/models/form/lettings/questions/tenancy_type_spec.rb index 8fd8a50f0..c5ad04a03 100644 --- a/spec/models/form/lettings/questions/tenancy_type_spec.rb +++ b/spec/models/form/lettings/questions/tenancy_type_spec.rb @@ -4,6 +4,14 @@ RSpec.describe Form::Lettings::Questions::TenancyType, type: :model do subject(:question) { described_class.new(nil, nil, page) } let(:page) { instance_double(Form::Page) } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form) } + + before do + allow(form).to receive(:start_year_after_2024?).and_return(false) + allow(page).to receive(:subsection).and_return(subsection) + allow(subsection).to receive(:form).and_return(form) + end it "has correct page" do expect(question.page).to eq(page) @@ -33,30 +41,76 @@ RSpec.describe Form::Lettings::Questions::TenancyType, type: :model do expect(question.conditional_for).to eq({ "tenancyother" => [3] }) end - it "has the correct answer_options" do - expect(question.answer_options).to eq({ - "4" => { - "value" => "Assured Shorthold Tenancy (AST) – Fixed term", - "hint" => "Mostly housing associations provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", - }, - "6" => { - "value" => "Secure – fixed term", - "hint" => "Mostly local authorities provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", - }, - "2" => { - "value" => "Assured – lifetime", - }, - "7" => { - "value" => "Secure – lifetime", - }, - "5" => { - "value" => "Licence agreement", - "hint" => "Licence agreements are mostly used for Supported Housing and work on a rolling basis.", - }, - "3" => { - "value" => "Other", - }, - }) + context "with 2023/24 form" do + before do + allow(form).to receive(:start_year_after_2024?).and_return(false) + end + + it "has the correct answer options" do + expect(question.answer_options).to eq( + { + "4" => { + "value" => "Assured Shorthold Tenancy (AST) – Fixed term", + "hint" => "Mostly housing associations provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "6" => { + "value" => "Secure – fixed term", + "hint" => "Mostly local authorities provide these. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "2" => { + "value" => "Assured – lifetime", + }, + "7" => { + "value" => "Secure – lifetime", + }, + "5" => { + "value" => "Licence agreement", + "hint" => "Licence agreements are mostly used for Supported Housing and work on a rolling basis.", + }, + "3" => { + "value" => "Other", + }, + }, + ) + end + end + + context "with 2024/25 form" do + before do + allow(form).to receive(:start_year_after_2024?).and_return(true) + end + + it "has the correct answer options" do + expect(question.answer_options).to eq( + { + "4" => { + "value" => "Assured Shorthold Tenancy (AST) – Fixed term", + "hint" => "These are mostly provided by housing associations. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "6" => { + "value" => "Secure – fixed term", + "hint" => "These are mostly provided by local authorities. Fixed term tenancies are intended to be for a set amount of time up to 20 years.", + }, + "2" => { + "value" => "Assured – lifetime", + }, + "7" => { + "value" => "Secure – lifetime", + }, + "8" => { + "value" => "Periodic", + "hint" => "These are rolling tenancies with no fixed end date. They may have an initial fixed term and then become rolling.", + }, + "5" => { + "value" => "Licence agreement", + "hint" => "These are mostly used for Supported Housing and work on a rolling basis.", + }, + "3" => { + "value" => "Other", + }, + }, + ) + end end it "is not marked as derived" do diff --git a/spec/models/form/lettings/subsections/tenancy_information_spec.rb b/spec/models/form/lettings/subsections/tenancy_information_spec.rb index 45a1d28b3..96770ea78 100644 --- a/spec/models/form/lettings/subsections/tenancy_information_spec.rb +++ b/spec/models/form/lettings/subsections/tenancy_information_spec.rb @@ -11,10 +11,37 @@ RSpec.describe Form::Lettings::Subsections::TenancyInformation, type: :model do expect(tenancy_information.section).to eq(section) end - it "has correct pages" do - expect(tenancy_information.pages.map(&:id)).to eq( - %w[joint starter_tenancy tenancy_type starter_tenancy_type tenancy_length tenancy_length_affordable_rent tenancy_length_intermediate_rent sheltered_accommodation], - ) + describe "pages" do + 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 2023" do + let(:start_date) { Time.utc(2023, 2, 8) } + + it "has correct pages" do + expect(tenancy_information.pages.map(&:id)).to eq( + %w[joint starter_tenancy tenancy_type starter_tenancy_type tenancy_length tenancy_length_affordable_rent tenancy_length_intermediate_rent sheltered_accommodation], + ) + end + end + + 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(tenancy_information.pages.map(&:id)).to eq( + %w[joint starter_tenancy tenancy_type starter_tenancy_type tenancy_length tenancy_length_affordable_rent tenancy_length_intermediate_rent tenancy_length_periodic sheltered_accommodation], + ) + end + end end it "has the correct id" do diff --git a/spec/models/validations/tenancy_validations_spec.rb b/spec/models/validations/tenancy_validations_spec.rb index ca0e84334..3d39e1e39 100644 --- a/spec/models/validations/tenancy_validations_spec.rb +++ b/spec/models/validations/tenancy_validations_spec.rb @@ -232,6 +232,53 @@ RSpec.describe Validations::TenancyValidations do end end end + + context "when type of tenancy is periodic" do + let(:expected_error) do + I18n.t( + "validations.tenancy.length.secure", + min_tenancy_length: 1, + ) + end + + before { record.tenancy = 8 } + + context "when tenancy length is less than 1" do + it "adds an error" do + record.tenancylength = 0 + tenancy_validator.validate_fixed_term_tenancy(record) + expect(record.errors["needstype"]).to include(match(expected_error)) + expect(record.errors["tenancylength"]).to include(match(expected_error)) + expect(record.errors["tenancy"]).to include(match(expected_error)) + end + end + + context "when tenancy length is greater than 99" do + it "adds an error" do + record.tenancylength = 100 + tenancy_validator.validate_fixed_term_tenancy(record) + expect(record.errors["needstype"]).to include(match(expected_error)) + expect(record.errors["tenancylength"]).to include(match(expected_error)) + expect(record.errors["tenancy"]).to include(match(expected_error)) + end + end + + context "when tenancy length is between 2-99" do + it "does not add an error" do + record.tenancylength = 3 + tenancy_validator.validate_fixed_term_tenancy(record) + expect(record.errors).to be_empty + end + end + + context "when tenancy length has not been answered" do + it "does not add an error" do + record.tenancylength = nil + tenancy_validator.validate_fixed_term_tenancy(record) + expect(record.errors).to be_empty + end + end + end end end end