From f0bf950abe9d692207c57bde36fe057c1e2a1f16 Mon Sep 17 00:00:00 2001 From: samyou-softwire Date: Wed, 1 Apr 2026 13:58:35 +0100 Subject: [PATCH 1/5] CLDC-4250: Add a new validation for universal credit and household income sources --- app/models/lettings_log.rb | 21 +++++++------------ .../validations/financial_validations.rb | 9 ++++++++ .../validations/lettings/financial.en.yml | 3 +++ 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb index 0ac9f728d..2e6b800eb 100644 --- a/app/models/lettings_log.rb +++ b/app/models/lettings_log.rb @@ -542,7 +542,7 @@ class LettingsLog < Log reason == 1 end - def receives_housing_benefit_only? + def receives_housing_benefit? # 1: Housing benefit hb == 1 end @@ -551,13 +551,7 @@ class LettingsLog < Log hb == 3 end - # Option 8 has been removed starting from 22/23 - def receives_housing_benefit_and_universal_credit? - # 8: Housing benefit and Universal Credit (without housing element) - hb == 8 - end - - def receives_uc_with_housing_element_excl_housing_benefit? + def receives_universal_credit # 6: Universal Credit with housing element (excluding housing benefit) hb == 6 end @@ -572,12 +566,11 @@ class LettingsLog < Log end def receives_housing_related_benefits? - if collection_start_year <= 2021 - receives_housing_benefit_only? || receives_uc_with_housing_element_excl_housing_benefit? || - receives_housing_benefit_and_universal_credit? - else - receives_housing_benefit_only? || receives_uc_with_housing_element_excl_housing_benefit? - end + receives_housing_benefit? || receives_universal_credit + end + + def no_household_income_comes_from_benefits? + benefits == 3 end def local_housing_referral? diff --git a/app/models/validations/financial_validations.rb b/app/models/validations/financial_validations.rb index 3dd6890be..82a5550f4 100644 --- a/app/models/validations/financial_validations.rb +++ b/app/models/validations/financial_validations.rb @@ -175,6 +175,15 @@ module Validations::FinancialValidations end end + def validate_housing_universal_credit_matches_income_proportion(record) + return unless record.hb && record.benefits && record.form.start_year_2026_or_later? + + if record.receives_universal_credit && record.no_household_income_comes_from_benefits? + record.errors.add :hb, I18n.t("validations.lettings.financial.hb.benefits_received_not_match_income_source") + record.errors.add :benefits, I18n.t("validations.lettings.financial.benefits.benefits_received_not_match_income_source") + end + end + private def validate_charges(record) diff --git a/config/locales/validations/lettings/financial.en.yml b/config/locales/validations/lettings/financial.en.yml index d91610602..bc731d696 100644 --- a/config/locales/validations/lettings/financial.en.yml +++ b/config/locales/validations/lettings/financial.en.yml @@ -12,6 +12,7 @@ en: outstanding_amount_not_expected: "Answer must be ‘yes’ as you have answered the outstanding amount question." 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." + benefits_received_not_match_income_source: "You answered that none of the household’s income is from Universal Credit, state pensions or benefits, but also that the tenant is likely to be receiving Universal Credit." earnings: 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." @@ -87,3 +88,5 @@ en: needstype: rent_below_hard_min: "Rent is below the absolute minimum expected for a property of this type based on this lettings type." rent_above_hard_max: "Rent is higher than the absolute maximum expected for a property of this type based on this lettings type." + hb: + benefits_received_not_match_income_source: "You answered that none of the household’s income is from Universal Credit, state pensions or benefits, but also that the tenant is likely to be receiving Universal Credit." From b08f2217417fa807ebcbf99a42cc7d5096367a27 Mon Sep 17 00:00:00 2001 From: samyou-softwire Date: Wed, 1 Apr 2026 15:19:46 +0100 Subject: [PATCH 2/5] CLDC-4250: Add verifying tests --- .../validations/financial_validations_spec.rb | 94 ++++++++++++++++++- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/spec/models/validations/financial_validations_spec.rb b/spec/models/validations/financial_validations_spec.rb index 14e2dfd0c..9f976fe67 100644 --- a/spec/models/validations/financial_validations_spec.rb +++ b/spec/models/validations/financial_validations_spec.rb @@ -5,11 +5,6 @@ RSpec.describe Validations::FinancialValidations do let(:validator_class) { Class.new { include Validations::FinancialValidations } } let(:record) { FactoryBot.create(:lettings_log) } - let(:fake_2021_2022_form) { Form.new("spec/fixtures/forms/2021_2022.json") } - - before do - allow(FormHandler.instance).to receive(:current_lettings_form).and_return(fake_2021_2022_form) - end describe "earnings and income frequency" do it "when earnings are provided it validates that income frequency must be provided" do @@ -1234,4 +1229,93 @@ RSpec.describe Validations::FinancialValidations do end end end + + describe "universal credit and income sources validations" do + before do + record.hb = hb + record.benefits = benefits + end + + context "with a 2025 form", metadata: { year: 25 } do + before do + allow(record.form).to receive(:start_year_2026_or_later?).and_return(false) + end + + context "when tenant receives universal credit and no household income comes from benefits" do + let(:hb) { 6 } + let(:benefits) { 3 } + + it "adds errors to hb and benefits" do + financial_validator.validate_housing_universal_credit_matches_income_proportion(record) + expect(record.errors["hb"]).to be_empty + expect(record.errors["benefits"]).to be_empty + end + end + end + + context "with a 2026 form", metadata: { year: 26 } do + before do + allow(record.form).to receive(:start_year_2026_or_later?).and_return(true) + end + + context "when tenant receives universal credit and no household income comes from benefits" do + let(:hb) { 6 } + let(:benefits) { 3 } + + it "adds errors to hb and benefits" do + financial_validator.validate_housing_universal_credit_matches_income_proportion(record) + expect(record.errors["hb"]).to include(match I18n.t("validations.lettings.financial.hb.benefits_received_not_match_income_source")) + expect(record.errors["benefits"]).to include(match I18n.t("validations.lettings.financial.benefits.benefits_received_not_match_income_source")) + end + end + + context "when tenant receives universal credit and some household income comes from benefits" do + let(:hb) { 6 } + let(:benefits) { 2 } + + it "does not add errors" do + financial_validator.validate_housing_universal_credit_matches_income_proportion(record) + expect(record.errors["hb"]).to be_empty + expect(record.errors["benefits"]).to be_empty + end + end + + context "when tenant receives housing benefit and no household income comes from benefits" do + let(:hb) { 1 } + let(:benefits) { 3 } + + it "does not add errors" do + financial_validator.validate_housing_universal_credit_matches_income_proportion(record) + expect(record.errors["hb"]).to be_empty + expect(record.errors["benefits"]).to be_empty + end + end + + context "when hb is not set" do + let(:hb) { nil } + let(:benefits) { 3 } + + it "does not add errors" do + record.hb = nil + record.benefits = 3 + financial_validator.validate_housing_universal_credit_matches_income_proportion(record) + expect(record.errors["hb"]).to be_empty + expect(record.errors["benefits"]).to be_empty + end + end + + context "when benefits is not set" do + let(:hb) { 6 } + let(:benefits) { nil } + + it "does not add errors" do + record.hb = 6 + record.benefits = nil + financial_validator.validate_housing_universal_credit_matches_income_proportion(record) + expect(record.errors["hb"]).to be_empty + expect(record.errors["benefits"]).to be_empty + end + end + end + end end From 6f63b6b2fb4cc25d70e4e8c604828f5553cfa44d Mon Sep 17 00:00:00 2001 From: samyou-softwire Date: Wed, 1 Apr 2026 15:29:08 +0100 Subject: [PATCH 3/5] CLDC-4250: Add a post release script --- .../update_logs_with_invalid_hb_benefits_2026.rake | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 lib/tasks/update_logs_with_invalid_hb_benefits_2026.rake diff --git a/lib/tasks/update_logs_with_invalid_hb_benefits_2026.rake b/lib/tasks/update_logs_with_invalid_hb_benefits_2026.rake new file mode 100644 index 000000000..4770db96a --- /dev/null +++ b/lib/tasks/update_logs_with_invalid_hb_benefits_2026.rake @@ -0,0 +1,10 @@ +desc "For logs that fail the validate_housing_universal_credit_matches_income_proportion check created before we released it, clear the answer to the question" +task update_logs_with_invalid_hb_benefits_2026: :environment do + impacted_logs = LettingsLog.filter_by_year(2026).where(hb: 6, benefits: 3) + + puts "#{impacted_logs.count} logs will be updated #{impacted_logs.map(&:id)}" + + impacted_logs.update!(benefits: nil, hb: nil) + + puts "Done" +end From 066a3adaf69939769426ac240c73da7735402e7f Mon Sep 17 00:00:00 2001 From: samyou-softwire Date: Thu, 2 Apr 2026 15:18:30 +0100 Subject: [PATCH 4/5] fixup! CLDC-4250: Add verifying tests remove unneeded setup --- spec/models/validations/financial_validations_spec.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/spec/models/validations/financial_validations_spec.rb b/spec/models/validations/financial_validations_spec.rb index 9f976fe67..24db9719c 100644 --- a/spec/models/validations/financial_validations_spec.rb +++ b/spec/models/validations/financial_validations_spec.rb @@ -1296,8 +1296,6 @@ RSpec.describe Validations::FinancialValidations do let(:benefits) { 3 } it "does not add errors" do - record.hb = nil - record.benefits = 3 financial_validator.validate_housing_universal_credit_matches_income_proportion(record) expect(record.errors["hb"]).to be_empty expect(record.errors["benefits"]).to be_empty @@ -1309,8 +1307,6 @@ RSpec.describe Validations::FinancialValidations do let(:benefits) { nil } it "does not add errors" do - record.hb = 6 - record.benefits = nil financial_validator.validate_housing_universal_credit_matches_income_proportion(record) expect(record.errors["hb"]).to be_empty expect(record.errors["benefits"]).to be_empty From a00239b3c790daf750ce2b77e82ec2a8e87a082b Mon Sep 17 00:00:00 2001 From: samyou-softwire Date: Thu, 2 Apr 2026 15:19:24 +0100 Subject: [PATCH 5/5] fixup! CLDC-4250: Add verifying tests fix test name --- spec/models/validations/financial_validations_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/validations/financial_validations_spec.rb b/spec/models/validations/financial_validations_spec.rb index 24db9719c..358cbeaf1 100644 --- a/spec/models/validations/financial_validations_spec.rb +++ b/spec/models/validations/financial_validations_spec.rb @@ -1245,7 +1245,7 @@ RSpec.describe Validations::FinancialValidations do let(:hb) { 6 } let(:benefits) { 3 } - it "adds errors to hb and benefits" do + it "does not add errors" do financial_validator.validate_housing_universal_credit_matches_income_proportion(record) expect(record.errors["hb"]).to be_empty expect(record.errors["benefits"]).to be_empty