diff --git a/changelog.d/winter-fuel-payment-charge.added.md b/changelog.d/winter-fuel-payment-charge.added.md new file mode 100644 index 0000000000..c581723a1b --- /dev/null +++ b/changelog.d/winter-fuel-payment-charge.added.md @@ -0,0 +1,2 @@ +- Add the winter fuel payment charge (`winter_fuel_payment_charge`, ITEPA 2003 s.681I, from 2025-26) with parameters under `gov.hmrc.income_tax.charges.winter_fuel_payment`. It is charged person by person: the whole Winter Fuel Payment (England, Wales and Northern Ireland) or Pension Age Winter Heating Payment, when the person's own total income exceeds £35,000 and they are not entitled to Income Support, income-based JSA, Pension Credit, income-related ESA or Universal Credit. It is added to `income_tax` after tax reductions (ITA 2007 s.23 Step 7). +- Add `income_tax_before_winter_fuel_payment_charge`. The Pension Credit, Income Support, Housing Benefit (applicable income and net earnings), Council Tax Reduction and benefit cap means tests now deduct it instead of `income_tax`, and the property allowance election compares it. The charge recovers a payment rather than taxing the income those tests assess, and it depends on Pension Credit and Universal Credit receipt, so deducting it would make the model circular. Universal Credit earned income already deducts only each person's own tax on earnings, which leaves out the charge. diff --git a/changelog.d/winter-fuel-payment-charge.changed.md b/changelog.d/winter-fuel-payment-charge.changed.md new file mode 100644 index 0000000000..d99a959352 --- /dev/null +++ b/changelog.d/winter-fuel-payment-charge.changed.md @@ -0,0 +1 @@ +- Deprecate `gov.dwp.winter_fuel_payment.eligibility.taxable_income_test`: it is off from 2025 and has effect only in a reform that requires a relevant benefit. Its limit now admits total income equal to it. Use `gov.hmrc.income_tax.charges.winter_fuel_payment` for the charge. diff --git a/changelog.d/winter-fuel-payment-charge.fixed.md b/changelog.d/winter-fuel-payment-charge.fixed.md new file mode 100644 index 0000000000..97b3a984df --- /dev/null +++ b/changelog.d/winter-fuel-payment-charge.fixed.md @@ -0,0 +1,2 @@ +- From the 2025 qualifying week, pay the Winter Fuel Payment to everyone of pensionable age in England, Wales and Northern Ireland (SI 2025/969 reg. 2; NISR 2025/142 reg. 2) and recover it through the winter fuel payment charge, in place of a household income test. The test paid a whole household if any member of pensionable age had total income under £35,000. It applied only in England and Wales, and it charged nobody in Northern Ireland or on the Pension Age Winter Heating Payment. Its boundary was also wrong: total income of exactly £35,000 is not charged. +- Count the Pension Age Winter Heating Payment in `household_benefits`, `hbai_household_net_income` and `hbai_benefits`, as the Winter Fuel Payment is. diff --git a/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/require_benefits.yaml b/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/require_benefits.yaml index a85099df07..85dac65b48 100644 --- a/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/require_benefits.yaml +++ b/policyengine_uk/parameters/gov/dwp/winter_fuel_payment/eligibility/require_benefits.yaml @@ -1,19 +1,28 @@ -description: Whether a relevant benefit is a condition of the Winter Fuel Payment. It was for the 2024 qualifying week. From the 2025 qualifying week the regulations pay everyone of pensionable age, and the winter fuel payment charge (ITEPA 2003 s.681I) recovers the payment from people with total income over £35,000 who are not on a relevant benefit. The model keeps this true from 2025 and lets people who are not on a relevant benefit through the income test in taxable_income_test, which stands in for the charge. +description: Whether a relevant benefit is a condition of the Winter Fuel Payment. It was for the 2024 qualifying week only. Up to the 2023 week, and from the 2025 week, everyone of pensionable age resident where the payment is made is entitled; from 2025-26 the winter fuel payment charge (gov.hmrc.income_tax.charges.winter_fuel_payment) recovers the payment from people with total income over £35,000 who are not on a relevant benefit. values: - 2000-01-01: false + 2000-01-01: + value: false + reference: + - title: The Social Fund Winter Fuel Payment Regulations 2000, reg. 2 (as in force for the 2023 qualifying week) + href: https://www.legislation.gov.uk/uksi/2000/729/regulation/2/2023-09-18 + # Dated 1 January so that the year's value is the one for its September + # qualifying week; SI 2024/869 came into force on 16 September 2024. 2024-01-01: value: true - metadata: - reference: - - title: The Social Fund Winter Fuel Payment Regulations 2024 regulation 2 - href: https://www.legislation.gov.uk/uksi/2024/869/regulation/2 + reference: + - title: The Social Fund Winter Fuel Payment Regulations 2024, reg. 2(2)(b) + href: https://www.legislation.gov.uk/uksi/2024/869/regulation/2/made + - title: The Social Fund Winter Fuel Payment Regulations (Northern Ireland) 2024, reg. 2(2)(b) + href: https://www.legislation.gov.uk/nisr/2024/160/regulation/2/made + # SI 2025/969 came into force on 15 September 2025, the first day of the + # 2025 qualifying week. + 2025-01-01: + value: false + reference: + - title: The Social Fund Winter Fuel Payment Regulations 2025, reg. 2 + href: https://www.legislation.gov.uk/uksi/2025/969/regulation/2/made + - title: The Social Fund Winter Fuel Payment Regulations (Northern Ireland) 2025, reg. 2 + href: https://www.legislation.gov.uk/nisr/2025/142/regulation/2 metadata: unit: bool label: Winter Fuel Payment means-tested benefits requirement - reference: - - href: https://www.legislation.gov.uk/uksi/2000/729/regulation/2 - title: The Social Fund Winter Fuel Payment Regulations 2000 - - title: The Social Fund Winter Fuel Payment Regulations 2025, reg. 2 - href: https://www.legislation.gov.uk/uksi/2025/969/regulation/2/made - - title: Finance Act 2026, Sch. 10 (ITEPA 2003 s.681I, winter fuel payment charge) - href: https://www.legislation.gov.uk/ukpga/2026/11/schedule/10 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..4b926ae091 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,11 +1,7 @@ -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: Deprecated; use gov.hmrc.income_tax.charges.winter_fuel_payment.income_threshold for the winter fuel payment charge. The household income test (use_maximum_taxable_income) pays a person not on a relevant benefit if a member of their household who has reached pensionable age has total income at or under this amount. It has effect only when that test is switched on and a relevant benefit is required (require_benefits). values: 2000-01-01: 0 - 2025-01-01: - value: 35_000 - reference: - - title: Finance Act 2026, Sch. 10 para. 1 (ITEPA 2003 s.681I(1)(b), for 2025-26 on) - href: https://www.legislation.gov.uk/ukpga/2026/11/schedule/10 + 2025-01-01: 35_000 metadata: unit: currency-GBP - label: Winter Fuel Payment maximum taxable income + label: Winter Fuel Payment household income test limit (deprecated) 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..1871b17ffd 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,10 +1,6 @@ -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: Deprecated; use gov.hmrc.income_tax.charges.winter_fuel_payment for the winter fuel payment charge. When this is true and a relevant benefit is required (require_benefits), a person who is not on one is still paid if a member of their household who has reached pensionable age has total income at or under maximum_taxable_income. No regulations have set such a test. It stood in for the winter fuel payment charge for 2025 before the model computed the charge, and is kept, off, so that reforms which set it still load. It has no effect while require_benefits is false, as it is from 2025. values: 2000-01-01: false - 2025-01-01: true metadata: unit: bool - label: WFA maximum taxable income eligibility - reference: - - title: Finance Act 2026, Sch. 10 para. 1 (ITEPA 2003 s.681I) - href: https://www.legislation.gov.uk/ukpga/2026/11/schedule/10 + label: Winter Fuel Payment household income test (deprecated) diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/README.md b/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/README.md new file mode 100644 index 0000000000..5bf15396bd --- /dev/null +++ b/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/README.md @@ -0,0 +1 @@ +# Winter fuel payment charge diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/in_effect.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/in_effect.yaml new file mode 100644 index 0000000000..a5972ca01a --- /dev/null +++ b/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/in_effect.yaml @@ -0,0 +1,14 @@ +description: Whether the winter fuel payment charge applies. It has effect for the tax year 2025-26 and later tax years. +values: + 2000-01-01: false + # Dated 1 January so that the year's value is the one for the tax year + # beginning in its April (2025 = 2025-26), whose qualifying week is in + # September 2025. + 2025-01-01: + value: true + reference: + - title: Finance Act 2026, Sch. 10 para. 5 (commencement) + href: https://www.legislation.gov.uk/ukpga/2026/11/schedule/10 +metadata: + unit: bool + label: Winter fuel payment charge in effect diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/income_threshold.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/income_threshold.yaml new file mode 100644 index 0000000000..f82887986d --- /dev/null +++ b/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/income_threshold.yaml @@ -0,0 +1,13 @@ +description: A person entitled to a winter fuel payment is liable to the winter fuel payment charge when their total income for the tax year exceeds this amount, unless they are entitled to a relevant benefit in the qualifying week. Total income of exactly this amount is not charged. The Treasury may change the amount by order for later tax years. +values: + 2025-01-01: + value: 35_000 + reference: + - title: Income Tax (Earnings and Pensions) Act 2003, s. 681I(1)(b), inserted by Finance Act 2026, Sch. 10 para. 1 + href: https://www.legislation.gov.uk/ukpga/2003/1/section/681I + - title: Income Tax (Earnings and Pensions) Act 2003, s. 681J (alteration of income limit by Treasury order) + href: https://www.legislation.gov.uk/ukpga/2026/11/schedule/10 +metadata: + unit: currency-GBP + period: year + label: Winter fuel payment charge income threshold diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/relevant_benefits.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/relevant_benefits.yaml new file mode 100644 index 0000000000..5a5b21883e --- /dev/null +++ b/policyengine_uk/parameters/gov/hmrc/income_tax/charges/winter_fuel_payment/relevant_benefits.yaml @@ -0,0 +1,15 @@ +description: Benefits that exempt a person from the winter fuel payment charge when they are entitled to one on any day in the qualifying week. The model takes a person to be entitled when an award is paid to them in the year. A couple's Income Support, income-based jobseeker's allowance, income-related employment and support allowance or Pension Credit is the claimant's, the member it is paid to, and not the partner's. Joint claimants of Universal Credit are both entitled. +values: + 2025-01-01: + value: + - is_on_income_support + - is_on_income_based_jsa + - is_on_pension_credit + - is_on_income_related_esa + - is_on_universal_credit + reference: + - title: Income Tax (Earnings and Pensions) Act 2003, s. 681I(4) and (5) + href: https://www.legislation.gov.uk/ukpga/2003/1/section/681I +metadata: + unit: list + label: Winter fuel payment charge relevant benefits diff --git a/policyengine_uk/programs.yaml b/policyengine_uk/programs.yaml index e8ba90376b..d4fa3aabaa 100644 --- a/policyengine_uk/programs.yaml +++ b/policyengine_uk/programs.yaml @@ -15,7 +15,7 @@ programs: variable: income_tax parameter_prefix: gov.hmrc.income_tax verified_start_year: 2019 - notes: Includes Scottish rates via devolved tax bands + notes: Includes Scottish rates via devolved tax bands, the high income child benefit charge and, from 2025-26, the winter fuel payment charge - id: national_insurance name: National Insurance @@ -355,7 +355,7 @@ programs: variable: winter_fuel_payment parameter_prefix: gov.dwp.winter_fuel_payment verified_start_year: 2022 - notes: Great Britain to winter 2023-24, then England and Wales; Northern Ireland's mirror scheme uses the same parameters + notes: Great Britain to winter 2023-24, then England and Wales; Northern Ireland's mirror scheme uses the same parameters. From winter 2025-26 paid to everyone of pensionable age and recovered by the winter fuel payment charge (income tax) - id: ssmg name: Sure Start Maternity Grant @@ -596,4 +596,4 @@ programs: variable: pension_age_winter_heating_payment parameter_prefix: gov.social_security_scotland.pawhp verified_start_year: 2024 - notes: Replaced the Winter Fuel Payment in Scotland from winter 2024-25 + notes: Replaced the Winter Fuel Payment in Scotland from winter 2024-25. From winter 2025-26 recovered by the winter fuel payment charge (income tax) above £35,000 of total income diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_applicable_income.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_applicable_income.yaml index f5218d1b0b..8b98dd09c1 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_applicable_income.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_applicable_income.yaml @@ -13,7 +13,7 @@ property_income: 0 private_pension_income: 0 # Tax - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 # Other tax_credits: 0 @@ -38,7 +38,7 @@ property_income: 0 private_pension_income: 0 # Tax - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 # Other tax_credits: 0 @@ -65,7 +65,7 @@ property_income: 0 private_pension_income: 0 # Tax - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 # Other tax_credits: 0 @@ -92,7 +92,7 @@ property_income: 0 private_pension_income: 0 # Tax - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 # Other tax_credits: 2_000 @@ -118,7 +118,7 @@ property_income: 0 private_pension_income: 0 # Tax - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 # Other tax_credits: 0 diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_net_earnings.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_net_earnings.yaml index 81e4733ddc..7db7b50af0 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_net_earnings.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_net_earnings.yaml @@ -112,7 +112,7 @@ self_employment_income: -25_000 # Tax and NI as inputs: the test is about attribution, not the # income tax calculation. - income_tax: 1_486 + income_tax_before_winter_fuel_payment_charge: 1_486 ni_class_1_employee: 594.40 benunits: benunit: @@ -171,7 +171,7 @@ employment_income: 10_000 statutory_maternity_pay: 20_000 private_pension_income: 10_000 - income_tax: 5_486 + income_tax_before_winter_fuel_payment_charge: 5_486 ni_class_1_employee: 1_394.40 benunits: benunit: @@ -194,7 +194,7 @@ employment_income: 10_000 private_pension_income: 10_000 property_income: -5_000 - income_tax: 1_486 + income_tax_before_winter_fuel_payment_charge: 1_486 benunits: benunit: members: [person] @@ -204,3 +204,30 @@ # attributed to them. No NI above State Pension age. # 10,000 - 743 = 9,257. (Dividing by 15,000 would attribute 990.67.) housing_benefit_net_earnings: 9_257 + +- name: The winter fuel payment charge does not come off earnings + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person: + age: 70 + employment_income: 10_000 + private_pension_income: 30_000 + benunits: + benunit: + members: [person] + households: + household: + members: [person] + country: ENGLAND + output: + # Total income 40,000 exceeds £35,000, so the £200 Winter Fuel Payment is + # charged back (ITEPA 2003 s.681I). The charge recovers the payment; it + # is not tax deducted from the earnings (reg 36(3); pension age reg + # 36(2)). Income tax before it is (40,000 - 12,570) x 20% = 5,486, of + # which 10,000 / 40,000 is attributed to earnings: 1,371.50. No NI above + # State Pension age. 10,000 - 1,371.50 = 8,628.50. + winter_fuel_payment_charge: [200] + income_tax: [5_686] + housing_benefit_net_earnings: 8_628.50 diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support/legacy_family_definitions.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support/legacy_family_definitions.yaml index 439406a636..ed8cb09712 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support/legacy_family_definitions.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support/legacy_family_definitions.yaml @@ -16,7 +16,7 @@ people: claimant: age: 17 - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -38,14 +38,14 @@ claimant: age: 17 is_parent: true - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 employment_income: 10000 child: age: 1 - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -67,7 +67,7 @@ claimant: age: 20 is_parent: true - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -75,7 +75,7 @@ young_person: age: 18 is_in_non_advanced_education: true - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -97,7 +97,7 @@ claimant: age: 20 is_parent: true - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -106,7 +106,7 @@ age: 17 is_in_non_advanced_education: false is_in_approved_training: false - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -127,7 +127,7 @@ people: claimant: age: 30 - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -136,7 +136,7 @@ partner: age: 17 is_claimant_or_partner: true - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -157,7 +157,7 @@ people: claimant: age: 24 - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -166,7 +166,7 @@ partner: age: 17 is_claimant_or_partner: true - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -187,7 +187,7 @@ people: claimant: age: 17 - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -196,7 +196,7 @@ partner: age: 17 is_claimant_or_partner: true - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -218,21 +218,21 @@ claimant: age: 40 is_parent: true - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 employment_income: 10000 partner: age: 40 - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 young_person: age: 19 is_in_non_advanced_education: true - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -254,7 +254,7 @@ people: claimant: age: 24 - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 @@ -273,7 +273,7 @@ people: claimant: age: 25 - income_tax: 0 + income_tax_before_winter_fuel_payment_charge: 0 national_insurance: 0 social_security_income: 0 pension_contributions: 0 diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/claimant_partner_income_and_carers.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/claimant_partner_income_and_carers.yaml index 462cdd1fca..6602c17a7d 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/claimant_partner_income_and_carers.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/claimant_partner_income_and_carers.yaml @@ -90,7 +90,7 @@ is_in_non_advanced_education: true age_started_or_accepted_current_education_or_training: 18 employment_income: 3_000 - income_tax: 100 + income_tax_before_winter_fuel_payment_charge: 100 national_insurance: 100 pension_contributions: 2_000 benunits: @@ -139,7 +139,7 @@ state_pension: 5_000 employment_income: 1_000 jsa_contrib: 100 - income_tax: 100 + income_tax_before_winter_fuel_payment_charge: 100 national_insurance: 0 pension_contributions: 200 is_entitled_to_carer_benefit: true @@ -148,7 +148,7 @@ private_pension_income: 2_000 self_employment_income: 500 esa_contrib: 200 - income_tax: 50 + income_tax_before_winter_fuel_payment_charge: 50 national_insurance: 25 pension_contributions: 100 is_entitled_to_carer_benefit: true diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/winter_fuel_payment/relevant_benefit_receipt.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/winter_fuel_payment/relevant_benefit_receipt.yaml index 37ebeebf31..038303d51c 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/winter_fuel_payment/relevant_benefit_receipt.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/winter_fuel_payment/relevant_benefit_receipt.yaml @@ -4,10 +4,10 @@ # - 2024: SI 2024/869 regs 2 to 4; # - 2025 on: SI 2025/969 regs 1(3) and 2 to 4. # Pension Credit and the other benefit-unit awards are entered on the benefit -# unit so that each case turns only on the receipt test. From 2025 the model -# stands in for the winter fuel payment charge (ITEPA 2003 s.681I) with its -# income test: a household passes when a member of pensionable age has total -# income below £35,000. +# unit so that each case turns only on the receipt test. From 2025 everyone +# of pensionable age is entitled (SI 2025/969 reg. 2), and the winter fuel +# payment charge (ITEPA 2003 s.681I) recovers the payment through income tax: +# see tests/policy/baseline/gov/hmrc/income_tax/charges/. - name: 2024 a non-dependant's income-related ESA does not entitle the pensioner # The pensioner is not entitled to a relevant benefit, nor is any partner, @@ -290,9 +290,9 @@ tax_credit_award: [0, 26] winter_fuel_payment: [0, 200] -- name: 2025 a non-dependant's income-related ESA does not exempt the pensioner from the income test +- name: 2025 a non-dependant's income-related ESA does not exempt the pensioner from the charge # Under SI 2025/969 the pensioner is entitled (reg. 2) to £200 (reg. 3(1)), - # but the winter fuel payment charge recovers it: total income over + # and the winter fuel payment charge recovers it: total income over # £35,000 and not entitled to a relevant benefit (ITEPA 2003 s.681I(1) and # (4)). The son's ESA is his own award, so it does not exempt the pensioner. period: 2025 @@ -316,10 +316,11 @@ country: ENGLAND output: is_on_winter_fuel_payment_relevant_benefit: [false, true] - winter_fuel_payment: [0, 0] - winter_fuel_allowance: 0 + winter_fuel_payment: [200, 0] + winter_fuel_payment_charge: [200, 0] + winter_fuel_allowance: 200 -- name: 2025 a pensioner under the income limit living with a non-dependant on ESA gets £200 +- name: 2025 a pensioner with total income under £35,000 living with a non-dependant on ESA keeps £200 # Reg. 3(1): under 80 and not living with another person entitled (the son # is under pensionable age). period: 2025 @@ -343,6 +344,7 @@ country: ENGLAND output: winter_fuel_payment: [200, 0] + winter_fuel_payment_charge: [0, 0] winter_fuel_allowance: 200 - name: 2025 a pensioner on Pension Credit and one who is not, in separate benefit units diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/charges/winter_fuel_payment_charge.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/charges/winter_fuel_payment_charge.yaml new file mode 100644 index 0000000000..bc02de5e3b --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/charges/winter_fuel_payment_charge.yaml @@ -0,0 +1,563 @@ +# The winter fuel payment charge, ITEPA 2003 s.681I (inserted by FA 2026 +# Sch. 10 para. 1, for 2025-26 on). Expected values are worked from the law: +# - P is liable if entitled to a winter fuel payment for the qualifying week +# and P's own total income for the tax year exceeds £35,000 (s.681I(1)); +# - the charge equals the payment (s.681I(3)); +# - P is not liable if entitled to income support, income-based JSA, Pension +# Credit, income-related ESA or Universal Credit (s.681I(4) and (5)); +# - "winter fuel payment" covers SI 2025/969 (England and Wales), SSI 2024/351 +# (Scotland's Pension Age Winter Heating Payment) and NISR 2025/142 +# (Northern Ireland) (s.681I(6)(a)); +# - the charge is additional tax at Step 7 of the income tax calculation (ITA +# 2007 ss.23 and 30). +# The payments are worked from SI 2025/969 regs 2 to 4, NISR 2025/142 regs 2 +# and 3, and SSI 2024/351 reg 10 as substituted by SSI 2025/282 (amounts from +# SSI 2025/100 and SSI 2026/170). Entitlement to a payment, and so who counts +# as "a person entitled to a winter fuel payment" for the shared amounts, does +# not depend on the charge. Benefit-unit awards are entered directly. + +- name: 2025 total income of exactly £35,000 is not charged + # s.681I(1)(b): total income must exceed £35,000. Reg. 2 and 3(1): £200. + period: 2025 + input: + people: + pensioner: + age: 70 + total_income: 35_000 + benunits: + unit: + members: [pensioner] + pension_credit: 0 + households: + household: + members: [pensioner] + country: ENGLAND + output: + winter_fuel_payment: [200] + winter_fuel_payment_charge: [0] + winter_fuel_allowance: 200 + +- name: 2025 total income of £35,001 is charged the whole payment + # s.681I(1) and (3). + period: 2025 + input: + people: + pensioner: + age: 70 + total_income: 35_001 + benunits: + unit: + members: [pensioner] + pension_credit: 0 + households: + household: + members: [pensioner] + country: ENGLAND + output: + winter_fuel_payment: [200] + winter_fuel_payment_charge: [200] + winter_fuel_allowance: 200 + +- name: 2025 a pensioner aged 85 with £50,000 is charged £300 + # Reg. 3(4): £300 at 80 or over, living alone. s.681I(3): charge £300. + period: 2025 + input: + people: + pensioner: + age: 85 + total_income: 50_000 + benunits: + unit: + members: [pensioner] + pension_credit: 0 + households: + household: + members: [pensioner] + country: WALES + output: + winter_fuel_payment: [300] + winter_fuel_payment_charge: [300] + +- name: 2025 a couple is charged on each partner's own income + # Neither is on a relevant benefit and each lives with a person entitled: + # reg. 3(2), £100 each. Only the partner with total income over £35,000 is + # charged (s.681I(1)(b)); the other keeps £100. + period: 2025 + input: + people: + partner_1: + age: 70 + total_income: 50_000 + partner_2: + age: 72 + total_income: 10_000 + benunits: + couple: + members: [partner_1, partner_2] + pension_credit: 0 + households: + household: + members: [partner_1, partner_2] + country: ENGLAND + output: + winter_fuel_payment: [100, 100] + winter_fuel_payment_charge: [100, 0] + winter_fuel_allowance: 200 + +- name: 2025 a couple aged 82 and 85 both over £35,000 are each charged £150 + # Reg. 3(6): over 80, no relevant benefit, living with an entitled person + # who has reached 80: £150 each. Both charged in full. + period: 2025 + input: + people: + partner_1: + age: 82 + total_income: 40_000 + partner_2: + age: 85 + total_income: 40_000 + benunits: + couple: + members: [partner_1, partner_2] + pension_credit: 0 + households: + household: + members: [partner_1, partner_2] + country: ENGLAND + output: + winter_fuel_payment: [150, 150] + winter_fuel_payment_charge: [150, 150] + winter_fuel_allowance: 300 + +- name: 2025 a person charged in full still counts as entitled for the shared amounts + # Two pensioners in separate benefit units. The 70-year-old is entitled + # under reg. 2 whatever their income, so each lives with a person entitled: + # the 70-year-old gets £100 (reg. 3(2)) and the 85-year-old £200 (reg. + # 3(5), living with an entitled person under 80), not £300. The charge + # recovers the 70-year-old's £100 (total income over £35,000). + period: 2025 + input: + people: + high_income: + age: 70 + total_income: 50_000 + aged_85: + age: 85 + total_income: 10_000 + benunits: + unit_1: + members: [high_income] + pension_credit: 0 + unit_2: + members: [aged_85] + pension_credit: 0 + households: + household: + members: [high_income, aged_85] + country: ENGLAND + output: + winter_fuel_payment: [100, 200] + winter_fuel_payment_charge: [100, 0] + winter_fuel_allowance: 300 + +- name: 2025 a lodger's own income is charged, not the Pension Credit recipient's + # The Pension Credit recipient: reg. 3(1), £200, not liable (s.681I(4)). + # The lodger, aged 72, on no relevant benefit and living with a person + # entitled: reg. 3(2), £100, charged (total income £40,000). + period: 2025 + input: + people: + on_pension_credit: + age: 70 + lodger: + age: 72 + total_income: 40_000 + benunits: + unit_1: + members: [on_pension_credit] + pension_credit: 1_000 + lodger_unit: + members: [lodger] + pension_credit: 0 + households: + household: + members: [on_pension_credit, lodger] + country: ENGLAND + output: + winter_fuel_payment: [200, 100] + winter_fuel_payment_charge: [0, 100] + winter_fuel_allowance: 300 + +- name: 2025 a non-dependant's income-related ESA does not exempt the pensioner + # s.681I(4) asks whether P is entitled to a relevant benefit. The son's ESA + # is his own award. The pensioner: reg. 3(1), £200, charged in full. + period: 2025 + input: + people: + pensioner: + age: 70 + total_income: 50_000 + son: + age: 40 + benunits: + pensioner_unit: + members: [pensioner] + pension_credit: 0 + son_unit: + members: [son] + esa_income: 4_000 + households: + household: + members: [pensioner, son] + country: ENGLAND + output: + winter_fuel_payment: [200, 0] + winter_fuel_payment_charge: [200, 0] + winter_fuel_allowance: 200 + +- name: 2025 a pensioner in a Universal Credit couple is not charged + # A couple claims Universal Credit jointly. The 70-year-old is the only + # member of pensionable age: reg. 3(1), £200, not liable (s.681I(4) and + # (5)(e)) despite total income of £40,000. + period: 2025 + input: + people: + claimant: + age: 60 + pensioner: + age: 70 + total_income: 40_000 + benunits: + couple: + members: [claimant, pensioner] + universal_credit: 1_000 + households: + household: + members: [claimant, pensioner] + country: ENGLAND + output: + winter_fuel_payment: [0, 200] + winter_fuel_payment_charge: [0, 0] + +- name: 2025 the partner of a Pension Credit claimant is not entitled and so not charged + # One payment for the couple, to the claimant who reports the award (reg. + # 4(2)(a)). The partner is not entitled to a winter fuel payment, so + # s.681I(1)(a) is not met whatever their income; the claimant is on Pension + # Credit (s.681I(4)). + period: 2025 + input: + people: + claimant: + age: 70 + pension_credit_reported: 1_000 + partner: + age: 72 + total_income: 50_000 + benunits: + couple: + members: [claimant, partner] + pension_credit: 1_000 + households: + household: + members: [claimant, partner] + country: ENGLAND + output: + winter_fuel_payment: [200, 0] + winter_fuel_payment_charge: [0, 0] + winter_fuel_allowance: 200 + +- name: 2025 the partner of an Income Support claimant is paid and charged + # The couple's Income Support is the claimant's, who reports it and is + # under pensionable age, so is not entitled to a payment. The partner has + # reached pensionable age and is entitled (reg. 2), at £200 (reg. 3(1)). The + # partner is not entitled to Income Support (only the claimant is), so + # s.681I(4) does not exempt them, and their total income exceeds £35,000. + period: 2025 + input: + people: + claimant: + age: 60 + income_support_reported: 1_000 + partner: + age: 70 + total_income: 40_000 + benunits: + couple: + members: [claimant, partner] + income_support: 1_000 + # Only the Income Support award: a Universal Credit award would make + # both members joint claimants, entitled to a relevant benefit. + universal_credit: 0 + pension_credit: 0 + households: + household: + members: [claimant, partner] + country: ENGLAND + output: + is_on_income_support: [true, false] + winter_fuel_payment: [0, 200] + winter_fuel_payment_charge: [0, 200] + +- name: 2025 Northern Ireland pays everyone of pensionable age + # NISR 2025/142 reg. 2 has no relevant-benefit condition; reg. 3(1): £200. + period: 2025 + input: + people: + pensioner: + age: 70 + total_income: 20_000 + benunits: + unit: + members: [pensioner] + pension_credit: 0 + households: + household: + members: [pensioner] + country: NORTHERN_IRELAND + output: + winter_fuel_payment: [200] + winter_fuel_payment_charge: [0] + winter_fuel_allowance: 200 + +- name: 2025 the charge recovers a Northern Ireland payment + # s.681I(6)(a) includes payments under NISR 2025/142. + period: 2025 + input: + people: + pensioner: + age: 70 + total_income: 50_000 + benunits: + unit: + members: [pensioner] + pension_credit: 0 + households: + household: + members: [pensioner] + country: NORTHERN_IRELAND + output: + winter_fuel_payment: [200] + winter_fuel_payment_charge: [200] + +- name: 2025 the charge recovers Scotland's Pension Age Winter Heating Payment + # SSI 2024/351 reg. 10(5)(a) as substituted by SSI 2025/282: £203.40. + # s.681I(6)(a) includes payments under SSI 2024/351. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + pensioner: + age: 70 + total_income: 50_000 + benunits: + unit: + members: [pensioner] + pension_credit: 0 + households: + household: + members: [pensioner] + country: SCOTLAND + output: + winter_fuel_payment: [0] + pension_age_winter_heating_payment: [203.40] + winter_fuel_payment_charge: [203.40] + pawhp: 203.40 + +- name: 2026 a Scottish couple aged 82 and 85 is charged on each partner's own income + # Reg. 10(6)(c) at the SSI 2026/170 amount: £158.35 each. Only the partner + # with total income over £35,000 is charged. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + partner_1: + age: 82 + total_income: 40_000 + partner_2: + age: 85 + total_income: 20_000 + benunits: + couple: + members: [partner_1, partner_2] + pension_credit: 0 + households: + household: + members: [partner_1, partner_2] + country: SCOTLAND + output: + pension_age_winter_heating_payment: [158.35, 158.35] + winter_fuel_payment_charge: [158.35, 0] + pawhp: 316.70 + +- name: 2025 a Scottish Pension Credit recipient is not charged + # Reg. 10(4)(a): £305.10 at 80 or over on a relevant benefit. Not liable + # (s.681I(4)). + period: 2025 + absolute_error_margin: 0.01 + input: + people: + pensioner: + age: 82 + total_income: 40_000 + benunits: + unit: + members: [pensioner] + pension_credit: 1_000 + households: + household: + members: [pensioner] + country: SCOTLAND + output: + pension_age_winter_heating_payment: [305.10] + winter_fuel_payment_charge: [0] + +- name: 2024 no charge before the tax year 2025-26 + # FA 2026 Sch. 10 para. 5: the charge has effect from 2025-26. For the 2024 + # week a relevant benefit was a condition of entitlement (SI 2024/869 reg. + # 2(2)(b)): £200 on Pension Credit, not charged. + period: 2024 + input: + people: + pensioner: + age: 70 + total_income: 50_000 + benunits: + unit: + members: [pensioner] + pension_credit: 1_000 + households: + household: + members: [pensioner] + country: ENGLAND + output: + winter_fuel_payment: [200] + winter_fuel_payment_charge: [0] + +- name: 2024 Northern Ireland paid only people on a relevant benefit + # NISR 2024/160 reg. 2(2)(b), as SI 2024/869 for England and Wales. + period: 2024 + input: + people: + pensioner: + age: 70 + total_income: 20_000 + benunits: + unit: + members: [pensioner] + pension_credit: 0 + households: + household: + members: [pensioner] + country: NORTHERN_IRELAND + output: + winter_fuel_payment: [0] + winter_fuel_payment_charge: [0] + +- name: 2025 the charge is added to income tax + # Private pension £50,000, no other income, England. Personal allowance + # £12,570; £37,430 at the basic rate of 20% = £7,486 (within the £37,700 + # basic rate band). The charge, £200, is added at Step 7: £7,686. HBAI net + # income counts the payment and deducts the tax: 50,000 + 200 - 7,686 = + # £42,514. + period: 2025 + input: + people: + pensioner: + age: 70 + private_pension_income: 50_000 + households: + household: + members: [pensioner] + country: ENGLAND + output: + total_income: [50_000] + income_tax_before_winter_fuel_payment_charge: [7_486] + winter_fuel_payment_charge: [200] + income_tax: [7_686] + winter_fuel_allowance: 200 + household_benefits: 200 + hbai_household_net_income: 42_514 + +- name: 2025 Council Tax Reduction income deducts income tax before the charge + # The pensioner above. Council Tax Reduction income under the general rules + # deducts income tax and National Insurance, but not the charge, which + # recovers the payment: 50,000 - 7,486 = £42,514, not 50,000 - 7,686. + period: 2025 + input: + people: + pensioner: + age: 70 + private_pension_income: 50_000 + households: + household: + members: [pensioner] + country: ENGLAND + output: + winter_fuel_payment_charge: [200] + council_tax_reduction_applicable_income: [42_514] + +- name: 2025 the payment is kept at £35,000 of private pension + # £22,430 at 20% = £4,486; no charge. HBAI net income: 35,000 + 200 - + # 4,486 = £30,714. + period: 2025 + input: + people: + pensioner: + age: 70 + private_pension_income: 35_000 + households: + household: + members: [pensioner] + country: ENGLAND + output: + winter_fuel_payment_charge: [0] + income_tax: [4_486] + hbai_household_net_income: 30_714 + +- name: 2025 Scotland's payment is household income + # PAWHP counts in household benefits and HBAI income, like the Winter Fuel + # Payment it replaced in Scotland. Reg. 10(5)(a): £203.40; no charge. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + pensioner: + age: 70 + private_pension_income: 20_000 + households: + household: + members: [pensioner] + country: SCOTLAND + output: + winter_fuel_payment_charge: [0] + pawhp: 203.40 + household_benefits: 203.40 + hbai_benefits: 203.40 + +- name: 2025 a landlord's property allowance election is made before the charge + # Private pension £32,000; property receipts £3,500, expenses £200 (profit + # £3,300), finance costs £1,500. With expenses: (35,300 - 12,570) x 20% = + # £4,546, less the finance-cost reduction 20% x £1,500 = £300, so £4,246. + # With partial relief (£1,000 allowance for £200 of expenses, no + # reduction): (34,500 - 12,570) x 20% = £4,386. Expenses are kept. The + # model's total_income is before the property allowance, £35,300 on either + # route, so the £200 charge is added on either. + period: 2025 + input: + people: + pensioner: + age: 70 + private_pension_income: 32_000 + property_rental_income: 3_500 + property_income: 3_300 + property_finance_costs: 1_500 + households: + household: + members: [pensioner] + country: ENGLAND + output: + uses_property_allowance: [false] + total_income: [35_300] + income_tax_before_winter_fuel_payment_charge: [4_246] + winter_fuel_payment_charge: [200] + income_tax: [4_446] 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..8b30f9c78b 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 @@ -1,3 +1,10 @@ +# The household income test in +# gov.dwp.winter_fuel_payment.eligibility.taxable_income_test is deprecated: +# no regulations set it, and from 2025 the winter fuel payment charge (ITEPA +# 2003 s.681I, gov.hmrc.income_tax.charges.winter_fuel_payment) recovers the +# payment instead. The test still works in a reform that requires a relevant +# benefit (require_benefits), as for the 2024 qualifying week. + - name: 2024 baseline - pensioner without benefits gets no WFA period: 2024 absolute_error_margin: 1 @@ -45,7 +52,10 @@ output: winter_fuel_allowance: 0 -- name: Enable income test - pensioner exactly at threshold gets no WFA +- name: Enable income test - pensioner exactly at threshold gets WFA + # The limit is a maximum: total income at the limit passes, as the winter + # fuel payment charge reaches only total income exceeding £35,000 (ITEPA + # 2003 s.681I(1)(b)). period: 2024 absolute_error_margin: 1 input: @@ -59,7 +69,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 +209,73 @@ country: "ENGLAND" total_income: 50000 output: - winter_fuel_allowance: 200 \ No newline at end of file + winter_fuel_allowance: 200 + +- name: 2025 baseline - pensioner without benefits is paid, and the charge recovers it above £35,000 + # SI 2025/969 reg. 2 pays everyone of pensionable age; ITEPA 2003 s.681I. + period: 2025 + absolute_error_margin: 1 + input: + age: 67 + country: "ENGLAND" + total_income: 50000 + pension_credit: 0 + income_support: 0 + esa_income: 0 + jsa_income: 0 + output: + winter_fuel_allowance: 200 + winter_fuel_payment_charge: 200 + +- name: 2025 the deprecated household income test has no effect while no relevant benefit is required + period: 2025 + 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" + total_income: 50000 + pension_credit: 0 + income_support: 0 + esa_income: 0 + jsa_income: 0 + output: + winter_fuel_allowance: 200 + winter_fuel_payment_charge: 200 + +- name: 2025 the deprecated household income test applies when a reform requires a relevant benefit - over the limit + period: 2025 + absolute_error_margin: 1 + input: + gov.dwp.winter_fuel_payment.eligibility.require_benefits: true + 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" + total_income: 50000 + pension_credit: 0 + income_support: 0 + esa_income: 0 + jsa_income: 0 + output: + winter_fuel_allowance: 0 + winter_fuel_payment_charge: 0 + +- name: 2025 the deprecated household income test applies when a reform requires a relevant benefit - under the limit + period: 2025 + absolute_error_margin: 1 + input: + gov.dwp.winter_fuel_payment.eligibility.require_benefits: true + 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" + total_income: 15000 + pension_credit: 0 + income_support: 0 + esa_income: 0 + jsa_income: 0 + output: + winter_fuel_allowance: 200 + winter_fuel_payment_charge: 0 diff --git a/policyengine_uk/tests/policy/reforms/parametric/winter_fuel_payment_charge/charge_parameters.yaml b/policyengine_uk/tests/policy/reforms/parametric/winter_fuel_payment_charge/charge_parameters.yaml new file mode 100644 index 0000000000..2a5c82c656 --- /dev/null +++ b/policyengine_uk/tests/policy/reforms/parametric/winter_fuel_payment_charge/charge_parameters.yaml @@ -0,0 +1,69 @@ +# Reforms to the winter fuel payment charge parameters +# (gov.hmrc.income_tax.charges.winter_fuel_payment). + +- name: A higher income threshold - total income under it is not charged + period: 2025 + input: + gov.hmrc.income_tax.charges.winter_fuel_payment.income_threshold: 50_000 + age: 70 + country: ENGLAND + total_income: 45_000 + pension_credit: 0 + output: + winter_fuel_payment: 200 + winter_fuel_payment_charge: 0 + +- name: A higher income threshold - total income over it is charged + period: 2025 + input: + gov.hmrc.income_tax.charges.winter_fuel_payment.income_threshold: 50_000 + age: 70 + country: ENGLAND + total_income: 50_001 + pension_credit: 0 + output: + winter_fuel_payment: 200 + winter_fuel_payment_charge: 200 + +- name: Repealing the charge leaves the payment with everyone + period: 2025 + input: + gov.hmrc.income_tax.charges.winter_fuel_payment.in_effect: false + age: 70 + country: ENGLAND + total_income: 50_000 + pension_credit: 0 + output: + winter_fuel_payment: 200 + winter_fuel_payment_charge: 0 + +- name: Charging a universal payment for the 2024 qualifying week + period: 2024 + input: + gov.dwp.winter_fuel_payment.eligibility.require_benefits: false + gov.hmrc.income_tax.charges.winter_fuel_payment.in_effect: true + age: 70 + country: ENGLAND + total_income: 50_000 + pension_credit: 0 + output: + winter_fuel_payment: 200 + winter_fuel_payment_charge: 200 + +- name: Tax credits do not exempt a person from the charge + # Charging the 2024 qualifying week's payments: a tax credit award of at + # least £26 entitled a person to that payment (SI 2024/869 reg. 2(2)(b) + # (ii)), but tax credits are not among the relevant benefits of ITEPA 2003 + # s.681I(5), so the person is charged. + period: 2024 + input: + gov.hmrc.income_tax.charges.winter_fuel_payment.in_effect: true + age: 70 + country: ENGLAND + total_income: 50_000 + pension_credit: 0 + tax_credits: 1_000 + output: + is_on_winter_fuel_payment_relevant_benefit: true + winter_fuel_payment: 200 + winter_fuel_payment_charge: 200 diff --git a/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py b/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py index 8795cdd8c6..0f698c3dce 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py @@ -20,7 +20,9 @@ all of a family's income tax from its Council Tax Reduction income, an existing approximation, so there the supplement, which is taxable (SI 2026/93), reaches that income through the tax charged on it and in no other -way. +way. The tax deducted is the liability before the winter fuel payment charge +(ITEPA 2003 s. 681I), which recovers a winter payment rather than taxing the +income assessed; "income tax" below means that liability. Invariants, for single people and couples in Scotland in 2026 in which one member is a carer, all of working age and taking no Universal Credit or all @@ -82,6 +84,9 @@ CARER_SUPPORT_PAYMENT = 86.45 * WEEKS SCOTTISH_CARER_SUPPLEMENT = 11.70 * WEEKS WITHDRAWAL_RATE = 0.2 +# The income tax Council Tax Reduction income deducts: the liability before +# the winter fuel payment charge. +INCOME_TAX = "income_tax_before_winter_fuel_payment_charge" PROPERTY_SETTINGS = settings( max_examples=10, deadline=None, @@ -128,7 +133,7 @@ "carer_support_payment", "carer_support_payment_pre_overlap", "scottish_carer_supplement", - "income_tax", + INCOME_TAX, "national_insurance", ] CLAIMS = (True, False) @@ -230,7 +235,7 @@ def grid(families, reform=None): # from the other benefits it counts. g["income_before_tax"] = ( g["council_tax_reduction_applicable_income"] - + g["income_tax"] + + g[INCOME_TAX] + g["national_insurance"] - g["other_counted_benefits"] ) @@ -330,8 +335,8 @@ def test_council_tax_reduction_income_ignores_the_scottish_carer_supplement( compared = (income > 0) & (income_without > 0) & general assert compared.any(), fam assert np.allclose( - (income + g["income_tax"][i])[compared], - (income_without + without["income_tax"][i])[compared], + (income + g[INCOME_TAX][i])[compared], + (income_without + without[INCOME_TAX][i])[compared], atol=0.05, ), fam award = g["council_tax_benefit"][i] @@ -341,7 +346,7 @@ def test_council_tax_reduction_income_ignores_the_scottish_carer_supplement( # follows invariant 4). assert np.all(award >= award_without - 0.01), fam both_partial = partial(g, i) & partial(without, i) & general - tax_on_supplement = g["income_tax"][i] - without["income_tax"][i] + tax_on_supplement = g[INCOME_TAX][i] - without[INCOME_TAX][i] assert np.allclose( (award - award_without)[both_partial], WITHDRAWAL_RATE * tax_on_supplement[both_partial], diff --git a/policyengine_uk/tests/test_housing_benefit_savings_credit_only_properties.py b/policyengine_uk/tests/test_housing_benefit_savings_credit_only_properties.py index 6d19738615..7ff84bd23a 100644 --- a/policyengine_uk/tests/test_housing_benefit_savings_credit_only_properties.py +++ b/policyengine_uk/tests/test_housing_benefit_savings_credit_only_properties.py @@ -27,19 +27,24 @@ award at both ends, household net income, excluding the TV licence, does not fall. 2. Boundary: on the step where savings credit ends, household net income does - not fall, excluding the TV licence, the Winter Fuel Payment and the - Scottish Pension Age Winter Heating Payment, which the model makes depend - on receiving Pension Credit (the free licence at 75, the Scottish payment's - Pension Credit rates, and the Winter Fuel Payment above £35,000 of taxable - income). Housing Benefit switches from the Secretary of State's figure to - its own rules there. + not fall, excluding the TV licence, the Scottish Pension Age Winter + Heating Payment and the winter fuel payment charge, which the model makes + depend on receiving Pension Credit (the free licence at 75, the Scottish + payment's Pension Credit rates, and the charge, from which Pension Credit + exempts a person with more than £35,000 of total income: ITEPA 2003 s. + 681I), and the Winter Fuel Payment, which depended on it before 2025-26. + Housing Benefit switches from the Secretary of State's figure to its own + rules there. 3. Differential: a savings-credit-only family's Housing Benefit income is the Pension Credit income, recomputed here from pensions, income tax and the deemed income on savings, plus the savings credit, less the earnings disregard; its tariff income is zero and its capital is its savings. Other families keep the Housing Benefit rules: zero income with a guarantee credit, otherwise pensions less income tax plus tariff income less the - earnings disregard. + earnings disregard. The income tax both routes deduct is the liability + before the winter fuel payment charge (ITEPA 2003 s. 681I), which recovers + the Winter Fuel Payment or the Scottish payment rather than taxing the + pensions. Carers are not drawn. """ @@ -176,7 +181,12 @@ def grid(families): variable: np.asarray(simulation.calculate(variable, YEAR)).reshape(shape) for variable in BENUNIT_VARIABLES + HOUSEHOLD_VARIABLES } - for variable in ["state_pension", "private_pension_income", "income_tax"]: + for variable in [ + "state_pension", + "private_pension_income", + "income_tax_before_winter_fuel_payment_charge", + "winter_fuel_payment_charge", + ]: values[variable] = np.asarray( simulation.calculate(variable, YEAR, map_to="benunit") ).reshape(shape) @@ -230,6 +240,7 @@ def test_net_income_does_not_fall_where_savings_credit_ends(families): + g["tv_licence"] - g["winter_fuel_allowance"] - g["pawhp"] + + g["winter_fuel_payment_charge"] ) step = np.diff(net, axis=1) ends = g["savings_credit_only"][:, :-1] & (g["pension_credit"][:, 1:] <= 0) @@ -254,7 +265,9 @@ def test_income_follows_the_route_for_the_award(families): savings = np.array([fam["savings"] for fam in families])[:, None] capital_income = deemed_income(savings) pensions_after_tax = ( - g["state_pension"] + g["private_pension_income"] - g["income_tax"] + g["state_pension"] + + g["private_pension_income"] + - g["income_tax_before_winter_fuel_payment_charge"] ) disregard = g["housing_benefit_applicable_income_disregard"] sc_only = g["savings_credit_only"] diff --git a/policyengine_uk/tests/test_uc_earnings_deductions_properties.py b/policyengine_uk/tests/test_uc_earnings_deductions_properties.py index bc961fe791..6032a8c3b5 100644 --- a/policyengine_uk/tests/test_uc_earnings_deductions_properties.py +++ b/policyengine_uk/tests/test_uc_earnings_deductions_properties.py @@ -292,10 +292,19 @@ def formula(benunit, period, parameters): period, ["employment_income", "self_employment_income", "miscellaneous_income"], ) + # The whole benefit unit's tax, as benunit_tax was before the + # winter fuel payment charge joined income tax: the charge depends + # on Universal Credit receipt, so deducting it here would be + # circular. disregards = add( benunit, period, - ["uc_work_allowance", "benunit_tax", "pension_contributions"], + [ + "uc_work_allowance", + "income_tax_before_winter_fuel_payment_charge", + "national_insurance", + "pension_contributions", + ], ) return max_(0, gross - disregards) diff --git a/policyengine_uk/tests/test_winter_heating_payment_properties.py b/policyengine_uk/tests/test_winter_heating_payment_properties.py index d4c368a871..996333a346 100644 --- a/policyengine_uk/tests/test_winter_heating_payment_properties.py +++ b/policyengine_uk/tests/test_winter_heating_payment_properties.py @@ -1,9 +1,11 @@ """The Winter Fuel Payment and the Pension Age Winter Heating Payment follow -each person's own receipt of a relevant benefit. +each person's own receipt of a relevant benefit, and the winter fuel payment +charge follows each person's own total income. Both schemes entitle and pay a person (SI 2000/729 reg 2; SI 2024/869 regs -2 to 4; SI 2025/969 regs 2 to 4; SSI 2024/351 regs 5, 9 and 10). Whether a -person is on a relevant benefit depends on the instrument: +2 to 4; SI 2025/969 regs 2 to 4; NISR 2025/142 regs 2 to 4; SSI 2024/351 +regs 5, 9 and 10). Whether a person is on a relevant benefit depends on the +instrument: - "paid to" the person (SI 2000/729, SI 2025/969): Income Support, income-based JSA, income-related ESA and Pension Credit are paid to one @@ -18,11 +20,21 @@ - through the couple (SI 2024/869 reg 2(5); SSI 2024/351 reg 7(2), 10(8) and 2A): a member of a couple is on one when the other member is. -Either way a couple on one receives a single payment. Properties: +Either way a couple on one receives a single payment. From 2025-26 the +winter fuel payment charge (ITEPA 2003 s.681I) recovers a person's payment +through income tax when their own total income exceeds £35,000 and they are +not entitled to a relevant benefit: the member a couple's award is paid to, +or both joint claimants of Universal Credit, but not the partner of an +Income Support, income-based JSA, income-related ESA or Pension Credit +claimant. Properties: - the model matches a reference implementation written directly from the - regulations, person by person, over households of up to three benefit - units, in every country and in the 2023 to 2026 qualifying weeks; + regulations and s.681I, person by person, over households of up to three + benefit units, in every country and in the 2023 to 2026 qualifying weeks: + payments, charges, and income tax with and without the charge; +- incomes never change anyone's payment, only the charge: entitlement, and + so who counts as another entitled person for the shared amounts, comes + before the charge; - adding a non-dependant under pensionable age, with or without a relevant benefit of their own, never changes what anyone else is paid; - from the 2025 qualifying week, a household of a single person or a couple @@ -50,7 +62,8 @@ # 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] +# Either side of the £35,000 charge threshold, and exactly on it. +INCOMES = [5_000, 20_000, 35_000, 35_001, 50_000] AWARD = 1_000 # The benefit-unit award a couple can be on, and the input that carries it. AWARD_INPUTS = { @@ -119,7 +132,9 @@ # SSI 2026/170 reg 15(3). 2026: (211.15, 316.70, 105.55, 211.15, 158.35), } -INCOME_LIMIT = 35_000 +# ITEPA 2003 s.681I(1)(b) and (5), from the tax year 2025-26. +CHARGE_THRESHOLD = 35_000 +CHARGE_RELEVANT = {"IS", "JSA", "PC", "ESA", "UC"} @st.composite @@ -212,13 +227,14 @@ def situation(drawn, year): return {"people": people, "benunits": benunits, "households": hh} -def reference_payments(household, year): - """WFP and PAWHP for each person, worked from the regulations. +def relevant_benefit_paid(household, relevant): + """Whether a relevant benefit is paid to each person of the household. - Everyone listed in AGES from 67 has reached pensionable age in these - years and everyone under 67 has not. + An outside member is on their own award. A couple's Income Support, + income-based JSA, income-related ESA and Pension Credit are paid to one + member, the claimant; Universal Credit and tax credits are joint awards, + paid to both. """ - country = household["country"] people = household_people(household) units = household["units"] @@ -247,13 +263,22 @@ def is_payee(i): return i in chosen return i == max(couple, key=lambda j: (people[j][0]["age"], -j)) - def paid(relevant): - """Whether a relevant benefit is paid to each person.""" - return [ - award_of(p) in relevant - and (not p[2] or award_of(p) in JOINT_AWARDS or is_payee(i)) - for i, p in enumerate(people) - ] + return [ + award_of(p) in relevant + and (not p[2] or award_of(p) in JOINT_AWARDS or is_payee(i)) + for i, p in enumerate(people) + ] + + +def reference_payments(household, year): + """WFP and PAWHP for each person, worked from the regulations. + + Everyone listed in AGES from 67 has reached pensionable age in these + years and everyone under 67 has not. + """ + country = household["country"] + people = household_people(household) + units = household["units"] def through_couple(receipt): """Each claimant or partner is on one when either of them is.""" @@ -266,7 +291,7 @@ def through_couple(receipt): def scheme(resident, relevant, means_test, amounts, partner_counts): lower, higher, shared, shared_80_with_under_80, shared_80_with_80 = amounts - paid_to = paid(relevant) + paid_to = relevant_benefit_paid(household, relevant) couple = through_couple(paid_to) on_relevant = couple if partner_counts else paid_to qualifies = [resident and p[0]["age"] >= 67 for p in people] @@ -328,17 +353,11 @@ def scheme(resident, relevant, means_test, amounts, partner_counts): if year <= 2023: wfp_resident = True - wfp_means = True else: wfp_resident = country in ("ENGLAND", "WALES", "NORTHERN_IRELAND") - if year == 2024: - wfp_means = False - 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 - for p in people - ) + # Only the 2024 regulations (SI 2024/869 reg 2(2)(b); NISR 2024/160) + # made a relevant benefit a condition of entitlement. + wfp_means = year != 2024 # Only SI 2024/869 (reg 2(5)) counts the other member's benefit. wfp = scheme(wfp_resident, WFP_RELEVANT[year], wfp_means, WFP_AMOUNTS, year == 2024) if year >= 2024 and country == "SCOTLAND": @@ -350,6 +369,29 @@ def scheme(resident, relevant, means_test, amounts, partner_counts): return wfp, pawhp +def reference_charges(household, year, payments): + """The winter fuel payment charge on each person (ITEPA 2003 s.681I). + + ``payments`` is each person's winter fuel payment of any kind (s.681I(6) + (a)). The charge is the whole payment (s.681I(3)) when the person's own + total income exceeds £35,000 (s.681I(1)(b)) and they are not entitled to + a relevant benefit (s.681I(4) and (5)), from 2025-26. Of a couple on + Income Support, income-based JSA, income-related ESA or Pension Credit + only the claimant, the member it is paid to, is entitled to it; both + joint claimants are entitled to Universal Credit. + """ + if year < 2025: + return [0.0] * len(payments) + entitled = relevant_benefit_paid(household, CHARGE_RELEVANT) + charges = [] + for (inputs, _, _), payment, exempt in zip( + household_people(household), payments, entitled + ): + liable = inputs["total_income"] > CHARGE_THRESHOLD and not exempt + charges.append(payment if liable else 0.0) + return charges + + SETTINGS = settings( max_examples=12, deadline=None, @@ -364,14 +406,34 @@ def test_payments_match_reference(year, drawn): sim = Simulation(situation=situation(drawn, year)) wfp = sim.calculate("winter_fuel_payment", year) pawhp = sim.calculate("pension_age_winter_heating_payment", year) + charge = sim.calculate("winter_fuel_payment_charge", year) + income_tax = sim.calculate("income_tax", year) + before_charge = sim.calculate("income_tax_before_winter_fuel_payment_charge", year) wfa_household = sim.calculate("winter_fuel_allowance", year) pawhp_household = sim.calculate("pawhp", year) start = 0 for h, household in enumerate(drawn): expected_wfp, expected_pawhp = reference_payments(household, year) + expected_charge = reference_charges( + household, year, [a + b for a, b in zip(expected_wfp, expected_pawhp)] + ) n = len(expected_wfp) got_wfp = wfp[start : start + n] got_pawhp = pawhp[start : start + n] + got_charge = charge[start : start + n] + assert np.allclose(got_charge, expected_charge, atol=0.005), ( + year, + household, + got_charge, + expected_charge, + ) + # The charge is added to income tax after everything else (ITA 2007 + # s.23 Step 7). + assert np.allclose( + income_tax[start : start + n] - before_charge[start : start + n], + expected_charge, + atol=0.005, + ) assert np.allclose(got_wfp, expected_wfp, atol=0.005), ( year, household, @@ -472,7 +534,7 @@ def one_unit_households(draw): if not any(a["age"] >= 67 for a in adults): adults[0]["age"] = draw(st.sampled_from(PENSION_AGES)) return { - "country": draw(st.sampled_from(["ENGLAND", "WALES", "SCOTLAND"])), + "country": draw(st.sampled_from(COUNTRIES)), "units": [ { "adults": adults, @@ -510,3 +572,49 @@ def test_one_benefit_unit_receives_the_full_amount(year, drawn): else: assert wfa[h] == (300 if any_80 else 200), (year, household) assert pawhp[h] == 0 + + +def with_incomes(household, income): + """The household with every member's total income set to ``income``.""" + units = [ + {**u, "adults": [{**a, "total_income": income} for a in u["adults"]]} + for u in household["units"] + ] + other = household["other"] + if other is not None: + other = {**other, "total_income": income} + return {**household, "units": units, "other": other} + + +@SETTINGS +@given( + st.sampled_from([2025, 2026]), + st.lists(households(), min_size=1, max_size=6), +) +def test_incomes_change_only_the_charge(year, drawn): + """The same households with everyone on £5,000 and everyone on £50,000: + the payments are identical (entitlement, and so the shared amounts, does + not depend on income), nobody on £5,000 is charged, and everyone on + £50,000 who is paid and not on a relevant benefit is charged their whole + payment.""" + low = [with_incomes(h, 5_000) for h in drawn] + high = [with_incomes(h, 50_000) for h in drawn] + sim = Simulation(situation=situation(low + high, year)) + paid = sim.calculate("winter_fuel_payment", year) + sim.calculate( + "pension_age_winter_heating_payment", year + ) + charge = sim.calculate("winter_fuel_payment_charge", year) + relevant = np.zeros_like(charge, dtype=bool) + for variable in [ + "is_on_income_support", + "is_on_income_based_jsa", + "is_on_pension_credit", + "is_on_income_related_esa", + "is_on_universal_credit", + ]: + relevant |= sim.calculate(variable, year).astype(bool) + n = len(paid) // 2 + assert np.allclose(paid[:n], paid[n:], atol=0.005), (year, drawn) + assert np.all(charge[:n] == 0), (year, drawn) + assert np.allclose(charge[n:], np.where(relevant[n:], 0, paid[n:]), atol=0.005) + assert np.all(charge <= paid + 0.005) diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_applicable_income.py b/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_applicable_income.py index b97d9ac316..3b5ba3b130 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_applicable_income.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_applicable_income.py @@ -93,7 +93,10 @@ def formula(benunit, period, parameters): pension_contributions = ( add_for_members(benunit, period, ["pension_contributions"], members) * 0.5 ) - TAX_COMPONENTS = ["income_tax", "national_insurance"] + TAX_COMPONENTS = [ + "income_tax_before_winter_fuel_payment_charge", + "national_insurance", + ] tax = add_for_members(benunit, period, TAX_COMPONENTS, members) increased_income_reduced_by_tax_and_pensions = ( increased_income - tax - pension_contributions diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_net_earnings.py b/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_net_earnings.py index 8f8d97ac9a..c0b1b64e1e 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_net_earnings.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_net_earnings.py @@ -11,7 +11,7 @@ class housing_benefit_net_earnings(Variable): "income plus self-employment profit (each floored at zero, as a loss " "in one employment is not set against another) plus statutory sick " "and maternity pay (regulation 35(1)(i); pension age regulation " - "35(1)(h)), less income tax, " + "35(1)(h)), less income tax (before the winter fuel payment charge), " "Class 1, 2 and 4 National Insurance, and half of pension " "contributions, floored at zero. For an employee the regulations " "deduct the income tax deducted from the earnings (regulation 36(3); " @@ -69,7 +69,11 @@ def formula(benunit, period, parameters): out=np.zeros_like(earnings), where=income_before_losses > 0, ) - income_tax = person("income_tax", period) * min_(earnings_share, 1) + # Tax before the winter fuel payment charge: the charge recovers a + # payment and is not deducted from earnings. + income_tax = person( + "income_tax_before_winter_fuel_payment_charge", period + ) * min_(earnings_share, 1) national_insurance = add( person, period, ["ni_class_1_employee", "ni_class_2", "ni_class_4"] ) diff --git a/policyengine_uk/variables/gov/dwp/income_support_applicable_income.py b/policyengine_uk/variables/gov/dwp/income_support_applicable_income.py index eea502562e..a61a454b9c 100644 --- a/policyengine_uk/variables/gov/dwp/income_support_applicable_income.py +++ b/policyengine_uk/variables/gov/dwp/income_support_applicable_income.py @@ -30,7 +30,10 @@ def formula(benunit, period, parameters): INCOME_COMPONENTS.append("basic_income") income = add_for_members(benunit, period, INCOME_COMPONENTS, members) tax = add_for_members( - benunit, period, ["income_tax", "national_insurance"], members + benunit, + period, + ["income_tax_before_winter_fuel_payment_charge", "national_insurance"], + members, ) income += add_for_members(benunit, period, ["social_security_income"], members) income += benunit("income_support_tariff_income", period) diff --git a/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_earnings.py b/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_earnings.py index 1bdb797d6a..345b0b4104 100644 --- a/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_earnings.py +++ b/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_earnings.py @@ -28,7 +28,7 @@ def formula(benunit, period, parameters): ( person("employment_income", period) + person("self_employment_income", period) - - person("income_tax", period) + - person("income_tax_before_winter_fuel_payment_charge", period) - person("national_insurance", period) ) * claimant diff --git a/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_health_disability.py b/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_health_disability.py index 69e1116338..ba5789c66b 100644 --- a/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_health_disability.py +++ b/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_health_disability.py @@ -36,7 +36,7 @@ def formula(benunit, period, parameters): uc_earned = benunit.sum( benunit.members("employment_income", period) + benunit.members("self_employment_income", period) - - benunit.members("income_tax", period) + - benunit.members("income_tax_before_winter_fuel_payment_charge", period) - benunit.members("national_insurance", period) ) earnings_threshold = 10_152 diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_income.py b/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_income.py index 944419416e..a809221406 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_income.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_income.py @@ -47,7 +47,11 @@ def formula(benunit, period, parameters): person("pension_contributions", period) * is_claimant_or_partner ) tax = benunit.sum( - add(person, period, ["income_tax", "national_insurance"]) + add( + person, + period, + ["income_tax_before_winter_fuel_payment_charge", "national_insurance"], + ) * is_claimant_or_partner ) pen_con_deduction_rate = pc.income.pension_contributions_deduction diff --git a/policyengine_uk/variables/gov/dwp/winter_fuel_allowance.py b/policyengine_uk/variables/gov/dwp/winter_fuel_allowance.py index b0a404dec5..51c01a5e0d 100644 --- a/policyengine_uk/variables/gov/dwp/winter_fuel_allowance.py +++ b/policyengine_uk/variables/gov/dwp/winter_fuel_allowance.py @@ -6,7 +6,10 @@ class winter_fuel_allowance(Variable): documentation = ( "Winter Fuel Payments made to the members of this household " "(winter_fuel_payment). Payments in Scotland from the 2024 " - "qualifying week are the Pension Age Winter Heating Payment (pawhp)." + "qualifying week are the Pension Age Winter Heating Payment (pawhp). " + "The payments are counted in full: from 2025-26 the winter fuel " + "payment charge recovers them from some members through income tax " + "(winter_fuel_payment_charge)." ) entity = Household definition_period = YEAR diff --git a/policyengine_uk/variables/gov/dwp/winter_fuel_payment.py b/policyengine_uk/variables/gov/dwp/winter_fuel_payment.py index 33fda18f95..13e5205d65 100644 --- a/policyengine_uk/variables/gov/dwp/winter_fuel_payment.py +++ b/policyengine_uk/variables/gov/dwp/winter_fuel_payment.py @@ -11,7 +11,8 @@ class winter_fuel_payment(Variable): "benefit receives the full amount (the higher amount if they or their " "partner have reached 80), once per couple. Anyone else receives the " "full amount if no other person in their household is eligible, and " - "a shared amount otherwise." + "a shared amount otherwise. This is the amount paid, before any " + "winter fuel payment charge (winter_fuel_payment_charge)." ) definition_period = YEAR unit = GBP 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..9bbf95bf8a 100644 --- a/policyengine_uk/variables/gov/dwp/winter_fuel_payment_eligible.py +++ b/policyengine_uk/variables/gov/dwp/winter_fuel_payment_eligible.py @@ -14,16 +14,17 @@ class winter_fuel_payment_eligible(Variable): "qualifying age for State Pension Credit) and live where the " "payment is made, they " "are not the partner of the person paid for a couple on a relevant " - "benefit, and they meet the model's means condition. The means " - "condition is a relevant benefit of their own (or their couple's) " - "where gov.dwp.winter_fuel_payment.eligibility.require_benefits is " - "set, as for the 2024 qualifying week (SI 2024/869 reg 2(2)(b)). " - "From 2025 the regulations pay everyone of pensionable age (SI " - "2025/969 reg 2) and the winter fuel payment charge recovers the " - "payment from people with total income over £35,000 who are not on a " - "relevant benefit (ITEPA 2003 s.681I); the model represents the " - "charge with the household income test in " - "gov.dwp.winter_fuel_payment.eligibility.taxable_income_test." + "benefit, and, for the 2024 qualifying week only, they are on a " + "relevant benefit of their own or their couple's (SI 2024/869 reg " + "2(2)(b)). Up to the 2023 week and from the 2025 week everyone who " + "meets the age and residence conditions is entitled (SI 2000/729 reg " + "2; SI 2025/969 reg 2; NISR 2025/142 reg 2). From 2025-26 the winter fuel payment charge " + "recovers the payment through income tax from a person whose own " + "total income exceeds £35,000 and who is not on a relevant benefit " + "(winter_fuel_payment_charge); entitlement, and so the shared " + "amounts, are unaffected by it. The deprecated household income test " + "in gov.dwp.winter_fuel_payment.eligibility.taxable_income_test " + "applies only in a reform that requires a relevant benefit." ) definition_period = YEAR reference = ( @@ -32,6 +33,7 @@ class winter_fuel_payment_eligible(Variable): "https://www.legislation.gov.uk/uksi/2024/869/regulation/4", "https://www.legislation.gov.uk/uksi/2025/969/regulation/2", "https://www.legislation.gov.uk/uksi/2025/969/regulation/4", + "https://www.legislation.gov.uk/nisr/2025/142/regulation/2", ) def formula(person, period, parameters): @@ -57,7 +59,7 @@ def formula(person, period, parameters): 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/allowances/uses_property_allowance.py b/policyengine_uk/variables/gov/hmrc/income_tax/allowances/uses_property_allowance.py index 6e77ce8650..f63250b5c8 100644 --- a/policyengine_uk/variables/gov/hmrc/income_tax/allowances/uses_property_allowance.py +++ b/policyengine_uk/variables/gov/hmrc/income_tax/allowances/uses_property_allowance.py @@ -22,15 +22,21 @@ def income_tax_with_route(simulation, name, period, uses_allowance): """Each person's income tax with the given choices of property allowance. - The branch shares the simulation's cached arrays until it writes, and is - dropped afterwards so a later period starts from a fresh branch. + The tax is before the winter fuel payment charge. The charge turns on + total_income, which is before the property allowance and so the same on + either route, and on receipt of means-tested benefits, which reading it + here would compute again in each route's branch. The branch shares the + simulation's cached arrays until it writes, and is dropped afterwards so + a later period starts from a fresh branch. """ while name in simulation.branches or name == simulation.branch_name: name += "_" branch = simulation.get_branch(name) try: branch.set_input("uses_property_allowance", period, uses_allowance) - return branch.populations["person"]("income_tax", period) + return branch.populations["person"]( + "income_tax_before_winter_fuel_payment_charge", period + ) finally: del simulation.branches[name] @@ -46,7 +52,8 @@ class uses_property_allowance(Variable): "two cannot be combined. Full relief applies to receipts within the " "allowance unless the person elects out of it, and partial relief " "only if they elect for it; each election is made only if it lowers " - "the person's own income tax, with everyone else's route held fixed. " + "the person's own income tax (before the winter fuel payment charge), " + "with everyone else's route held fixed. " "Ties keep the default, so a person with receipts within the " "allowance keeps full relief even where electing out would carry " "finance costs forward. Without finance costs to relieve, the " diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/charges/winter_fuel_payment_charge.py b/policyengine_uk/variables/gov/hmrc/income_tax/charges/winter_fuel_payment_charge.py new file mode 100644 index 0000000000..c1dab9a309 --- /dev/null +++ b/policyengine_uk/variables/gov/hmrc/income_tax/charges/winter_fuel_payment_charge.py @@ -0,0 +1,38 @@ +from policyengine_uk.model_api import * + +# The payments s.681I(6)(a) defines as a "winter fuel payment": the Winter +# Fuel Payment in England and Wales (SI 2025/969) and Northern Ireland (NISR +# 2025/142), and Scotland's Pension Age Winter Heating Payment (SSI 2024/351). +WINTER_FUEL_PAYMENTS = [ + "winter_fuel_payment", + "pension_age_winter_heating_payment", +] + + +class winter_fuel_payment_charge(Variable): + value_type = float + entity = Person + label = "winter fuel payment charge" + documentation = ( + "The charge to income tax that recovers a person's winter fuel " + "payment: the whole payment, when the person's own total income for " + "the tax year exceeds the threshold and they are not entitled to a " + "relevant benefit in the qualifying week. It is additional tax at " + "Step 7 of the income tax calculation, so tax reductions do not " + "offset it. The payment itself, and who counts as another entitled " + "person for the shared amounts, are unaffected by the charge." + ) + definition_period = YEAR + unit = GBP + reference = ( + "https://www.legislation.gov.uk/ukpga/2003/1/section/681I", + "https://www.legislation.gov.uk/ukpga/2007/3/section/30", + "https://www.legislation.gov.uk/ukpga/2026/11/schedule/10", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.hmrc.income_tax.charges.winter_fuel_payment + payment = add(person, period, WINTER_FUEL_PAYMENTS) + over_threshold = person("total_income", period) > p.income_threshold + on_relevant_benefit = add(person, period, p.relevant_benefits) > 0 + return p.in_effect * payment * over_threshold * ~on_relevant_benefit diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/income_tax.py b/policyengine_uk/variables/gov/hmrc/income_tax/income_tax.py index 8a1596bc94..352fb5396e 100644 --- a/policyengine_uk/variables/gov/hmrc/income_tax/income_tax.py +++ b/policyengine_uk/variables/gov/hmrc/income_tax/income_tax.py @@ -5,19 +5,25 @@ class income_tax(Variable): value_type = float entity = Person label = "Income Tax" - documentation = "Total Income Tax liability" + documentation = ( + "Total Income Tax liability: the liability before the winter fuel " + "payment charge, plus the charge, which is additional tax added at " + "Step 7 after tax reductions." + ) definition_period = YEAR unit = GBP - reference = dict( - title="Income Tax Act 2007 s. 23", - href="https://www.legislation.gov.uk/ukpga/2007/3/section/23", + reference = ( + dict( + title="Income Tax Act 2007 s. 23", + href="https://www.legislation.gov.uk/ukpga/2007/3/section/23", + ), + dict( + title="Income Tax Act 2007 s. 30", + href="https://www.legislation.gov.uk/ukpga/2007/3/section/30", + ), ) category = TAX - - def formula(person, period, parameters): - p = parameters(period).gov.hmrc.income_tax - - additions = add(person, period, p.income_tax_additions) - subtractions = add(person, period, p.income_tax_subtractions) - - return max_(0, additions - subtractions) + adds = [ + "income_tax_before_winter_fuel_payment_charge", + "winter_fuel_payment_charge", + ] diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/income_tax_before_winter_fuel_payment_charge.py b/policyengine_uk/variables/gov/hmrc/income_tax/income_tax_before_winter_fuel_payment_charge.py new file mode 100644 index 0000000000..dfd8b453d9 --- /dev/null +++ b/policyengine_uk/variables/gov/hmrc/income_tax/income_tax_before_winter_fuel_payment_charge.py @@ -0,0 +1,28 @@ +from policyengine_uk.model_api import * + + +class income_tax_before_winter_fuel_payment_charge(Variable): + value_type = float + entity = Person + label = "Income Tax before the winter fuel payment charge" + documentation = ( + "Income Tax liability before the winter fuel payment charge is added " + "at Step 7. The means tests deduct this rather than income_tax: the " + "charge is not tax on the income they assess but the recovery of a " + "winter fuel payment, and it depends on receipt of Pension Credit " + "and Universal Credit, so deducting it would make the model circular." + ) + definition_period = YEAR + unit = GBP + reference = dict( + title="Income Tax Act 2007 s. 23", + href="https://www.legislation.gov.uk/ukpga/2007/3/section/23", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.hmrc.income_tax + + additions = add(person, period, p.income_tax_additions) + subtractions = add(person, period, p.income_tax_subtractions) + + return max_(0, additions - subtractions) diff --git a/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/council_tax_reduction_applicable_income.py b/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/council_tax_reduction_applicable_income.py index 55575e1987..615adf103a 100644 --- a/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/council_tax_reduction_applicable_income.py +++ b/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/council_tax_reduction_applicable_income.py @@ -116,7 +116,10 @@ def formula(benunit, period, parameters): add_for_members(benunit, period, ["pension_contributions"], members) * 0.5 ) tax = add_for_members( - benunit, period, ["income_tax", "national_insurance"], members + benunit, + period, + ["income_tax_before_winter_fuel_payment_charge", "national_insurance"], + members, ) # SI 2012/2885 Sch 1 para 17(9) and Sch 4; WSI 2013/3029 Sch 1 para # 11(9) and Sch 3; SSI 2012/319 reg 31(8) and Sch 2: the pensioner diff --git a/policyengine_uk/variables/gov/social_security_scotland/pawhp.py b/policyengine_uk/variables/gov/social_security_scotland/pawhp.py index d1c565a7e7..a282bdbc62 100644 --- a/policyengine_uk/variables/gov/social_security_scotland/pawhp.py +++ b/policyengine_uk/variables/gov/social_security_scotland/pawhp.py @@ -5,7 +5,10 @@ class pawhp(Variable): label = "Pension Age Winter Heating Payment" documentation = ( "Pension Age Winter Heating Payments made to the members of this " - "household (pension_age_winter_heating_payment)." + "household (pension_age_winter_heating_payment). The payments are " + "counted in full: from 2025-26 the winter fuel payment charge " + "recovers them from some members through income tax " + "(winter_fuel_payment_charge)." ) entity = Household definition_period = YEAR diff --git a/policyengine_uk/variables/gov/social_security_scotland/pension_age_winter_heating_payment.py b/policyengine_uk/variables/gov/social_security_scotland/pension_age_winter_heating_payment.py index aa3e0c0cca..c869030212 100644 --- a/policyengine_uk/variables/gov/social_security_scotland/pension_age_winter_heating_payment.py +++ b/policyengine_uk/variables/gov/social_security_scotland/pension_age_winter_heating_payment.py @@ -12,7 +12,8 @@ class pension_age_winter_heating_payment(Variable): "(the higher amount if they or their partner have reached 80), once " "per couple. From the 2025 qualifying week anyone else receives the " "full amount if they do not live with another entitled individual, " - "and a shared amount otherwise." + "and a shared amount otherwise. This is the amount paid, before any " + "winter fuel payment charge (winter_fuel_payment_charge)." ) definition_period = YEAR unit = GBP diff --git a/policyengine_uk/variables/household/income/hbai_benefits.py b/policyengine_uk/variables/household/income/hbai_benefits.py index ac8d146133..69165d87c8 100644 --- a/policyengine_uk/variables/household/income/hbai_benefits.py +++ b/policyengine_uk/variables/household/income/hbai_benefits.py @@ -35,6 +35,7 @@ class hbai_benefits(Variable): "ssmg", "cost_of_living_support_payment", "winter_fuel_allowance", + "pawhp", "tax_free_childcare", "childcare_grant", "parents_learning_allowance", diff --git a/policyengine_uk/variables/household/income/hbai_household_net_income.py b/policyengine_uk/variables/household/income/hbai_household_net_income.py index 5061ab23c1..7f3ff86227 100644 --- a/policyengine_uk/variables/household/income/hbai_household_net_income.py +++ b/policyengine_uk/variables/household/income/hbai_household_net_income.py @@ -45,6 +45,7 @@ "ssmg", "cost_of_living_support_payment", "winter_fuel_allowance", + "pawhp", "tax_free_childcare", "healthy_start_vouchers", "scottish_child_payment", diff --git a/policyengine_uk/variables/household/income/household_benefits.py b/policyengine_uk/variables/household/income/household_benefits.py index 1de62cbaec..7d52631e7a 100644 --- a/policyengine_uk/variables/household/income/household_benefits.py +++ b/policyengine_uk/variables/household/income/household_benefits.py @@ -33,6 +33,7 @@ "cost_of_living_support_payment", "energy_bills_rebate", "winter_fuel_allowance", + "pawhp", "tax_free_childcare", "extended_childcare_entitlement", "universal_childcare_entitlement",