Browse Source

CLDC-3278: Restructure tenancy length validations to only error on relevant fields

pull/2295/head
Rachael Booth 2 years ago
parent
commit
5d1348a696
  1. 108
      app/models/validations/tenancy_validations.rb
  2. 9
      spec/models/lettings_log_spec.rb
  3. 426
      spec/models/validations/tenancy_validations_spec.rb

108
app/models/validations/tenancy_validations.rb

@ -3,48 +3,68 @@ module Validations::TenancyValidations
# or 'validate_' to run on submit as well # or 'validate_' to run on submit as well
include Validations::SharedValidations include Validations::SharedValidations
def validate_fixed_term_tenancy(record) # N.B. To match the page split and naming, this is the supported housing case
is_present = record.tenancylength.present? # General needs cases are in the other validations below
is_in_range = record.tenancylength.to_i.between?(min_tenancy_length(record), 99) def validate_tenancy_length(record)
rent_type_dependent_conditions = [ return unless record.tenancy_type_fixed_term? && record.is_supported_housing?
{ return if record.tenancylength.blank?
condition: (record.is_assured_shorthold_tenancy? && !is_in_range) && is_present,
error: I18n.t( min_tenancy_length = 1
"validations.tenancy.length.shorthold", return if record.tenancylength.to_i.between?(min_tenancy_length, 99)
min_tenancy_length: min_tenancy_length(record),
), message = record.is_assured_shorthold_tenancy? ? I18n.t("validations.tenancy.length.shorthold", min_tenancy_length:) : I18n.t("validations.tenancy.length.secure", min_tenancy_length:)
}, record.errors.add :needstype, message
{ record.errors.add :rent_type, message
condition: (record.is_secure_tenancy? && !is_in_range) && is_present, record.errors.add :tenancylength, :tenancylength_invalid, message: message
error: I18n.t( record.errors.add :tenancy, message
"validations.tenancy.length.secure", end
min_tenancy_length: min_tenancy_length(record),
), def validate_tenancy_length_affordable_rent(record)
}, return unless record.tenancy_type_fixed_term? && record.affordable_or_social_rent? && record.is_general_needs?
{ return if record.tenancylength.blank?
condition: (record.is_periodic_tenancy? && !is_in_range) && is_present,
error: I18n.t( min_tenancy_length = 2
"validations.tenancy.length.secure", return if record.tenancylength.to_i.between?(min_tenancy_length, 99)
min_tenancy_length: min_tenancy_length(record),
), message = record.is_assured_shorthold_tenancy? ? I18n.t("validations.tenancy.length.shorthold", min_tenancy_length:) : I18n.t("validations.tenancy.length.secure", min_tenancy_length:)
}, record.errors.add :needstype, message
] record.errors.add :rent_type, message
rent_type_independent_conditions = [ record.errors.add :tenancylength, :tenancylength_invalid, message: message
{ record.errors.add :tenancy, message
condition: !(record.is_secure_tenancy? || record.is_assured_shorthold_tenancy? || record.is_periodic_tenancy?) && is_present, end
error: I18n.t("validations.tenancy.length.fixed_term_not_required"),
}, def validate_tenancy_length_intermediate_rent(record)
] return unless record.tenancy_type_fixed_term? && !record.affordable_or_social_rent? && record.is_general_needs?
conditions = rent_type_dependent_conditions + rent_type_independent_conditions return if record.tenancylength.blank?
conditions.each do |condition| min_tenancy_length = 1
next unless condition[:condition] return if record.tenancylength.to_i.between?(min_tenancy_length, 99)
record.errors.add :needstype, condition[:error] message = record.is_assured_shorthold_tenancy? ? I18n.t("validations.tenancy.length.shorthold", min_tenancy_length:) : I18n.t("validations.tenancy.length.secure", min_tenancy_length:)
record.errors.add :rent_type, condition[:error] if rent_type_dependent_conditions.include?(condition) record.errors.add :needstype, message
record.errors.add :tenancylength, :tenancylength_invalid, message: condition[:error] record.errors.add :rent_type, message
record.errors.add :tenancy, condition[:error] record.errors.add :tenancylength, :tenancylength_invalid, message: message
end record.errors.add :tenancy, message
end
def validate_tenancy_length_periodic(record)
return unless record.is_periodic_tenancy? && record.tenancylength.present?
min_tenancy_length = 1
return if record.tenancylength.to_i.between?(min_tenancy_length, 99)
message = I18n.t("validations.tenancy.length.secure", min_tenancy_length:)
record.errors.add :tenancylength, :tenancylength_invalid, message: message
record.errors.add :tenancy, message
end
def validate_tenancy_length_blank_when_not_required(record)
return if record.tenancylength.blank?
return if record.tenancy_type_fixed_term? || record.is_periodic_tenancy?
message = I18n.t("validations.tenancy.length.fixed_term_not_required")
record.errors.add :tenancylength, :tenancylength_invalid, message: message
record.errors.add :tenancy, message
end end
def validate_other_tenancy_type(record) def validate_other_tenancy_type(record)
@ -59,8 +79,4 @@ module Validations::TenancyValidations
record.errors.add :hhmemb, I18n.t("validations.tenancy.joint_more_than_one_member") record.errors.add :hhmemb, I18n.t("validations.tenancy.joint_more_than_one_member")
end end
end end
def min_tenancy_length(record)
record.is_supported_housing? || record.renttype == 3 || record.is_periodic_tenancy? ? 1 : 2
end
end end

