diff --git a/changelog.d/2174.fixed.md b/changelog.d/2174.fixed.md new file mode 100644 index 0000000000..f65d91381d --- /dev/null +++ b/changelog.d/2174.fixed.md @@ -0,0 +1,2 @@ +- Count other investment income (National Savings, securities and trust interest) in `total_income`, which income tax already charges, so post-tax income and the Winter Fuel Payment income test see it. Housing Benefit and national Council Tax Reduction non-dependant deductions keep banding on income without it until the remunerative-work test is modelled (#2007) (#2174). +- Keep the Winter Fuel Payment for a pensioner whose total income is exactly £35,000: the winter fuel payment charge applies only where total income exceeds £35,000 (ITEPA 2003 s.681I(1)(b)). diff --git a/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/taxable_income_test/maximum_taxable_income.yaml b/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/taxable_income_test/maximum_taxable_income.yaml index 29e4138a20..78e8908217 100644 --- a/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/taxable_income_test/maximum_taxable_income.yaml +++ b/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/taxable_income_test/maximum_taxable_income.yaml @@ -1,4 +1,4 @@ -description: Households in England or Wales with pensioners earning under this amount of yearly taxable income are eligible for the Winter Fuel Payment. This stands in for the winter fuel payment charge, which recovers the payment from a person whose own total income exceeds £35,000 and who is not entitled to a relevant benefit. +description: Households in England or Wales with a pensioner whose total income is at or below this amount are eligible for the Winter Fuel Payment. This stands in for the winter fuel payment charge, which recovers the payment from a person whose own total income exceeds £35,000 and who is not entitled to a relevant benefit. values: 2000-01-01: 0 2025-01-01: diff --git a/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/taxable_income_test/use_maximum_taxable_income.yaml b/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/taxable_income_test/use_maximum_taxable_income.yaml index 594e55d980..bd6ee4612f 100644 --- a/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/taxable_income_test/use_maximum_taxable_income.yaml +++ b/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/taxable_income_test/use_maximum_taxable_income.yaml @@ -1,4 +1,4 @@ -description: When this is true, households in England or Wales with pensioners earning under the maximum taxable income are eligible for the Winter Fuel Payment. This stands in for the winter fuel payment charge on people with total income over £35,000 (ITEPA 2003 s.681I, from 2025-26). +description: When this is true, households in England or Wales with a pensioner whose total income is at or below the maximum taxable income are eligible for the Winter Fuel Payment. This stands in for the winter fuel payment charge on people with total income over £35,000 (ITEPA 2003 s.681I, from 2025-26). values: 2000-01-01: false 2025-01-01: true diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/non_dep_deduction/household_benefits_individual_non_dep_deduction.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/non_dep_deduction/household_benefits_individual_non_dep_deduction.yaml index 07e7c96efb..5d87d27d68 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/non_dep_deduction/household_benefits_individual_non_dep_deduction.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/non_dep_deduction/household_benefits_individual_non_dep_deduction.yaml @@ -36,3 +36,30 @@ total_income: 9_517 # just over 183 weekly, the lower edge of the second band output: household_benefits_individual_non_dep_deduction: 45.15 * 52 + +# Other investment income counts in total_income (ITA 2007 s. 23), but it is +# left out of the non-dependant band until the reg 74(2) remunerative-work +# test is modelled (#2007). Otherwise a non-worker whose only income is +# investment income would be banded on it, where reg 74(1)(b) gives them the +# minimum whatever their income. +- name: Other investment income does not band a non-worker + period: 2025 + input: + housing_benefit_individual_non_dep_deduction_eligible: true + other_investment_income: 28_912 # 556 weekly, no hours + output: + # The same as a non-dependant with no income. Banding the £556 would give + # 115.45 * 52 = 6,003.40. + household_benefits_individual_non_dep_deduction: 0 + +- name: Other investment income does not move a worker's band + period: 2025 + input: + housing_benefit_individual_non_dep_deduction_eligible: true + hours_worked: 1_950 # 37.5 hours a week + employment_income: 9_517 # just over 183 weekly + other_investment_income: 28_912 # 556 weekly + output: + # Banded on the £183 of earnings: 45.15 * 52 = 2,347.80. Adding the £556 + # would give the top band, 126.65 * 52 = 6,585.80. + household_benefits_individual_non_dep_deduction: 45.15 * 52 diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/non_dep_deduction/housing_benefit_non_dep_deductions.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/non_dep_deduction/housing_benefit_non_dep_deductions.yaml index 81d1b71bcb..8d5ed07037 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/non_dep_deduction/housing_benefit_non_dep_deductions.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/non_dep_deduction/housing_benefit_non_dep_deductions.yaml @@ -97,3 +97,32 @@ output: # Only person 3 is a non-dependant of the head's family: 3. housing_benefit_non_dep_deductions: [3, 0, 0] + +# The review case on #2184: an existing claimant in council housing with an +# adult child whose only income is £28,912 of other investment income and who +# does no paid work. The deduction is the same as for an adult child with no +# income; reg 74(1)(b) minimum for non-workers comes with #2007. +- name: A non-dependant's investment income does not raise the Housing Benefit deduction + period: 2025 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 40 + is_household_head: true + adult_child: + age: 25 + other_investment_income: 28_912 # 556 a week, no hours + benunits: + claimant_family: + members: [claimant] + adult_child_family: + members: [adult_child] + households: + household: + members: [claimant, adult_child] + tenure_type: RENT_FROM_COUNCIL + rent: 15_000 + output: + # Banding the £556 would give 115.45 * 52 = 6,003.40. + housing_benefit_non_dep_deductions: [0, 0] diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/winter_fuel_allowance.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/winter_fuel_allowance.yaml index ea2ebcccf7..4d6c77c229 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/winter_fuel_allowance.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/winter_fuel_allowance.yaml @@ -106,3 +106,58 @@ income_support: 80 output: winter_fuel_allowance: 200 + +# ITEPA 2003 s.681I(1)(b): the winter fuel payment charge applies only where +# total income "exceeds £35,000". The model stands in for the charge with the +# income test, so a pensioner with exactly £35,000 keeps the payment. Total +# income is built from pension and other investment income, not input. +- name: Pensioner with total income just under £35,000 keeps WFP + period: 2026 + absolute_error_margin: 1 + input: + age: 70 + country: ENGLAND + private_pension_income: 15_000 + other_investment_income: 19_999 + pension_credit: 0 + output: + total_income: 34_999 + winter_fuel_allowance: 200 + +- name: Pensioner with total income of exactly £35,000 keeps WFP + period: 2026 + absolute_error_margin: 1 + input: + age: 70 + country: ENGLAND + private_pension_income: 15_000 + other_investment_income: 20_000 + pension_credit: 0 + output: + total_income: 35_000 + winter_fuel_allowance: 200 + +- name: Pensioner with total income just over £35,000 loses WFP + period: 2026 + absolute_error_margin: 1 + input: + age: 70 + country: ENGLAND + private_pension_income: 15_000 + other_investment_income: 20_001 + pension_credit: 0 + output: + total_income: 35_001 + winter_fuel_allowance: 0 + +- name: Pensioner with total income of exactly £35,000 keeps WFP in 2025-26 + period: 2025 + absolute_error_margin: 1 + input: + age: 70 + country: ENGLAND + private_pension_income: 35_000 + pension_credit: 0 + output: + total_income: 35_000 + winter_fuel_allowance: 200 diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/total_income.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/total_income.yaml new file mode 100644 index 0000000000..339e1ecbb5 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/total_income.yaml @@ -0,0 +1,35 @@ +# ITA 2007 s. 23 Step 1 sums all income charged to income tax. Other +# investment income (National Savings, securities and trust interest) is +# charged as savings income (taxable_savings_interest_income), so it counts. + +- name: Other investment income only counts in total income + period: 2025 + input: + other_investment_income: 20_000 + output: + total_income: 20_000 + taxable_savings_interest_income: 20_000 + adjusted_net_income: 20_000 + +- name: Other investment income adds to savings interest, not double counted + period: 2025 + input: + employment_income: 30_000 + savings_interest_income: 2_000 + other_investment_income: 3_000 + output: + total_income: 35_000 + taxable_savings_interest_income: 5_000 + adjusted_net_income: 35_000 + +- name: Total income matches adjusted net income above the taper threshold + # £90k employment plus £20k other investment income: ANI £110k, so the + # personal allowance is reduced by (110,000 - 100,000) / 2 = £5,000. + period: 2025 + input: + employment_income: 90_000 + other_investment_income: 20_000 + output: + total_income: 110_000 + adjusted_net_income: 110_000 + personal_allowance: 7_570 diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_individual_non_dep_deduction.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_individual_non_dep_deduction.yaml new file mode 100644 index 0000000000..9bb8d99600 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_individual_non_dep_deduction.yaml @@ -0,0 +1,54 @@ +# The national Council Tax Reduction non-dependant deduction bands on gross +# income, but SI 2012/2885 Sch 1 para 8(2) applies the bands only to a +# non-dependant in remunerative work, which this formula does not yet test +# (#2007). Other investment income, now in total_income, is left out of the +# band until it does, so a non-worker whose only income is investment income +# is not banded on it. + +- name: Other investment income does not band a non-worker for CTR + period: 2025 + input: + council_tax_reduction_individual_non_dep_deduction_eligible: true + other_investment_income: 28_912 # 556 weekly, no hours + output: + # The same as a non-dependant with no income. Banding the £556 would give + # 115.45 * 52 = 6,003.40. + council_tax_reduction_individual_non_dep_deduction: 0 + +- name: Other investment income does not move a worker's CTR band + period: 2025 + input: + council_tax_reduction_individual_non_dep_deduction_eligible: true + hours_worked: 1_950 # 37.5 hours a week + employment_income: 9_517 # just over 183 weekly + other_investment_income: 28_912 # 556 weekly + output: + # Banded on the £183 of earnings: 45.15 * 52 = 2,347.80. + council_tax_reduction_individual_non_dep_deduction: 45.15 * 52 + +- name: A pensioner's CTR is not cut for a non-dependant's investment income + period: 2025 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 70 + is_household_head: true + adult_child: + age: 30 + other_investment_income: 28_912 # 556 a week, no hours + benunits: + claimant_family: + members: [claimant] + adult_child_family: + members: [adult_child] + households: + household: + members: [claimant, adult_child] + tenure_type: RENT_FROM_COUNCIL + rent: 15_000 + council_tax: 2_000 + country: ENGLAND + output: + # Banding the £556 would give 115.45 * 52 = 6,003.40. + council_tax_reduction_non_dep_deductions: [0, 0] diff --git a/policyengine_uk/tests/policy/baseline/household/post_tax_income_other_investment.yaml b/policyengine_uk/tests/policy/baseline/household/post_tax_income_other_investment.yaml new file mode 100644 index 0000000000..c406bdf948 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/household/post_tax_income_other_investment.yaml @@ -0,0 +1,16 @@ +- name: Post-tax income adds other investment income and subtracts its tax + # £20,000 of other investment income alone in 2025-26: personal allowance + # £12,570, starting rate for savings £5,000 at 0%, personal savings + # allowance £1,000 at 0%, the remaining £1,430 at 20% = £286. + period: 2025 + input: + people: + person: + age: 40 + other_investment_income: 20_000 + households: + household: + members: [person] + output: + income_tax: [286] + post_tax_income: [19_714] diff --git a/policyengine_uk/tests/policy/reforms/parametric/winter_fuel_allowance/taxable_income_test.yaml b/policyengine_uk/tests/policy/reforms/parametric/winter_fuel_allowance/taxable_income_test.yaml index be70a4d8a8..87ec0723dc 100644 --- a/policyengine_uk/tests/policy/reforms/parametric/winter_fuel_allowance/taxable_income_test.yaml +++ b/policyengine_uk/tests/policy/reforms/parametric/winter_fuel_allowance/taxable_income_test.yaml @@ -45,7 +45,10 @@ output: winter_fuel_allowance: 0 -- name: Enable income test - pensioner exactly at threshold gets no WFA +# The limit is inclusive: the winter fuel payment charge the income test stands +# in for applies only where total income "exceeds" the limit (ITEPA 2003 +# s.681I(1)(b)), so income exactly at the limit keeps the payment. +- name: Enable income test - pensioner exactly at threshold keeps WFA period: 2024 absolute_error_margin: 1 input: @@ -59,7 +62,7 @@ esa_income: 0 jsa_income: 0 output: - winter_fuel_allowance: 0 + winter_fuel_allowance: 200 - name: Enable income test - pensioner £1 under threshold gets WFA period: 2024 @@ -199,4 +202,21 @@ country: "ENGLAND" total_income: 50000 output: - winter_fuel_allowance: 200 \ No newline at end of file + winter_fuel_allowance: 200 + +- name: Enable income test - other investment income counts towards taxable income + period: 2024 + absolute_error_margin: 1 + input: + gov.dwp.winter_fuel_payment.eligibility.taxable_income_test.use_maximum_taxable_income: true + gov.dwp.winter_fuel_payment.eligibility.taxable_income_test.maximum_taxable_income: 20000 + age: 67 + country: "ENGLAND" + private_pension_income: 15000 + other_investment_income: 10000 + pension_credit: 0 + income_support: 0 + esa_income: 0 + jsa_income: 0 + output: + winter_fuel_allowance: 0 diff --git a/policyengine_uk/tests/test_winter_heating_payment_properties.py b/policyengine_uk/tests/test_winter_heating_payment_properties.py index d4c368a871..2639d8881b 100644 --- a/policyengine_uk/tests/test_winter_heating_payment_properties.py +++ b/policyengine_uk/tests/test_winter_heating_payment_properties.py @@ -50,7 +50,9 @@ # Ages either side of pensionable age (66 to 67 over these years) and of 80. PENSION_AGES = [67, 70, 79, 80, 85] AGES = [40, 60, *PENSION_AGES] -INCOMES = [5_000, 20_000, 50_000] +# 35,000 is the charge limit itself: ITEPA 2003 s.681I(1)(b) charges only +# total income that "exceeds £35,000". +INCOMES = [5_000, 20_000, 35_000, 50_000] AWARD = 1_000 # The benefit-unit award a couple can be on, and the input that carries it. AWARD_INPUTS = { @@ -336,7 +338,7 @@ def scheme(resident, relevant, means_test, amounts, partner_counts): else: # The model's stand-in for the winter fuel payment charge. wfp_means = country in ("ENGLAND", "WALES") and any( - p[0]["age"] >= 67 and p[0]["total_income"] < INCOME_LIMIT + p[0]["age"] >= 67 and p[0]["total_income"] <= INCOME_LIMIT for p in people ) # Only SI 2024/869 (reg 2(5)) counts the other member's benefit. diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit/non_dep_deduction/household_benefits_individual_non_dep_deduction.py b/policyengine_uk/variables/gov/dwp/housing_benefit/non_dep_deduction/household_benefits_individual_non_dep_deduction.py index 95b6bcb695..b23543c89a 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit/non_dep_deduction/household_benefits_individual_non_dep_deduction.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit/non_dep_deduction/household_benefits_individual_non_dep_deduction.py @@ -11,6 +11,15 @@ class household_benefits_individual_non_dep_deduction(Variable): def formula(person, period, parameters): p = parameters(period).gov.dwp.housing_benefit.non_dep_deduction - weekly_income = person("total_income", period) / WEEKS_IN_YEAR + # Other investment income is left out of the band for now. These bands + # apply only to a non-dependant in remunerative work (HB Regs 2006 reg + # 74(2); SPC Regs reg 55(2)), and the model does not yet test that, so + # counting it would band non-workers whose only income is investment + # income. #2007 implements reg 74 in full and can then read + # total_income directly. + income = person("total_income", period) - person( + "other_investment_income", period + ) + weekly_income = income / WEEKS_IN_YEAR deduction = p.amount.calc(weekly_income, right=True) return deduction * WEEKS_IN_YEAR diff --git a/policyengine_uk/variables/gov/dwp/winter_fuel_payment_eligible.py b/policyengine_uk/variables/gov/dwp/winter_fuel_payment_eligible.py index ff957e3327..a4c3a9c9fd 100644 --- a/policyengine_uk/variables/gov/dwp/winter_fuel_payment_eligible.py +++ b/policyengine_uk/variables/gov/dwp/winter_fuel_payment_eligible.py @@ -54,10 +54,12 @@ def formula(person, period, parameters): "is_on_winter_fuel_payment_relevant_benefit", period ) income_test = p.taxable_income_test + # ITEPA 2003 s.681I(1)(b): the charge applies only where total income + # "exceeds £35,000", so a person with exactly £35,000 keeps the payment. meets_income_test = ( person.household.any( age_eligible - & (person("total_income", period) < income_test.maximum_taxable_income) + & (person("total_income", period) <= income_test.maximum_taxable_income) ) & np.isin(country, ["ENGLAND", "WALES"]) & income_test.use_maximum_taxable_income diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/total_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/total_income.py index 0503c8447c..b90dacbb58 100644 --- a/policyengine_uk/variables/gov/hmrc/income_tax/total_income.py +++ b/policyengine_uk/variables/gov/hmrc/income_tax/total_income.py @@ -19,6 +19,7 @@ class total_income(Variable): "self_employment_income", "property_income", "savings_interest_income", + "other_investment_income", "dividend_income", # A miscellaneous loss is never part of total income (ITA 2007 s. 152(4)). "taxable_miscellaneous_income", diff --git a/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/council_tax_reduction_individual_non_dep_deduction.py b/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/council_tax_reduction_individual_non_dep_deduction.py index 102c093f63..64458e2319 100644 --- a/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/council_tax_reduction_individual_non_dep_deduction.py +++ b/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/council_tax_reduction_individual_non_dep_deduction.py @@ -11,5 +11,12 @@ class council_tax_reduction_individual_non_dep_deduction(Variable): def formula(person, period, parameters): p = parameters(period).gov.dwp.housing_benefit.non_dep_deduction - weekly_total_income = person("total_income", period) / WEEKS_IN_YEAR + # Other investment income is left out of the band for now, as in + # household_benefits_individual_non_dep_deduction: the bands apply only + # to a non-dependant in remunerative work (SI 2012/2885 Sch 1 para + # 8(2)), which this formula does not yet test (#2007). + income = person("total_income", period) - person( + "other_investment_income", period + ) + weekly_total_income = income / WEEKS_IN_YEAR return p.amount.calc(weekly_total_income, right=True) * WEEKS_IN_YEAR