Browse Source

Household member validations (#420)

* Add missing ecstat validation

* Add compound validation errors to all involved fields

* Update ecstat values

* Update values in validations and tests

* Update rent rant values

* Add some helper methods for readability
2021-2022-json-updates
baarkerlounger 3 years ago committed by GitHub
parent
commit
910f13d507
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 45
      app/models/validations/household_validations.rb
  2. 18
      app/models/validations/soft_validations.rb
  3. 127
      config/forms/2021_2022.json
  4. 11
      config/locales/en.yml
  5. 2
      spec/factories/case_log.rb
  6. 16
      spec/fixtures/complete_case_log.json
  7. 2
      spec/fixtures/exports/case_logs.xml
  8. 62
      spec/models/validations/household_validations_spec.rb

45
app/models/validations/household_validations.rb

@ -131,11 +131,17 @@ private
economic_status = record.public_send("ecstat#{person_num}")
return unless age && economic_status
if age > 70 && economic_status != 4
if age > 70 && !tenant_is_retired?(economic_status)
record.errors.add "ecstat#{person_num}", I18n.t("validations.household.ecstat.retired_over_70", person_num:)
record.errors.add "age#{person_num}", I18n.t("validations.household.age.retired_over_70", person_num:)
end
if age < 16 && economic_status != 8
if age < 16 && !tenant_is_economic_child?(economic_status)
record.errors.add "ecstat#{person_num}", I18n.t("validations.household.ecstat.child_under_16", person_num:)
record.errors.add "age#{person_num}", I18n.t("validations.household.age.child_under_16", person_num:)
end
if tenant_is_economic_child?(economic_status) && age > 16
record.errors.add "ecstat#{person_num}", I18n.t("validations.household.ecstat.child_over_16", person_num:)
record.errors.add "age#{person_num}", I18n.t("validations.household.age.child_over_16", person_num:)
end
end
@ -144,8 +150,9 @@ private
relationship = record.public_send("relat#{person_num}")
return unless age && relationship
if age < 16 && relationship != 1
if age < 16 && !tenant_is_child?(relationship)
record.errors.add "relat#{person_num}", I18n.t("validations.household.relat.child_under_16", person_num:)
record.errors.add "age#{person_num}", I18n.t("validations.household.age.child_under_16_relat", person_num:)
end
end
@ -155,8 +162,10 @@ private
relationship = record.public_send("relat#{person_num}")
return unless age && economic_status && relationship
if age >= 16 && age <= 19 && relationship == 1 && (economic_status != 6 && economic_status != 10)
if age >= 16 && age <= 19 && tenant_is_child?(relationship) && (!tenant_is_fulltime_student?(economic_status) && !tenant_economic_status_refused?(economic_status))
record.errors.add "ecstat#{person_num}", I18n.t("validations.household.ecstat.student_16_19", person_num:)
record.errors.add "age#{person_num}", I18n.t("validations.household.age.student_16_19", person_num:)
record.errors.add "relat#{person_num}", I18n.t("validations.household.relat.student_16_19", person_num:)
end
end
@ -166,11 +175,15 @@ private
economic_status = record.public_send("ecstat#{person_num}")
return unless age && economic_status && gender
if gender == "M" && economic_status == 4 && age < 65
if gender == "M" && tenant_is_retired?(economic_status) && age < 65
record.errors.add "age#{person_num}", I18n.t("validations.household.age.retired_male")
record.errors.add "sex#{person_num}", I18n.t("validations.household.gender.retired_male")
record.errors.add "ecstat#{person_num}", I18n.t("validations.household.ecstat.retired_male")
end
if gender == "F" && economic_status == 4 && age < 60
if gender == "F" && tenant_is_retired?(economic_status) && age < 60
record.errors.add "age#{person_num}", I18n.t("validations.household.age.retired_female")
record.errors.add "sex#{person_num}", I18n.t("validations.household.gender.retired_female")
record.errors.add "ecstat#{person_num}", I18n.t("validations.household.ecstat.retired_female")
end
end
@ -180,4 +193,24 @@ private
record.errors.add :base, I18n.t("validations.household.relat.one_partner")
end
end
def tenant_is_retired?(economic_status)
economic_status == 5
end
def tenant_is_economic_child?(economic_status)
economic_status == 9
end
def tenant_is_fulltime_student?(economic_status)
economic_status == 7
end
def tenant_economic_status_refused?(economic_status)
economic_status == 10
end
def tenant_is_child?(relationship)
relationship == 1
end
end

18
app/models/validations/soft_validations.rb

@ -1,15 +1,15 @@
module Validations::SoftValidations
ALLOWED_INCOME_RANGES = {
1 => OpenStruct.new(soft_min: 143, soft_max: 730, hard_min: 90, hard_max: 1230),
0 => OpenStruct.new(soft_min: 67, soft_max: 620, hard_min: 50, hard_max: 950),
2 => OpenStruct.new(soft_min: 80, soft_max: 480, hard_min: 40, hard_max: 990),
3 => OpenStruct.new(soft_min: 50, soft_max: 370, hard_min: 10, hard_max: 450),
4 => OpenStruct.new(soft_min: 50, soft_max: 380, hard_min: 10, hard_max: 690),
5 => OpenStruct.new(soft_min: 53, soft_max: 540, hard_min: 10, hard_max: 890),
6 => OpenStruct.new(soft_min: 47, soft_max: 460, hard_min: 10, hard_max: 1300),
7 => OpenStruct.new(soft_min: 54, soft_max: 460, hard_min: 10, hard_max: 820),
8 => OpenStruct.new(soft_min: 50, soft_max: 450, hard_min: 10, hard_max: 750),
9 => OpenStruct.new(soft_min: 50, soft_max: 580, hard_min: 10, hard_max: 1040),
2 => OpenStruct.new(soft_min: 67, soft_max: 620, hard_min: 50, hard_max: 950),
3 => OpenStruct.new(soft_min: 80, soft_max: 480, hard_min: 40, hard_max: 990),
4 => OpenStruct.new(soft_min: 50, soft_max: 370, hard_min: 10, hard_max: 450),
5 => OpenStruct.new(soft_min: 50, soft_max: 380, hard_min: 10, hard_max: 690),
6 => OpenStruct.new(soft_min: 53, soft_max: 540, hard_min: 10, hard_max: 890),
7 => OpenStruct.new(soft_min: 47, soft_max: 460, hard_min: 10, hard_max: 1300),
8 => OpenStruct.new(soft_min: 54, soft_max: 460, hard_min: 10, hard_max: 820),
9 => OpenStruct.new(soft_min: 50, soft_max: 450, hard_min: 10, hard_max: 750),
0 => OpenStruct.new(soft_min: 50, soft_max: 580, hard_min: 10, hard_max: 1040),
10 => OpenStruct.new(soft_min: 47, soft_max: 730, hard_min: 10, hard_max: 1300),
}.freeze

127
config/forms/2021_2022.json

@ -1537,13 +1537,13 @@
"hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.",
"type": "radio",
"answer_options": {
"0": {
"2": {
"value": "Part-time – Less than 30 hours"
},
"1": {
"value": "Full-time – 30 hours or more"
},
"2": {
"7": {
"value": "Full-time student"
},
"3": {
@ -1552,19 +1552,16 @@
"4": {
"value": "Jobseeker"
},
"5": {
"6": {
"value": "Not seeking work"
},
"6": {
"8": {
"value": "Unable to work because of long term sick or disability"
},
"7": {
"5": {
"value": "Retired"
},
"8": {
"value": "Child under 16"
},
"9": {
"0": {
"value": "Other"
},
"divider": {
@ -1743,13 +1740,13 @@
"hint_text": "",
"type": "radio",
"answer_options": {
"0": {
"2": {
"value": "Part-time – Less than 30 hours"
},
"1": {
"value": "Full-time – 30 hours or more"
},
"2": {
"7": {
"value": "Full-time student"
},
"3": {
@ -1758,26 +1755,26 @@
"4": {
"value": "Jobseeker"
},
"5": {
"6": {
"value": "Not seeking work"
},
"6": {
"8": {
"value": "Unable to work because of long term sick or disability"
},
"7": {
"5": {
"value": "Retired"
},
"8": {
"9": {
"value": "Child under 16"
},
"9": {
"0": {
"value": "Other"
},
"divider": {
"value": true
},
"10": {
"value": "Person prefers not to say"
"value": "Tenant prefers not to say"
}
}
}
@ -1951,13 +1948,13 @@
"hint_text": "",
"type": "radio",
"answer_options": {
"0": {
"2": {
"value": "Part-time – Less than 30 hours"
},
"1": {
"value": "Full-time – 30 hours or more"
},
"2": {
"7": {
"value": "Full-time student"
},
"3": {
@ -1966,26 +1963,26 @@
"4": {
"value": "Jobseeker"
},
"5": {
"6": {
"value": "Not seeking work"
},
"6": {
"8": {
"value": "Unable to work because of long term sick or disability"
},
"7": {
"5": {
"value": "Retired"
},
"8": {
"9": {
"value": "Child under 16"
},
"9": {
"0": {
"value": "Other"
},
"divider": {
"value": true
},
"10": {
"value": "Person prefers not to say"
"value": "Tenant prefers not to say"
}
}
}
@ -2156,13 +2153,13 @@
"hint_text": "",
"type": "radio",
"answer_options": {
"0": {
"2": {
"value": "Part-time – Less than 30 hours"
},
"1": {
"value": "Full-time – 30 hours or more"
},
"2": {
"7": {
"value": "Full-time student"
},
"3": {
@ -2171,26 +2168,26 @@
"4": {
"value": "Jobseeker"
},
"5": {
"6": {
"value": "Not seeking work"
},
"6": {
"8": {
"value": "Unable to work because of long term sick or disability"
},
"7": {
"5": {
"value": "Retired"
},
"8": {
"9": {
"value": "Child under 16"
},
"9": {
"0": {
"value": "Other"
},
"divider": {
"value": true
},
"10": {
"value": "Person prefers not to say"
"value": "Tenant prefers not to say"
}
}
}
@ -2358,13 +2355,13 @@
"hint_text": "",
"type": "radio",
"answer_options": {
"0": {
"2": {
"value": "Part-time – Less than 30 hours"
},
"1": {
"value": "Full-time – 30 hours or more"
},
"2": {
"7": {
"value": "Full-time student"
},
"3": {
@ -2373,26 +2370,26 @@
"4": {
"value": "Jobseeker"
},
"5": {
"6": {
"value": "Not seeking work"
},
"6": {
"8": {
"value": "Unable to work because of long term sick or disability"
},
"7": {
"5": {
"value": "Retired"
},
"8": {
"9": {
"value": "Child under 16"
},
"9": {
"0": {
"value": "Other"
},
"divider": {
"value": true
},
"10": {
"value": "Person prefers not to say"
"value": "Tenant prefers not to say"
}
}
}
@ -2557,13 +2554,13 @@
"hint_text": "",
"type": "radio",
"answer_options": {
"0": {
"2": {
"value": "Part-time – Less than 30 hours"
},
"1": {
"value": "Full-time – 30 hours or more"
},
"2": {
"7": {
"value": "Full-time student"
},
"3": {
@ -2572,26 +2569,26 @@
"4": {
"value": "Jobseeker"
},
"5": {
"6": {
"value": "Not seeking work"
},
"6": {
"8": {
"value": "Unable to work because of long term sick or disability"
},
"7": {
"5": {
"value": "Retired"
},
"8": {
"9": {
"value": "Child under 16"
},
"9": {
"0": {
"value": "Other"
},
"divider": {
"value": true
},
"10": {
"value": "Person prefers not to say"
"value": "Tenant prefers not to say"
}
}
}
@ -2753,13 +2750,13 @@
"hint_text": "",
"type": "radio",
"answer_options": {
"0": {
"2": {
"value": "Part-time – Less than 30 hours"
},
"1": {
"value": "Full-time – 30 hours or more"
},
"2": {
"7": {
"value": "Full-time student"
},
"3": {
@ -2768,26 +2765,26 @@
"4": {
"value": "Jobseeker"
},
"5": {
"6": {
"value": "Not seeking work"
},
"6": {
"8": {
"value": "Unable to work because of long term sick or disability"
},
"7": {
"5": {
"value": "Retired"
},
"8": {
"9": {
"value": "Child under 16"
},
"9": {
"0": {
"value": "Other"
},
"divider": {
"value": true
},
"10": {
"value": "Person prefers not to say"
"value": "Tenant prefers not to say"
}
}
}
@ -2946,13 +2943,13 @@
"hint_text": "",
"type": "radio",
"answer_options": {
"0": {
"2": {
"value": "Part-time – Less than 30 hours"
},
"1": {
"value": "Full-time – 30 hours or more"
},
"2": {
"7": {
"value": "Full-time student"
},
"3": {
@ -2961,26 +2958,26 @@
"4": {
"value": "Jobseeker"
},
"5": {
"6": {
"value": "Not seeking work"
},
"6": {
"8": {
"value": "Unable to work because of long term sick or disability"
},
"7": {
"5": {
"value": "Retired"
},
"8": {
"9": {
"value": "Child under 16"
},
"9": {
"0": {
"value": "Other"
},
"divider": {
"value": true
},
"10": {
"value": "Person prefers not to say"
"value": "Tenant prefers not to say"
}
}
}

11
config/locales/en.yml

@ -152,15 +152,24 @@ en:
age:
retired_male: "Male tenant who is retired must be 65 or over"
retired_female: "Female tenant who is retired must be 60 or over"
retired_over_70: 'Answer cannot be over 70 as as tenant %{person_num} has economic status that is not "Retired"'
child_under_16_relat: 'Answer cannot be under 16 as tenant %{person_num} is not a child of the lead tenant'
child_under_16: 'Answer cannot be under 16 as tenant %{person_num} has economic status that is not "Child under 16"'
child_over_16: 'Answer cannot be over 16 as tenant %{person_num} has economic status "Child under 16"'
student_16_19: 'Answer cannot be between 16 and 19 as tenant %{person_num} is a child of the lead tenant but is not a full time student'
lead:
over_20: "Lead tenant must be under 20 as you told us that their housing situation immediately before this letting was a children's home or foster care"
ecstat:
retired_over_70: "Tenant %{person_num} must be retired if over 70"
child_under_16: "Tenant %{person_num} economic status must be Child under 16 if their age is under 16"
child_over_16: 'Answer cannot be "Child under 16" as tenant %{person_num} is older than 16'
student_16_19: "If age is between 16 and 19 - tenant %{person_num} must be a full time student or prefer not to say."
retired_male: "Male tenant who is under 65 cannot be retired"
retired_female: "Female tenant who is under 60 cannot be retired"
relat:
child_under_16: "Tenant %{person_num}’s relationship to tenant 1 must be Child if their age is under 16"
one_partner: "Number of partners cannot be greater than 1"
student_16_19: 'Answer cannot be "Child" as tenant %{person_num} is between 16 and 19 but is not a full time student'
housingneeds_a:
one_or_two_choices: "Only one box must be ticked or 'other disabilities' plus one of mobility disabilities"
prevten:
@ -185,6 +194,8 @@ en:
not_homeless: "Answer cannot be ‘no’ as you already told us the tenant was homeless or about to lose their home"
previous_la_known: "Enter a local authority"
gender:
retired_male: 'Answer cannot be "Male" as tenant is under 65 and retired'
retired_female: 'Answer cannot be "Female" as tenant is under 60 and retired'
male_refuge: "Answer cannot be male as you told us their housing situation immediately before this letting was a refuge"
reason:
not_internal_transfer: "Answer cannot be permanently decanted from another property owned by this landlord as you told us the source of referral for this tenancy was not an internal transfer"

2
spec/factories/case_log.rb

@ -46,7 +46,7 @@ FactoryBot.define do
relat2 { 0 }
age2 { 32 }
sex2 { "M" }
ecstat2 { 5 }
ecstat2 { 6 }
homeless { 1 }
underoccupation_benefitcap { 0 }
leftreg { 1 }

16
spec/fixtures/complete_case_log.json vendored

@ -14,31 +14,31 @@
"relat2": 0,
"age2": 32,
"sex2": "M",
"ecstat2": 5,
"ecstat2": 6,
"relat3": 1,
"age3": 12,
"sex3": "M",
"ecstat3": 8,
"ecstat3": 9,
"relat4": 1,
"age4": 12,
"sex4": "F",
"ecstat4": 8,
"ecstat4": 9,
"relat5": 1,
"age5": 10,
"sex5": "X",
"ecstat5": 8,
"ecstat5": 9,
"relat6": 1,
"age6": 5,
"sex6": "R",
"ecstat6": 8,
"ecstat6": 9,
"relat7": 1,
"age7": 5,
"sex7": "R",
"ecstat7": 8,
"ecstat7": 9,
"relat8": 1,
"age8": 2,
"sex8": "R",
"ecstat8": 8,
"ecstat8": 9,
"homeless": 2,
"reason": 1,
"underoccupation_benefitcap": 0,
@ -66,7 +66,7 @@
"property_void_date": "10/10/2020",
"vday": 10,
"vmonth": 10,
"vyear": 2020,
"vyear": 2020,
"majorrepairs": 1,
"mrcdate": "11/11/2020",
"mrcday": 11,

2
spec/fixtures/exports/case_logs.xml vendored

@ -15,7 +15,7 @@
<hhmemb>2</hhmemb>
<age2>32</age2>
<sex2>M</sex2>
<ecstat2>5</ecstat2>
<ecstat2>6</ecstat2>
<age3/>
<sex3/>
<ecstat3/>

62
spec/models/validations/household_validations_spec.rb

@ -296,6 +296,8 @@ RSpec.describe Validations::HouseholdValidations do
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["relat2"])
.to include(match I18n.t("validations.household.relat.child_under_16", person_num: 2))
expect(record.errors["age2"])
.to include(match I18n.t("validations.household.age.child_under_16_relat", person_num: 2))
end
it "expects that person is a child of the tenant" do
@ -303,6 +305,7 @@ RSpec.describe Validations::HouseholdValidations do
record.relat2 = 1
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["relat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "validates that person's economic status must be Child" do
@ -311,13 +314,27 @@ RSpec.describe Validations::HouseholdValidations do
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["ecstat2"])
.to include(match I18n.t("validations.household.ecstat.child_under_16", person_num: 2))
expect(record.errors["age2"])
.to include(match I18n.t("validations.household.age.child_under_16", person_num: 2))
end
it "expects that person's economic status is Child" do
record.age2 = 14
record.ecstat2 = 8
record.ecstat2 = 9
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "validates that a person with economic status 'child' must be under 16" do
record.age2 = 21
record.relat2 = 1
record.ecstat2 = 9
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["ecstat2"])
.to include(match I18n.t("validations.household.ecstat.child_over_16", person_num: 2))
expect(record.errors["age2"])
.to include(match I18n.t("validations.household.age.child_over_16", person_num: 2))
end
end
@ -329,14 +346,20 @@ RSpec.describe Validations::HouseholdValidations do
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["ecstat2"])
.to include(match I18n.t("validations.household.ecstat.student_16_19", person_num: 2))
expect(record.errors["age2"])
.to include(match I18n.t("validations.household.age.student_16_19", person_num: 2))
expect(record.errors["relat2"])
.to include(match I18n.t("validations.household.relat.student_16_19", person_num: 2))
end
it "expects that person can be a full time student" do
record.age2 = 17
record.relat2 = 1
record.ecstat2 = 6
record.ecstat2 = 7
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
expect(record.errors["relat2"]).to be_empty
end
it "expects that person can refuse to share their work status" do
@ -345,6 +368,8 @@ RSpec.describe Validations::HouseholdValidations do
record.ecstat2 = 10
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
expect(record.errors["relat2"]).to be_empty
end
end
@ -355,13 +380,24 @@ RSpec.describe Validations::HouseholdValidations do
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["ecstat2"])
.to include(match I18n.t("validations.household.ecstat.retired_over_70", person_num: 2))
expect(record.errors["age2"])
.to include(match I18n.t("validations.household.age.retired_over_70", person_num: 2))
end
it "expects that person is retired" do
it "expects that person under 70 does not need to be retired" do
record.age2 = 50
record.ecstat2 = 1
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "expects that person over 70 is retired" do
record.age2 = 71
record.ecstat2 = 5
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
end
@ -369,19 +405,25 @@ RSpec.describe Validations::HouseholdValidations do
it "validates that person must be over 65" do
record.age2 = 64
record.sex2 = "M"
record.ecstat2 = 4
record.ecstat2 = 5
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["age2"])
.to include(match I18n.t("validations.household.age.retired_male"))
expect(record.errors["sex2"])
.to include(match I18n.t("validations.household.gender.retired_male"))
expect(record.errors["ecstat2"])
.to include(match I18n.t("validations.household.ecstat.retired_male"))
end
it "expects that person is over 65" do
record.age2 = 66
record.sex2 = "M"
record.ecstat2 = 4
record.ecstat2 = 5
household_validator.validate_household_number_of_other_members(record)
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["sex2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "validates that the number of other household members cannot be less than 0" do
@ -409,19 +451,25 @@ RSpec.describe Validations::HouseholdValidations do
it "validates that person must be over 60" do
record.age2 = 59
record.sex2 = "F"
record.ecstat2 = 4
record.ecstat2 = 5
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["age2"])
.to include(match I18n.t("validations.household.age.retired_female"))
expect(record.errors["sex2"])
.to include(match I18n.t("validations.household.gender.retired_female"))
expect(record.errors["ecstat2"])
.to include(match I18n.t("validations.household.ecstat.retired_female"))
end
it "expects that person is over 60" do
record.age2 = 61
record.sex2 = "F"
record.ecstat2 = 4
record.ecstat2 = 5
household_validator.validate_household_number_of_other_members(record)
household_validator.validate_household_number_of_other_members(record)
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["sex2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
end
end

Loading…
Cancel
Save