9
spec/models/lettings_log_spec.rb

@ -112,10 +112,17 @@ RSpec.describe LettingsLog do
end end
it "validates tenancy type" do it "validates tenancy type" do
expect(validator).to receive(:validate_fixed_term_tenancy)
expect(validator).to receive(:validate_other_tenancy_type) expect(validator).to receive(:validate_other_tenancy_type)
end end
it "validates tenancy length" do
expect(validator).to receive(:validate_tenancy_length)
expect(validator).to receive(:validate_tenancy_length_affordable_rent)
expect(validator).to receive(:validate_tenancy_length_intermediate_rent)
expect(validator).to receive(:validate_tenancy_length_periodic)
expect(validator).to receive(:validate_tenancy_length_blank_when_not_required)
end
it "validates the previous postcode" do it "validates the previous postcode" do
expect(validator).to receive(:validate_previous_accommodation_postcode) expect(validator).to receive(:validate_previous_accommodation_postcode)
end end

426
spec/models/validations/tenancy_validations_spec.rb

@ -3,280 +3,271 @@ require "rails_helper"
RSpec.describe Validations::TenancyValidations do RSpec.describe Validations::TenancyValidations do
subject(:tenancy_validator) { validator_class.new } subject(:tenancy_validator) { validator_class.new }
before do let(:validator_class) { Class.new { include Validations::TenancyValidations } }
Timecop.freeze(Time.zone.local(2021, 5, 1))
end
after do describe "tenancy length validations" do
Timecop.unfreeze let(:record) { FactoryBot.create(:lettings_log, :setup_completed) }
end
let(:validator_class) { Class.new { include Validations::TenancyValidations } } shared_examples "adds expected errors based on the tenancy length" do |tenancy_type_case, min_tenancy_length|
let(:record) { FactoryBot.create(:lettings_log, startdate: Time.zone.local(2021, 5, 1), needstype: 1, rent_type: 1) } context "and tenancy type is #{tenancy_type_case[:name]}" do
let(:expected_error) { tenancy_type_case[:expected_error].call(min_tenancy_length) }
describe "fixed term tenancy validations" do
context "when fixed term tenancy" do
context "when type of tenancy is not assured or assured shorthold" do
let(:expected_error) { I18n.t("validations.tenancy.length.fixed_term_not_required") }
it "tenancy length should not be present" do
record.tenancy = 3
record.tenancylength = 10
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["needstype"]).to include(match(expected_error))
expect(record.errors["rent_type"]).not_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 type of tenancy is assured shorthold" do before { record.tenancy = tenancy_type_case[:code] }
let(:expected_error) do
I18n.t(
"validations.tenancy.length.shorthold",
min_tenancy_length: 2,
)
end
before { record.tenancy = 4 } context "and tenancy length is less than #{min_tenancy_length}" do
before { record.tenancylength = min_tenancy_length - 1 }
context "when tenancy length is less than 2" do it "adds errors to #{tenancy_type_case[:error_fields].join(', ')}" do
it "adds an error" do validation.call(record)
record.tenancylength = 1 tenancy_type_case[:error_fields].each do |field|
tenancy_validator.validate_fixed_term_tenancy(record) expect(record.errors[field]).to include(match(expected_error))
expect(record.errors["needstype"]).to include(match(expected_error)) end
expect(record.errors["rent_type"]).to include(match(expected_error)) expect(record.errors.size).to be(tenancy_type_case[:error_fields].length)
expect(record.errors["tenancylength"]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error))
end end
end end
context "when tenancy length is greater than 99" do context "and tenancy length is more than 99" do
it "adds an error" do before { record.tenancylength = 100 }
record.tenancylength = 100
tenancy_validator.validate_fixed_term_tenancy(record) it "adds errors to #{tenancy_type_case[:error_fields].join(', ')}" do
expect(record.errors["needstype"]).to include(match(expected_error)) validation.call(record)
expect(record.errors["rent_type"]).to include(match(expected_error)) tenancy_type_case[:error_fields].each do |field|
expect(record.errors["tenancylength"]).to include(match(expected_error)) expect(record.errors[field]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error)) end
expect(record.errors.size).to be(tenancy_type_case[:error_fields].length)
end end
end end
context "when tenancy length is between 2-99" do context "and tenancy length is between #{min_tenancy_length} and 99" do
it "does not add an error" do before { record.tenancylength = min_tenancy_length }
record.tenancylength = 3
tenancy_validator.validate_fixed_term_tenancy(record) it "does not add errors" do
validation.call(record)
expect(record.errors).to be_empty expect(record.errors).to be_empty
end end
end end
context "when tenancy length has not been answered" do context "and tenancy length is not set" do
it "does not add an error" do before { record.tenancylength = nil }
record.tenancylength = nil
tenancy_validator.validate_fixed_term_tenancy(record) it "does not add errors" do
validation.call(record)
expect(record.errors).to be_empty expect(record.errors).to be_empty
end end
end end
end end
end
context "when the collection start year is before 2022" do shared_examples "does not add errors when tenancy type is not fixed term" do
context "when type of tenancy is secure" do context "and tenancy type is not fixed term" do
let(:expected_error) do before do
I18n.t( record.tenancy = 8
"validations.tenancy.length.secure", record.tenancylength = 0
min_tenancy_length: 2, end
)
end it "does not add errors" do
validation.call(record)
expect(record.errors).to be_empty
end
end
end
before { record.tenancy = 1 } fixed_term_tenancy_type_cases = [
{
name: "assured shorthold",
code: 4,
expected_error: ->(min_tenancy_length) { I18n.t("validations.tenancy.length.shorthold", min_tenancy_length:) },
error_fields: %w[needstype rent_type tenancylength tenancy],
},
{
name: "secure fixed term",
code: 6,
expected_error: ->(min_tenancy_length) { I18n.t("validations.tenancy.length.secure", min_tenancy_length:) },
error_fields: %w[needstype rent_type tenancylength tenancy],
},
]
describe "#validate_tenancy_length" do
subject(:validation) { ->(record) { tenancy_validator.validate_tenancy_length(record) } }
context "when needs type is supported housing" do
before { record.needstype = 2 }
fixed_term_tenancy_type_cases.each do |tenancy_type_case|
include_examples "adds expected errors based on the tenancy length", tenancy_type_case, 1
end
context "when tenancy length is less than 2" do include_examples "does not add errors when tenancy type is not fixed term"
it "adds an error" do end
record.tenancylength = 1
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 context "when needs type is general needs" do
it "adds an error" do before do
record.tenancylength = 100 record.needstype = 1
tenancy_validator.validate_fixed_term_tenancy(record) record.tenancy = 4
expect(record.errors["needstype"]).to include(match(expected_error)) record.tenancylength = 0
expect(record.errors["tenancylength"]).to include(match(expected_error)) end
expect(record.errors["tenancy"]).to include(match(expected_error))
end it "does not add errors" do
validation.call(record)
expect(record.errors).to be_empty
end
end
end
describe "#validate_tenancy_length_affordable_rent" do
subject(:validation) { ->(record) { tenancy_validator.validate_tenancy_length_affordable_rent(record) } }
context "when needs type is general needs" do
before { record.needstype = 1 }
context "and rent type is affordable or social rent" do
before { record.renttype = 1 }
fixed_term_tenancy_type_cases.each do |tenancy_type_case|
include_examples "adds expected errors based on the tenancy length", tenancy_type_case, 2
end end
context "when tenancy length is between 2-99" do include_examples "does not add errors when tenancy type is not fixed term"
it "does not add an error" do end
record.tenancylength = 3
tenancy_validator.validate_fixed_term_tenancy(record) context "and rent type is intermediate rent" do
expect(record.errors).to be_empty before do
end record.renttype = 3
record.tenancy = 4
record.tenancylength = 0
end end
context "when tenancy length has not been answered" do it "does not add errors" do
it "does not add an error" do validation.call(record)
record.tenancylength = nil expect(record.errors).to be_empty
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors).to be_empty
end
end end
end end
end end
context "when the collection start year is 2022 or later" do context "when needs type is supported housing" do
before do before do
Timecop.freeze(2022, 5, 1) record.needstype = 2
record.renttype = 1
record.tenancy = 4
record.tenancylength = 0
end end
after do it "does not add errors" do
Timecop.unfreeze validation.call(record)
expect(record.errors).to be_empty
end end
end
end
let(:record) { FactoryBot.create(:lettings_log, startdate: Time.zone.local(2022, 5, 1), needstype: 1, rent_type: 1) } describe "#validate_tenancy_length_intermediate_rent" do
subject(:validation) { ->(record) { tenancy_validator.validate_tenancy_length_intermediate_rent(record) } }
context "when type of tenancy is Secure - fixed term" do context "when needs type is general needs" do
let(:expected_error) do before { record.needstype = 1 }
I18n.t(
"validations.tenancy.length.secure",
min_tenancy_length: 2,
)
end
before { record.tenancy = 6 } context "and rent type is intermediate rent" do
before { record.renttype = 3 }
context "when tenancy length is less than 2" do fixed_term_tenancy_type_cases.each do |tenancy_type_case|
it "adds an error" do include_examples "adds expected errors based on the tenancy length", tenancy_type_case, 1
record.tenancylength = 1
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 end
context "when tenancy length is greater than 99" do include_examples "does not add errors when tenancy type is not fixed term"
it "adds an error" do end
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 context "and rent type is not intermediate rent" do
it "does not add an error" do before do
record.tenancylength = 3 record.renttype = 2
tenancy_validator.validate_fixed_term_tenancy(record) record.tenancy = 4
expect(record.errors).to be_empty record.tenancylength = 0
end
end end
context "when tenancy length has not been answered" do it "does not add errors" do
it "does not add an error" do validation.call(record)
record.tenancylength = nil expect(record.errors).to be_empty
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors).to be_empty
end
end end
end end
end
context "when type of tenancy is Secure - lifetime" do context "when needs type is supported housing" do
let(:expected_error) do before do
I18n.t( record.needstype = 2
"validations.tenancy.length.secure", record.renttype = 3
min_tenancy_length: 2, record.tenancy = 4
) record.tenancylength = 0
end end
before { record.tenancy = 7 } it "does not add errors" do
validation.call(record)
expect(record.errors).to be_empty
end
end
end
context "when tenancy length is less than 2" do describe "#validate_tenancy_length_periodic" do
it "adds an error" do subject(:validation) { ->(record) { tenancy_validator.validate_tenancy_length_periodic(record) } }
record.tenancylength = 1
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 periodic_tenancy_case = {
it "adds an error" do name: "periodic",
record.tenancylength = 100 code: 8,
tenancy_validator.validate_fixed_term_tenancy(record) expected_error: ->(min_tenancy_length) { I18n.t("validations.tenancy.length.secure", min_tenancy_length:) },
expect(record.errors["needstype"]).to include(match(expected_error)) error_fields: %w[tenancylength tenancy],
expect(record.errors["tenancylength"]).to include(match(expected_error)) }
expect(record.errors["tenancy"]).to include(match(expected_error)) include_examples "adds expected errors based on the tenancy length", periodic_tenancy_case, 1
end
end
context "when tenancy length is between 2-99" do context "when tenancy type is not periodic" do
it "does not add an error" do before do
record.tenancylength = 3 record.tenancy = 6
tenancy_validator.validate_fixed_term_tenancy(record) record.tenancylength = 0
expect(record.errors).to be_empty end
end
end
context "when tenancy length has not been answered" do it "does not add errors" do
it "does not add an error" do validation.call(record)
record.tenancylength = nil expect(record.errors).to be_empty
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors).to be_empty
end
end
end end
end
context "when type of tenancy is periodic" do describe "#validate_tenancy_length_blank_when_not_required" do
let(:expected_error) do context "when a tenancy length is provided" do
I18n.t( before { record.tenancylength = 10 }
"validations.tenancy.length.secure",
min_tenancy_length: 1,
)
end
before { record.tenancy = 8 } context "and tenancy type is not fixed term or periodic" do
before { record.tenancy = 5 }
context "when tenancy length is less than 1" do it "adds errors to tenancylength and tenancy" do
it "adds an error" do tenancy_validator.validate_tenancy_length_blank_when_not_required(record)
record.tenancylength = 0 expected_error = I18n.t("validations.tenancy.length.fixed_term_not_required")
tenancy_validator.validate_fixed_term_tenancy(record) expect(record.errors["tenancylength"]).to include(expected_error)
expect(record.errors["needstype"]).to include(match(expected_error)) expect(record.errors["tenancy"]).to include(expected_error)
expect(record.errors["tenancylength"]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error))
end end
end end
context "when tenancy length is greater than 99" do tenancy_types_with_length = [
it "adds an error" do { name: "assured shorthold", code: 4 },
record.tenancylength = 100 { name: "secure fixed term", code: 6 },
tenancy_validator.validate_fixed_term_tenancy(record) { name: "periodic", code: 8 },
expect(record.errors["needstype"]).to include(match(expected_error)) ]
expect(record.errors["tenancylength"]).to include(match(expected_error)) tenancy_types_with_length.each do |type|
expect(record.errors["tenancy"]).to include(match(expected_error)) context "and tenancy type is #{type[:name]}" do
before { record.tenancy = type[:code] }
it "does not add errors" do
tenancy_validator.validate_tenancy_length_blank_when_not_required(record)
expect(record.errors).to be_empty
end
end end
end end
end
context "when tenancy length is between 2-99" do context "when tenancy length is not provided" do
it "does not add an error" do before do
record.tenancylength = 3 record.tenancylength = nil
tenancy_validator.validate_fixed_term_tenancy(record) record.tenancy = 5
expect(record.errors).to be_empty
end
end end
context "when tenancy length has not been answered" do it "does not add errors" do
it "does not add an error" do tenancy_validator.validate_tenancy_length_blank_when_not_required(record)
record.tenancylength = nil expect(record.errors).to be_empty
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors).to be_empty
end
end end
end end
end end
@ -284,6 +275,7 @@ RSpec.describe Validations::TenancyValidations do
end end
describe "tenancy type validations" do describe "tenancy type validations" do
let(:record) { FactoryBot.create(:lettings_log, :setup_completed) }
let(:field) { "validations.other_field_missing" } let(:field) { "validations.other_field_missing" }
let(:main_field_label) { "tenancy type" } let(:main_field_label) { "tenancy type" }
let(:other_field) { "tenancyother" } let(:other_field) { "tenancyother" }
@ -327,20 +319,11 @@ RSpec.describe Validations::TenancyValidations do
describe "joint tenancy validation" do describe "joint tenancy validation" do
context "when the data inputter has said that there is only one member in the household" do context "when the data inputter has said that there is only one member in the household" do
before do let(:record) { FactoryBot.create(:lettings_log, :setup_completed, hhmemb: 1) }
Timecop.freeze(2022, 5, 1)
end
after do
Timecop.unfreeze
end
let(:record) { FactoryBot.create(:lettings_log, startdate: Time.zone.local(2022, 5, 1)) }
let(:expected_error) { I18n.t("validations.tenancy.not_joint") } let(:expected_error) { I18n.t("validations.tenancy.not_joint") }
let(:hhmemb_expected_error) { I18n.t("validations.tenancy.joint_more_than_one_member") } let(:hhmemb_expected_error) { I18n.t("validations.tenancy.joint_more_than_one_member") }
it "displays an error if the data inputter says the letting is a joint tenancy" do it "displays an error if the data inputter says the letting is a joint tenancy" do
record.hhmemb = 1
record.joint = 1 record.joint = 1
tenancy_validator.validate_joint_tenancy(record) tenancy_validator.validate_joint_tenancy(record)
expect(record.errors["joint"]).to include(match(expected_error)) expect(record.errors["joint"]).to include(match(expected_error))
@ -348,7 +331,6 @@ RSpec.describe Validations::TenancyValidations do
end end
it "does not display an error if the data inputter says the letting is not a joint tenancy" do it "does not display an error if the data inputter says the letting is not a joint tenancy" do
record.hhmemb = 1
record.joint = 2 record.joint = 2
tenancy_validator.validate_joint_tenancy(record) tenancy_validator.validate_joint_tenancy(record)
expect(record.errors["joint"]).to be_empty expect(record.errors["joint"]).to be_empty
@ -356,7 +338,6 @@ RSpec.describe Validations::TenancyValidations do
end end
it "does not display an error if the data inputter has given the household members but not input if it is a joint tenancy" do it "does not display an error if the data inputter has given the household members but not input if it is a joint tenancy" do
record.hhmemb = 1
record.joint = nil record.joint = nil
tenancy_validator.validate_joint_tenancy(record) tenancy_validator.validate_joint_tenancy(record)
expect(record.errors["joint"]).to be_empty expect(record.errors["joint"]).to be_empty
@ -364,7 +345,6 @@ RSpec.describe Validations::TenancyValidations do
end end
it "does not error when don't know answer to joint" do it "does not error when don't know answer to joint" do
record.hhmemb = 1
record.joint = 3 record.joint = 3
tenancy_validator.validate_joint_tenancy(record) tenancy_validator.validate_joint_tenancy(record)

Loading…
Cancel
Save