From c5e3680b27b49a564e6789e238604967e0d80db3 Mon Sep 17 00:00:00 2001 From: Rachael Booth Date: Tue, 23 Jan 2024 12:08:08 +0000 Subject: [PATCH] CLDC-3110: Base income validations on all tenants for lettings logs (#2136) * CLDC-3110: Update hard max income for ecstat 8 to 2000 * CLDC-3110: Update hard max income for ecstat 10 to match new highest max * CLDC-3110: Base income validations on all tenants for lettings logs * CLDC-3110: Tweak validation messages * CLDC-3110: Use prefer not to say values when tenant ecstat is not specified --- .../lettings/pages/net_income_value_check.rb | 2 +- app/models/lettings_log.rb | 18 +++- .../validations/financial_validations.rb | 36 +++++++- app/models/validations/soft_validations.rb | 8 +- config/locales/en.yml | 21 +++-- spec/factories/lettings_log.rb | 5 +- .../check_answers_page_lettings_logs_spec.rb | 1 + spec/features/form/validations_spec.rb | 7 +- spec/fixtures/exports/general_needs_log.xml | 2 +- .../exports/general_needs_log_23_24.xml | 2 +- .../exports/supported_housing_logs.xml | 2 +- .../files/lettings_log_csv_export_codes.csv | 2 +- .../files/lettings_log_csv_export_labels.csv | 2 +- ...tings_log_csv_export_non_support_codes.csv | 2 +- ...ings_log_csv_export_non_support_labels.csv | 2 +- spec/helpers/check_answers_helper_spec.rb | 2 +- .../interruption_screen_helper_spec.rb | 1 + spec/models/form/subsection_spec.rb | 2 +- spec/models/form_spec.rb | 1 + spec/models/lettings_log_spec.rb | 32 +++++++ .../validations/financial_validations_spec.rb | 84 ++++++++++++++++++- .../lettings/year2022/row_parser_spec.rb | 2 +- .../lettings/year2023/row_parser_spec.rb | 2 +- 23 files changed, 201 insertions(+), 37 deletions(-) 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",