diff --git a/app/models/form/lettings/pages/net_income_value_check.rb b/app/models/form/lettings/pages/net_income_value_check.rb
index f5ffd78c1..ccb2b2a08 100644
--- a/app/models/form/lettings/pages/net_income_value_check.rb
+++ b/app/models/form/lettings/pages/net_income_value_check.rb
@@ -36,6 +36,6 @@ class Form::Lettings::Pages::NetIncomeValueCheck < ::Form::Page
end
def interruption_screen_question_ids
- %w[incfreq earnings ecstat1]
+ %w[incfreq earnings hhmemb ecstat1 age2 ecstat2 age3 ecstat3 age4 ecstat4 age5 ecstat5 age6 ecstat6 age7 ecstat7 age8 ecstat8]
end
end
diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb
index 3eda732d1..8ebf8092f 100644
--- a/app/models/lettings_log.rb
+++ b/app/models/lettings_log.rb
@@ -214,9 +214,23 @@ class LettingsLog < Log
end
def applicable_income_range
- return unless ecstat1
+ return unless ecstat1 && hhmemb
- ALLOWED_INCOME_RANGES[ecstat1]
+ range = ALLOWED_INCOME_RANGES[ecstat1].clone
+
+ if hhmemb > 1
+ (2..hhmemb).each do |person_index|
+ ecstat = self["ecstat#{person_index}"] || 10
+
+ person_range = ALLOWED_INCOME_RANGES[ecstat]
+ range.soft_min += person_range.soft_min
+ range.hard_min += person_range.hard_min
+ range.soft_max += person_range.soft_max
+ range.hard_max += person_range.hard_max
+ end
+ end
+
+ range
end
def first_time_property_let_as_social_housing?
diff --git a/app/models/validations/financial_validations.rb b/app/models/validations/financial_validations.rb
index eb66de861..a1d799624 100644
--- a/app/models/validations/financial_validations.rb
+++ b/app/models/validations/financial_validations.rb
@@ -24,29 +24,57 @@ module Validations::FinancialValidations
end
def validate_net_income(record)
- if record.ecstat1 && record.weekly_net_income
+ if record.ecstat1 && record.hhmemb && record.weekly_net_income
if record.weekly_net_income > record.applicable_income_range.hard_max
- hard_max = format_as_currency(record.applicable_income_range.hard_max)
frequency = record.form.get_question("incfreq", record).label_from_value(record.incfreq).downcase
+ hard_max = format_as_currency(record.applicable_income_range.hard_max)
record.errors.add(
:earnings,
:over_hard_max,
message: I18n.t("validations.financial.earnings.over_hard_max", hard_max:),
)
record.errors.add(
- :ecstat1,
+ :hhmemb,
:over_hard_max,
- message: I18n.t("validations.financial.ecstat.over_hard_max", earnings: format_as_currency(record.earnings), frequency:),
+ message: I18n.t("validations.financial.hhmemb.earnings.over_hard_max", earnings: format_as_currency(record.earnings), frequency:),
)
+ (1..record.hhmemb).each do |n|
+ record.errors.add(
+ "ecstat#{n}",
+ :over_hard_max,
+ message: I18n.t("validations.financial.ecstat.over_hard_max", earnings: format_as_currency(record.earnings), frequency:),
+ )
+ next unless record["ecstat#{n}"] == 9
+
+ record.errors.add(
+ "age#{n}",
+ :over_hard_max,
+ message: I18n.t("validations.financial.age.earnings_over_hard_max", earnings: format_as_currency(record.earnings), frequency:),
+ )
+ end
end
if record.weekly_net_income < record.applicable_income_range.hard_min
hard_min = format_as_currency(record.applicable_income_range.hard_min)
+ frequency = record.form.get_question("incfreq", record).label_from_value(record.incfreq).downcase
record.errors.add(
:earnings,
:under_hard_min,
message: I18n.t("validations.financial.earnings.under_hard_min", hard_min:),
)
+ record.errors.add(
+ :hhmemb,
+ :under_hard_min,
+ message: I18n.t("validations.financial.hhmemb.earnings.under_hard_min", earnings: format_as_currency(record.earnings), frequency:),
+ )
+ (1..record.hhmemb).each do |n|
+ record.errors.add(
+ "ecstat#{n}",
+ :under_hard_min,
+ message: I18n.t("validations.financial.ecstat.under_hard_min", earnings: format_as_currency(record.earnings), frequency:),
+ )
+ # N.B. It is not possible for a change to an age field to increase the hard min
+ end
end
end
diff --git a/app/models/validations/soft_validations.rb b/app/models/validations/soft_validations.rb
index 5720c0f0d..92685afe0 100644
--- a/app/models/validations/soft_validations.rb
+++ b/app/models/validations/soft_validations.rb
@@ -7,20 +7,20 @@ module Validations::SoftValidations
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),
+ 8 => OpenStruct.new(soft_min: 54, soft_max: 460, hard_min: 10, hard_max: 2000),
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),
+ 10 => OpenStruct.new(soft_min: 47, soft_max: 730, hard_min: 10, hard_max: 2000),
}.freeze
def net_income_in_soft_max_range?
- return unless weekly_net_income && ecstat1
+ return unless weekly_net_income && ecstat1 && hhmemb
weekly_net_income.between?(applicable_income_range.soft_max, applicable_income_range.hard_max)
end
def net_income_in_soft_min_range?
- return unless weekly_net_income && ecstat1
+ return unless weekly_net_income && ecstat1 && hhmemb
weekly_net_income.between?(applicable_income_range.hard_min, applicable_income_range.soft_min)
end
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 5a9c635be..862528021 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -361,8 +361,8 @@ en:
benefits:
part_or_full_time: "Answer cannot be ‘all’ for income from Universal Credit, state pensions or benefits if the tenant or their partner works part-time or full-time"
earnings:
- over_hard_max: "Net income cannot be greater than %{hard_max} per week given the tenant’s working situation"
- under_hard_min: "Net income cannot be less than %{hard_min} per week given the tenant’s working situation"
+ over_hard_max: "The household’s income cannot be greater than %{hard_max} per week given the household’s working situation"
+ under_hard_min: "The household’s income cannot be less than %{hard_min} per week given the household’s working situation"
freq_missing: "Select how often the household receives income"
earnings_missing: "Enter how much income the household has in total"
income:
@@ -376,7 +376,14 @@ en:
less_than_shortfall: "Enter an amount that is more than the shortfall in basic rent"
out_of_range: "Enter a value for the %{charge_name} between £0 and %{maximum_per_period} paid %{frequency}. %{maximum_per_period} is the max limit for rent and charges paid %{frequency} for %{letting_type} lettings owned by a %{provider_type}."
ecstat:
- over_hard_max: "Net income of %{earnings} %{frequency} is too high given the tenant’s working situation"
+ over_hard_max: "The household’s income of %{earnings} %{frequency} is too high given the household’s working situation"
+ under_hard_min: "The household’s income of %{earnings} %{frequency} is too low given the household’s working situation"
+ age:
+ earnings_over_hard_max: "The household’s income of %{earnings} %{frequency} is too high for the number of adults. Change either the household income or the age of the tenants."
+ hhmemb:
+ earnings:
+ over_hard_max: "The household’s income of %{earnings} %{frequency} is too high for this number of tenants. Change either the household income or number of tenants."
+ under_hard_min: "The household’s income of %{earnings} %{frequency} is too low for this number of tenants. Change either the household income or number of tenants."
brent:
below_hard_min: "Rent is below the absolute minimum expected for a property of this type. Please check the rent, rent period, local authority and (if general needs) number of bedrooms"
above_hard_max: "Rent is higher than the absolute maximum expected for a property of this type. Please check the rent, rent period, local authority and (if general needs) number of bedrooms"
@@ -610,12 +617,12 @@ en:
soft_validations:
net_income:
- title_text: "You told us the lead tenant’s income is %{earnings} %{incfreq}."
- hint_text: "This is %{net_income_higher_or_lower_text} than we would expect for their working situation."
+ title_text: "You told us that the household’s income is %{earnings} %{incfreq}"
+ hint_text: "This is %{net_income_higher_or_lower_text} than we would expect for the household’s working situation."
in_soft_min_range:
- message: "Net income is lower than expected based on the lead tenant’s working situation. Are you sure this is correct?"
+ message: "Net income is lower than expected based on the household’s working situation. Are you sure this is correct?"
in_soft_max_range:
- message: "Net income is higher than expected based on the lead tenant’s working situation. Are you sure this is correct?"
+ message: "Net income is higher than expected based on the household’s working situation. Are you sure this is correct?"
income:
under_soft_min_for_economic_status:
title_text: "You told us income was %{income}."
diff --git a/spec/factories/lettings_log.rb b/spec/factories/lettings_log.rb
index f01d6b4a4..f0493fc2d 100644
--- a/spec/factories/lettings_log.rb
+++ b/spec/factories/lettings_log.rb
@@ -16,6 +16,7 @@ FactoryBot.define do
tenancycode { Faker::Name.initials(number: 10) }
postcode_full { Faker::Address.postcode }
ppostcode_full { Faker::Address.postcode }
+ hhmemb { 2 }
age1 { 17 }
age2 { 19 }
renewal { 1 }
@@ -24,6 +25,7 @@ FactoryBot.define do
end
trait :soft_validations_triggered do
status { 1 }
+ hhmemb { 1 }
ecstat1 { 1 }
earnings { 750 }
incfreq { 1 }
@@ -47,6 +49,7 @@ FactoryBot.define do
age1_known { 0 }
age1 { 18 }
sex1 { "M" }
+ hhmemb { 1 }
ecstat1 { 0 }
period { 2 }
brent { 200 }
@@ -92,7 +95,7 @@ FactoryBot.define do
voiddate { 2.days.ago }
offered { 2 }
wchair { 1 }
- earnings { 68 }
+ earnings { 268 }
incfreq { 1 }
benefits { 1 }
period { 2 }
diff --git a/spec/features/form/check_answers_page_lettings_logs_spec.rb b/spec/features/form/check_answers_page_lettings_logs_spec.rb
index 9ff419f93..f45854b4f 100644
--- a/spec/features/form/check_answers_page_lettings_logs_spec.rb
+++ b/spec/features/form/check_answers_page_lettings_logs_spec.rb
@@ -244,6 +244,7 @@ RSpec.describe "Lettings Log Check Answers Page" do
created_by: user,
needstype: 1,
tenancycode: nil,
+ hhmemb: nil,
age1: nil,
layear: 2,
waityear: 1,
diff --git a/spec/features/form/validations_spec.rb b/spec/features/form/validations_spec.rb
index a3a5b9bc2..c674ea839 100644
--- a/spec/features/form/validations_spec.rb
+++ b/spec/features/form/validations_spec.rb
@@ -131,6 +131,7 @@ RSpec.describe "validations" do
FactoryBot.create(
:lettings_log,
:in_progress,
+ hhmemb: 1,
ecstat1: 1,
created_by: user,
)
@@ -147,8 +148,8 @@ RSpec.describe "validations" do
it "prompts the user to confirm the value is correct with an interruption screen" do
expect(page).to have_current_path("/lettings-logs/#{lettings_log.id}/net-income-value-check")
- expect(page).to have_content("You told us the lead tenant’s income is £750.00 weekly.")
- expect(page).to have_content("This is higher than we would expect for their working situation.")
+ expect(page).to have_content("You told us that the household’s income is £750.00 weekly")
+ expect(page).to have_content("This is higher than we would expect for the household’s working situation.")
expect(page).not_to have_button("Save changes")
click_button("Confirm and continue")
expect(page).to have_current_path("/lettings-logs/#{lettings_log.id}/net-income-uc-proportion")
@@ -165,7 +166,7 @@ RSpec.describe "validations" do
choose("lettings-log-incfreq-1-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{lettings_log.id}/net-income-value-check")
- expect(page).not_to have_content("You told us the lead tenant’s income is £750.00 weekly.")
+ expect(page).not_to have_content("You told us that the household’s income is £750.00 weekly")
expect(page).to have_css(".govuk-notification-banner.govuk-notification-banner--success")
end
diff --git a/spec/fixtures/exports/general_needs_log.xml b/spec/fixtures/exports/general_needs_log.xml
index fe7985668..79e904dcf 100644
--- a/spec/fixtures/exports/general_needs_log.xml
+++ b/spec/fixtures/exports/general_needs_log.xml
@@ -46,7 +46,7 @@
3
2
1
- 68
+ 268
1
1
2
diff --git a/spec/fixtures/exports/general_needs_log_23_24.xml b/spec/fixtures/exports/general_needs_log_23_24.xml
index ab4871a94..a1b53162d 100644
--- a/spec/fixtures/exports/general_needs_log_23_24.xml
+++ b/spec/fixtures/exports/general_needs_log_23_24.xml
@@ -46,7 +46,7 @@
3
2
1
- 68
+ 268
1
1
2
diff --git a/spec/fixtures/exports/supported_housing_logs.xml b/spec/fixtures/exports/supported_housing_logs.xml
index c05f2c76a..bc80fd49b 100644
--- a/spec/fixtures/exports/supported_housing_logs.xml
+++ b/spec/fixtures/exports/supported_housing_logs.xml
@@ -45,7 +45,7 @@
2
2
- 68
+ 268
1
1
2
diff --git a/spec/fixtures/files/lettings_log_csv_export_codes.csv b/spec/fixtures/files/lettings_log_csv_export_codes.csv
index aa3a23a09..cdd43809f 100644
--- a/spec/fixtures/files/lettings_log_csv_export_codes.csv
+++ b/spec/fixtures/files/lettings_log_csv_export_codes.csv
@@ -1,2 +1,2 @@
id,status,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,rent_type_detail,irproduct,irproduct_other,lar,tenancycode,propcode,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
-,completed,s.port@jeemayle.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-06-26,2,1,1,,2,HIJKLMN,ABCDEFG,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-06-24,,,1,2023-06-25,,3,1,4,,2,,1,4,,1,4,0,0,2,35,,F,0,2,13,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,,2,,0,0,68,1,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,,
+,completed,s.port@jeemayle.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-06-26,2,1,1,,2,HIJKLMN,ABCDEFG,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-06-24,,,1,2023-06-25,,3,1,4,,2,,1,4,,1,4,0,0,2,35,,F,0,2,13,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,,2,,0,0,268,1,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,,
diff --git a/spec/fixtures/files/lettings_log_csv_export_labels.csv b/spec/fixtures/files/lettings_log_csv_export_labels.csv
index b6120916d..7d76b9a36 100644
--- a/spec/fixtures/files/lettings_log_csv_export_labels.csv
+++ b/spec/fixtures/files/lettings_log_csv_export_labels.csv
@@ -1,2 +1,2 @@
id,status,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,rent_type_detail,irproduct,irproduct_other,lar,tenancycode,propcode,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
-,completed,s.port@jeemayle.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-06-26,2,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-06-24,,,Yes,2023-06-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,Yes,No,68,Weekly,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,,
+,completed,s.port@jeemayle.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-06-26,2,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-06-24,,,Yes,2023-06-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,Yes,No,268,Weekly,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,,
diff --git a/spec/fixtures/files/lettings_log_csv_export_non_support_codes.csv b/spec/fixtures/files/lettings_log_csv_export_non_support_codes.csv
index 3e92a556b..9fedc109d 100644
--- a/spec/fixtures/files/lettings_log_csv_export_non_support_codes.csv
+++ b/spec/fixtures/files/lettings_log_csv_export_non_support_codes.csv
@@ -1,2 +1,2 @@
id,status,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,rent_type_detail,irproduct,irproduct_other,lar,tenancycode,propcode,uprn_known,uprn,address_line1,address_line2,town_or_city,county,postcode_full,la_label,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,refused,age1,sex1,ethnic_group,ethnic,national,ecstat1,relat2,age2,sex2,ecstat2,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,relat7,age7,sex7,ecstat7,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,homeless,ppcodenk,ppostcode_full,prevloc_label,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,incref,earnings,incfreq,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,scharge,pscharge,supcharg,tcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
-,completed,choreographer@owtluk.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,1,2023,DLUHC,DLUHC,1,7,0,2023-06-26,2,1,1,,2,HIJKLMN,ABCDEFG,0,,fake address,,London,,NW9 5LL,Barnet,2,6,2,2,7,1,1,3,2023-06-24,1,,1,2023-06-25,,3,1,4,,2,,1,4,1,35,F,0,2,13,0,P,32,M,6,R,-9,R,10,R,-9,R,10,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,6,1,0,TN23 6LZ,Ashford,1,0,1,0,0,0,0,0,1,,2,,0,68,1,6,1,1,,0,2,,,,,200.0,50.0,40.0,35.0,325.0,,,,1,12.0,,,,,,,,,,,,,,,,,,,,
+,completed,choreographer@owtluk.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,1,2023,DLUHC,DLUHC,1,7,0,2023-06-26,2,1,1,,2,HIJKLMN,ABCDEFG,0,,fake address,,London,,NW9 5LL,Barnet,2,6,2,2,7,1,1,3,2023-06-24,1,,1,2023-06-25,,3,1,4,,2,,1,4,1,35,F,0,2,13,0,P,32,M,6,R,-9,R,10,R,-9,R,10,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,6,1,0,TN23 6LZ,Ashford,1,0,1,0,0,0,0,0,1,,2,,0,268,1,6,1,1,,0,2,,,,,200.0,50.0,40.0,35.0,325.0,,,,1,12.0,,,,,,,,,,,,,,,,,,,,
diff --git a/spec/fixtures/files/lettings_log_csv_export_non_support_labels.csv b/spec/fixtures/files/lettings_log_csv_export_non_support_labels.csv
index 50682d2bf..563a231b6 100644
--- a/spec/fixtures/files/lettings_log_csv_export_non_support_labels.csv
+++ b/spec/fixtures/files/lettings_log_csv_export_non_support_labels.csv
@@ -1,2 +1,2 @@
id,status,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,rent_type_detail,irproduct,irproduct_other,lar,tenancycode,propcode,uprn_known,uprn,address_line1,address_line2,town_or_city,county,postcode_full,la_label,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,refused,age1,sex1,ethnic_group,ethnic,national,ecstat1,relat2,age2,sex2,ecstat2,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,relat7,age7,sex7,ecstat7,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,homeless,ppcodenk,ppostcode_full,prevloc_label,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,incref,earnings,incfreq,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,scharge,pscharge,supcharg,tcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
-,completed,choreographer@owtluk.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,single log,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-06-26,2,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,No,,fake address,,London,,NW9 5LL,Barnet,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-06-24,1,,Yes,2023-06-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,Yes,35,Female,White,Irish,Tenant prefers not to say,Other,Partner,32,Male,Not seeking work,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,Other supported housing,No,Yes,TN23 6LZ,Ashford,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,No,68,Weekly,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,50.0,40.0,35.0,325.0,,,,Yes,12.0,,,,,,,,,,,,,,,,,,,,
+,completed,choreographer@owtluk.com,false,2023-06-26T00:00:00+01:00,,2023-06-26T00:00:00+01:00,single log,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-06-26,2,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,No,,fake address,,London,,NW9 5LL,Barnet,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-06-24,1,,Yes,2023-06-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,Yes,35,Female,White,Irish,Tenant prefers not to say,Other,Partner,32,Male,Not seeking work,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,Other supported housing,No,Yes,TN23 6LZ,Ashford,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,No,268,Weekly,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,50.0,40.0,35.0,325.0,,,,Yes,12.0,,,,,,,,,,,,,,,,,,,,
diff --git a/spec/helpers/check_answers_helper_spec.rb b/spec/helpers/check_answers_helper_spec.rb
index bc9382127..baa26ca44 100644
--- a/spec/helpers/check_answers_helper_spec.rb
+++ b/spec/helpers/check_answers_helper_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe CheckAnswersHelper do
context "when a section hasn't been completed yet" do
it "returns that you have unanswered questions" do
expect(display_answered_questions_summary(subsection, lettings_log, current_user))
- .to match(/You have answered 2 of 7 questions./)
+ .to match(/You have answered 4 of 10 questions./)
end
end
diff --git a/spec/helpers/interruption_screen_helper_spec.rb b/spec/helpers/interruption_screen_helper_spec.rb
index a100cf3ad..1604bcbb0 100644
--- a/spec/helpers/interruption_screen_helper_spec.rb
+++ b/spec/helpers/interruption_screen_helper_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe InterruptionScreenHelper do
create(
:lettings_log,
:in_progress,
+ hhmemb: 1,
ecstat1: 1,
earnings: 750,
incfreq: 1,
diff --git a/spec/models/form/subsection_spec.rb b/spec/models/form/subsection_spec.rb
index 3e224dd38..4cb430e39 100644
--- a/spec/models/form/subsection_spec.rb
+++ b/spec/models/form/subsection_spec.rb
@@ -84,7 +84,7 @@ RSpec.describe Form::Subsection, type: :model do
end
it "has question helpers for the number of applicable questions" do
- expected_questions = %w[tenancycode age1 sex1 ecstat1 hhmemb ecstat2 propcode]
+ expected_questions = %w[tenancycode age1 sex1 ecstat1 hhmemb relat2 age2 sex2 ecstat2 propcode]
expect(subsection.applicable_questions(lettings_log).map(&:id)).to eq(expected_questions)
end
end
diff --git a/spec/models/form_spec.rb b/spec/models/form_spec.rb
index 838b636dd..4370ee43c 100644
--- a/spec/models/form_spec.rb
+++ b/spec/models/form_spec.rb
@@ -26,6 +26,7 @@ RSpec.describe Form, type: :model do
context "when the current page is a value check page" do
before do
+ lettings_log.hhmemb = 1
lettings_log.incfreq = 1
lettings_log.earnings = 140
lettings_log.ecstat1 = 1
diff --git a/spec/models/lettings_log_spec.rb b/spec/models/lettings_log_spec.rb
index 1f128c8d7..1b641f452 100644
--- a/spec/models/lettings_log_spec.rb
+++ b/spec/models/lettings_log_spec.rb
@@ -3411,5 +3411,37 @@ RSpec.describe LettingsLog do
end
end
end
+
+ describe "#applicable_income_range" do
+ context "when ecstat for a non-lead tenant is not set" do
+ let(:lettings_log) { build(:lettings_log, hhmemb: 2, ecstat1: 1) }
+
+ it "uses the prefers-not-to-say values for that tenant to calculate the range" do
+ range = lettings_log.applicable_income_range
+ expected_range = OpenStruct.new(
+ soft_min: 143 + 47,
+ soft_max: 730 + 730,
+ hard_min: 90 + 10,
+ hard_max: 1230 + 2000,
+ )
+ expect(range).to eq(expected_range)
+ end
+ end
+
+ context "when ecstat for a non-lead tenant is set" do
+ let(:lettings_log) { build(:lettings_log, hhmemb: 2, ecstat1: 1, ecstat2: 2) }
+
+ it "uses the relevant income range values for that tenant to calculate the range" do
+ range = lettings_log.applicable_income_range
+ expected_range = OpenStruct.new(
+ soft_min: 143 + 67,
+ soft_max: 730 + 620,
+ hard_min: 90 + 50,
+ hard_max: 1230 + 950,
+ )
+ expect(range).to eq(expected_range)
+ end
+ end
+ end
end
# rubocop:enable RSpec/MessageChain
diff --git a/spec/models/validations/financial_validations_spec.rb b/spec/models/validations/financial_validations_spec.rb
index 1f9445489..1a6672e08 100644
--- a/spec/models/validations/financial_validations_spec.rb
+++ b/spec/models/validations/financial_validations_spec.rb
@@ -187,9 +187,10 @@ RSpec.describe Validations::FinancialValidations do
end
describe "net income validations" do
- it "validates that the net income is within the expected range for the tenant’s employment status" do
+ it "validates that the net income is within the expected range for the household’s employment status" do
record.earnings = 200
record.incfreq = 1
+ record.hhmemb = 1
record.ecstat1 = 1
financial_validator.validate_net_income(record)
expect(record.errors["earnings"]).to be_empty
@@ -199,12 +200,15 @@ RSpec.describe Validations::FinancialValidations do
it "adds an error" do
record.earnings = 5000
record.incfreq = 1
+ record.hhmemb = 1
record.ecstat1 = 1
financial_validator.validate_net_income(record)
expect(record.errors["earnings"])
- .to eq(["Net income cannot be greater than £1,230.00 per week given the tenant’s working situation"])
+ .to eq(["The household’s income cannot be greater than £1,230.00 per week given the household’s working situation"])
expect(record.errors["ecstat1"])
- .to eq(["Net income of £5,000.00 weekly is too high given the tenant’s working situation"])
+ .to eq(["The household’s income of £5,000.00 weekly is too high given the household’s working situation"])
+ expect(record.errors["hhmemb"])
+ .to eq(["The household’s income of £5,000.00 weekly is too high for this number of tenants. Change either the household income or number of tenants."])
end
end
@@ -212,10 +216,82 @@ RSpec.describe Validations::FinancialValidations do
it "adds an error" do
record.earnings = 50
record.incfreq = 1
+ record.hhmemb = 1
record.ecstat1 = 1
financial_validator.validate_net_income(record)
expect(record.errors["earnings"])
- .to eq(["Net income cannot be less than £90.00 per week given the tenant’s working situation"])
+ .to eq(["The household’s income cannot be less than £90.00 per week given the household’s working situation"])
+ expect(record.errors["ecstat1"])
+ .to eq(["The household’s income of £50.00 weekly is too low given the household’s working situation"])
+ expect(record.errors["hhmemb"])
+ .to eq(["The household’s income of £50.00 weekly is too low for this number of tenants. Change either the household income or number of tenants."])
+ end
+ end
+
+ context "when there is more than one household member" do
+ it "allows income levels based on all working situations combined" do
+ record.earnings = 5000
+ record.incfreq = 1
+ record.hhmemb = 4
+ record.ecstat1 = 1
+ record.ecstat2 = 1
+ record.ecstat3 = 8
+ record.ecstat4 = 9
+ financial_validator.validate_net_income(record)
+ expect(record.errors["earnings"]).to be_empty
+ end
+
+ it "uses the combined value in error messages" do
+ record.earnings = 100
+ record.incfreq = 1
+ record.hhmemb = 3
+ record.ecstat1 = 1
+ record.ecstat2 = 2
+ record.ecstat3 = 9
+ financial_validator.validate_net_income(record)
+ expect(record.errors["earnings"])
+ .to eq(["The household’s income cannot be less than £150.00 per week given the household’s working situation"])
+ end
+
+ it "adds errors to relevant fields for each tenant when income is too high" do
+ record.earnings = 5000
+ record.incfreq = 1
+ record.hhmemb = 3
+ record.ecstat1 = 1
+ record.ecstat2 = 2
+ record.age3 = 12
+ record.ecstat3 = 9
+ financial_validator.validate_net_income(record)
+ (1..record.hhmemb).each do |n|
+ expect(record.errors["ecstat#{n}"])
+ .to eq(["The household’s income of £5,000.00 weekly is too high given the household’s working situation"])
+ end
+ expect(record.errors["age1"]).to be_empty
+ expect(record.errors["age2"]).to be_empty
+ expect(record.errors["age3"])
+ .to eq(["The household’s income of £5,000.00 weekly is too high for the number of adults. Change either the household income or the age of the tenants."])
+ (record.hhmemb + 1..8).each do |n|
+ expect(record.errors["ecstat#{n}"]).to be_empty
+ expect(record.errors["age#{n}"]).to be_empty
+ end
+ end
+
+ it "adds errors to relevant fields for each tenant when income is too low" do
+ record.earnings = 50
+ record.incfreq = 1
+ record.hhmemb = 3
+ record.ecstat1 = 1
+ record.ecstat2 = 2
+ record.age3 = 12
+ record.ecstat3 = 9
+ financial_validator.validate_net_income(record)
+ (1..record.hhmemb).each do |n|
+ expect(record.errors["ecstat#{n}"])
+ .to eq(["The household’s income of £50.00 weekly is too low given the household’s working situation"])
+ end
+ (record.hhmemb + 1..8).each do |n|
+ expect(record.errors["ecstat#{n}"]).to be_empty
+ end
end
end
end
diff --git a/spec/services/bulk_upload/lettings/year2022/row_parser_spec.rb b/spec/services/bulk_upload/lettings/year2022/row_parser_spec.rb
index 9fdfab47d..a34cedbed 100644
--- a/spec/services/bulk_upload/lettings/year2022/row_parser_spec.rb
+++ b/spec/services/bulk_upload/lettings/year2022/row_parser_spec.rb
@@ -129,7 +129,7 @@ RSpec.describe BulkUpload::Lettings::Year2022::RowParser do
field_78: "2",
field_51: "1",
- field_50: "2000",
+ field_50: "2300",
field_116: "2",
field_48: "1",
field_49: "1",
diff --git a/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb b/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb
index 04044655d..cb816ef82 100644
--- a/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb
+++ b/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb
@@ -207,7 +207,7 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do
field_119: "2",
field_120: "1",
- field_122: "2000",
+ field_122: "2300",
field_121: "2",
field_123: "1",
field_124: "1",