diff --git a/changelog.d/1955.fixed.md b/changelog.d/1955.fixed.md new file mode 100644 index 0000000000..056db824ef --- /dev/null +++ b/changelog.d/1955.fixed.md @@ -0,0 +1 @@ +Council Tax Reduction income now counts Carer Support Payment, which Scottish carers receive in place of Carer's Allowance (Council Tax Reduction (Scotland) Regulations 2021 reg 57(1)(b)(iva); Council Tax Reduction (State Pension Credit) (Scotland) Regulations 2012 reg 27(1)(j)). The Scottish Carer Supplement stays out. diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_carer_support_payment.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_carer_support_payment.yaml new file mode 100644 index 0000000000..83dc25ff15 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_carer_support_payment.yaml @@ -0,0 +1,441 @@ +# Carer Support Payment in Council Tax Reduction income. +# Scottish carers receive Carer Support Payment (CSP) in place of Carer's +# Allowance (CA); the model moves them in 2025. Scottish Council Tax Reduction +# counts the CSP component, with no cap at the CA amount: +# - working age: Council Tax Reduction (Scotland) Regulations 2021 (SSI +# 2021/249) reg 57(1)(b)(iva), a closed list of unearned income; +# - pension age: Council Tax Reduction (State Pension Credit) (Scotland) +# Regulations 2012 (SSI 2012/319) reg 27(1)(j), social security benefits +# other than those it lists. +# Neither counts the Scottish Carer Supplement, paid with CSP from 15 March +# 2026: reg 57(1) does not list it and reg 27(1)(j)(xxib) excepts it. In law +# the supplement's tax does not reach Council Tax Reduction either: at working +# age SSI 2021/249 deducts tax only from earnings, and at pension age SSI +# 2012/319 reg 31(12) disregards the tax payable on income taken into +# account, which the supplement is not. The model deducts all income tax, so +# the taxable supplement reaches the model's Council Tax Reduction income +# through income tax and in no other way. +# Neither instrument disregards CSP above the CA amount. +# +# Weekly rates. 2026: CSP and CA 86.45, Scottish Carer Supplement 11.70, +# carer premium 48.15, personal allowance 95.55 (single, 25 or over), 256.00 +# (single, pension age) and 383.35 (couple, pension age). 2025: CSP 83.30, no +# supplement, and the model's carer premium 46.38 and personal allowance 92.04 +# (the statutory 2025-26 amounts were 46.40 and 92.05; see #2110). 2024: CA +# 81.90, carer premium 45.60, personal allowance 90.50. Reduction is withdrawn +# at 20% of income above the applicable amount. Council tax is 2,000 +# throughout. +# The working-age cases take no Universal Credit, so the award does not turn +# on how Universal Credit treats CSP. + +- name: Carer Support Payment counts as working-age Council Tax Reduction income in Scotland + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 40 + private_pension_income: 7_000 + care_hours: 35 + benunits: + benunit: + members: [carer] + would_claim_uc: false + households: + household: + members: [carer] + country: SCOTLAND + region: SCOTLAND + council_tax: 2_000 + savings: 0 + output: + carers_allowance: 0 + carer_support_payment: 86.45 * 52 + scottish_carer_supplement: 11.70 * 52 + # 7,000 + 4,495.40 + 608.40 is below the 12,570 personal allowance. + income_tax: 0 + # The CSP component only: 7,000 + 4,495.40. Counting the supplement too + # would give 12,103.80. + council_tax_reduction_applicable_income: 7_000 + 86.45 * 52 + council_tax_reduction_applicable_amount: (95.55 + 48.15) * 52 + # 2,000 - 0.2 x (11,495.40 - 7,472.40) + council_tax_benefit: 2_000 - 0.2 * (7_000 + 86.45 * 52 - (95.55 + 48.15) * 52) + council_tax_reduction: 1_195.40 + +- name: A reported carer's award in Scotland counts as Council Tax Reduction income + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 40 + private_pension_income: 7_000 + carers_allowance_reported: 1 + care_hours: 0 + benunits: + benunit: + members: [carer] + would_claim_uc: false + households: + household: + members: [carer] + country: SCOTLAND + region: SCOTLAND + council_tax: 2_000 + savings: 0 + output: + carer_support_payment: 86.45 * 52 + council_tax_reduction_applicable_income: 7_000 + 86.45 * 52 + council_tax_reduction: 1_195.40 + +- name: A Welsh carer on Carer's Allowance gets the same Council Tax Reduction as the Scottish carer + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 40 + private_pension_income: 7_000 + care_hours: 35 + benunits: + benunit: + members: [carer] + would_claim_uc: false + households: + household: + members: [carer] + country: WALES + region: WALES + council_tax: 2_000 + savings: 0 + output: + carers_allowance: 86.45 * 52 + carer_support_payment: 0 + scottish_carer_supplement: 0 + council_tax_reduction_applicable_income: 7_000 + 86.45 * 52 + council_tax_reduction: 1_195.40 + +- name: A Scottish carer who does not claim Carer Support Payment has none counted + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 40 + private_pension_income: 7_000 + care_hours: 35 + would_claim_carers_allowance: false + benunits: + benunit: + members: [carer] + would_claim_uc: false + households: + household: + members: [carer] + country: SCOTLAND + region: SCOTLAND + council_tax: 2_000 + savings: 0 + output: + carer_support_payment: 0 + scottish_carer_supplement: 0 + council_tax_reduction_applicable_income: 7_000 + # Without a claim there is no entitlement, so no carer premium (SSI + # 2021/249 Sch 1 paras 5(2) and 6(1)): the applicable amount is 95.55 x 52 + # = 4,968.60. + council_tax_reduction_applicable_amount: 95.55 * 52 + # 2,000 - 0.2 x (7,000 - 4,968.60) + council_tax_reduction: 2_000 - 0.2 * (7_000 - 95.55 * 52) + +- name: A working-age carer on contributory ESA above the Carer Support Payment rate has it counted in Council Tax Reduction + # Contributory ESA (96.15 a week here) is an overlapping benefit, so CSP + # Regs (SSI 2023/302) reg 16(2)(b) reduces the CSP given to nil. Until it is + # decided which amount CTR counts, CTR counts the 86.45 x 52 before the + # reduction (carer_support_payment_pre_overlap). + # SSI 2021/249 reg 57(1)(b) counts CSP "to which the applicant is entitled, + # subject to any adjustment ... in accordance with Regulations under + # section 73 of the Social Security Administration Act 1992"; reg 16(2) is + # made under the Social Security (Scotland) Act 2018, not section 73. + # Whoever settles which amount CTR counts must update this case; it fails + # if CTR income silently drops the CSP. Taxable income, + # 5,000 + 4,495.40 + 608.40 = 10,103.80, is below the personal allowance + # either way. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 40 + esa_contrib_reported: 5_000 + care_hours: 35 + benunits: + benunit: + members: [carer] + would_claim_uc: false + households: + household: + members: [carer] + country: SCOTLAND + region: SCOTLAND + council_tax: 2_000 + savings: 0 + output: + esa_contrib: 5_000 + carer_support_payment: 0 + carer_support_payment_pre_overlap: 86.45 * 52 + income_tax: 0 + # 5,000 + 4,495.40. Leaving the CSP out would give 5,000, below the + # applicable amount, and a full award of 2,000. + council_tax_reduction_applicable_income: 5_000 + 86.45 * 52 + council_tax_reduction_applicable_amount: (95.55 + 48.15) * 52 + # 2,000 - 0.2 x (9,495.40 - 7,472.40) + council_tax_reduction: 1_595.40 + +- name: Carer Support Payment counts in 2025, before the Scottish Carer Supplement + period: 2025 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 40 + private_pension_income: 7_000 + care_hours: 35 + benunits: + benunit: + members: [carer] + would_claim_uc: false + households: + household: + members: [carer] + country: SCOTLAND + region: SCOTLAND + council_tax: 2_000 + savings: 0 + output: + carers_allowance: 0 + carer_support_payment: 83.30 * 52 + scottish_carer_supplement: 0 + council_tax_reduction_applicable_income: 7_000 + 83.30 * 52 + council_tax_reduction_applicable_amount: (92.04 + 46.38) * 52 + # 2,000 - 0.2 x (11,331.60 - 7,197.84) = 1,173.25 + council_tax_reduction: 2_000 - 0.2 * (7_000 + 83.30 * 52 - (92.04 + 46.38) * 52) + +- name: In 2024 the Scottish carer is still on Carer's Allowance, which was already counted + period: 2024 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 40 + private_pension_income: 7_000 + care_hours: 35 + benunits: + benunit: + members: [carer] + would_claim_uc: false + households: + household: + members: [carer] + country: SCOTLAND + region: SCOTLAND + council_tax: 2_000 + savings: 0 + output: + carers_allowance: 81.90 * 52 + carer_support_payment: 0 + council_tax_reduction_applicable_income: 7_000 + 81.90 * 52 + # 2,000 - 0.2 x (11,258.80 - 7,077.20) = 1,163.68. The award no longer + # jumps to 2,000 when the carer moves to Carer Support Payment in 2025. + council_tax_reduction: 2_000 - 0.2 * (7_000 + 81.90 * 52 - (90.50 + 45.60) * 52) + +- name: Pension-age Council Tax Reduction counts Carer Support Payment, and the supplement only through tax + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 70 + state_pension: 0 + private_pension_income: 14_000 + care_hours: 35 + benunits: + benunit: + members: [carer] + households: + household: + members: [carer] + country: SCOTLAND + region: SCOTLAND + council_tax: 2_000 + savings: 0 + output: + carer_support_payment: 86.45 * 52 + scottish_carer_supplement: 11.70 * 52 + # Taxable income is 14,000 + 4,495.40 + 608.40 - 12,570 = 6,533.80: the + # first 3,967 at the Scottish starter rate of 19% and 2,566.80 at 20%. + # The supplement adds 608.40 x 20% = 121.68 of that tax. + income_tax: 3_967 * 0.19 + 2_566.80 * 0.20 + # 14,000 + 4,495.40 - 1,267.09: the supplement is not added. + council_tax_reduction_applicable_income: 14_000 + 86.45 * 52 - 1_267.09 + council_tax_reduction_applicable_amount: (256 + 48.15) * 52 + # Income is above the minimum guarantee of (238 + 48.15) x 52 = 14,879.80. + guarantee_credit: 0 + # 2,000 - 0.2 x (17,228.31 - 15,815.80) + council_tax_reduction: 1_717.50 + +- name: A pension-age couple's Council Tax Reduction counts the partner's Carer Support Payment + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 70 + state_pension: 0 + private_pension_income: 12_000 + partner: + age: 70 + state_pension: 0 + private_pension_income: 6_500 + care_hours: 35 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + country: SCOTLAND + region: SCOTLAND + council_tax: 2_000 + savings: 0 + output: + # 86.45 x 52 and 11.70 x 52, for the partner. + carer_support_payment: [0, 4_495.40] + scottish_carer_supplement: [0, 608.40] + # Each is below the personal allowance: 12,000, and 6,500 + 4,495.40 + + # 608.40 = 11,603.80. + income_tax: [0, 0] + council_tax_reduction_applicable_income: 12_000 + 6_500 + 86.45 * 52 + council_tax_reduction_applicable_amount: (383.35 + 48.15) * 52 + # Income is above the minimum guarantee of (363.25 + 48.15) x 52 = + # 21,392.80. + guarantee_credit: 0 + # 2,000 - 0.2 x (22,995.40 - 22,438.00) + council_tax_reduction: 1_888.52 + +- name: A pension-age carer whose State Pension exceeds the Carer Support Payment rate has it counted in Council Tax Reduction + # The partner's State Pension (142.31 a week) exceeds the CSP rate, so CSP + # Regs (SSI 2023/302) reg 16(2)(b) reduces the CSP given to them to nil, + # and with it the supplement. Whether pension-age CTR should count CSP + # before or after that reduction is open: SSI 2012/319 reg 27(3) counts a + # benefit before any deduction other than the reg 27(5) adjustments, and + # reg 27(5) lists the Overlapping Benefits Regulations 1979 but not reg + # 16(2). Until it is decided CTR counts the 86.45 x 52 before the + # reduction (carer_support_payment_pre_overlap). Whoever settles it must + # update this case; it fails if CTR income silently drops the CSP. The + # couple is unmarried, so no marriage allowance links the claimant's tax to + # the partner's income. The partner's taxable income is 7,400, below the + # personal allowance, and would stay below it (7,400 + 4,495.40 + 608.40 = + # 12,503.80) if the CSP were paid, so the tax does not depend on the + # choice. Guarantee Credit is nil either way. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 70 + state_pension: 15_000 + partner: + age: 70 + state_pension: 7_400 + care_hours: 35 + benunits: + benunit: + members: [claimant, partner] + is_married: false + households: + household: + members: [claimant, partner] + country: SCOTLAND + region: SCOTLAND + council_tax: 2_000 + savings: 0 + output: + carer_support_payment: [0, 0] + # 86.45 x 52 for the partner. + carer_support_payment_pre_overlap: [0, 4_495.40] + scottish_carer_supplement: [0, 0] + # (15,000 - 12,570) x 19%, all in the Scottish starter band. + income_tax: [461.70, 0] + # Income is above the minimum guarantee of (363.25 + 48.15) x 52 = + # 21,392.80 with or without the CSP: 15,000 + 7,400 - 461.70 = 21,938.30. + guarantee_credit: 0 + # 15,000 + 7,400 + 86.45 x 52 - 461.70. Leaving the CSP out would give + # 21,938.30, below the applicable amount, and a full award of 2,000. + council_tax_reduction_applicable_income: 15_000 + 7_400 + 86.45 * 52 - 461.70 + council_tax_reduction_applicable_amount: (383.35 + 48.15) * 52 + # 2,000 - 0.2 x (26,433.70 - 22,438.00) + council_tax_reduction: 1_200.86 + +- name: A pension-age couple below the applicable amount keeps full Council Tax Reduction + period: 2026 + absolute_error_margin: 0.01 + input: + people: + claimant: + age: 70 + state_pension: 0 + private_pension_income: 9_000 + partner: + age: 70 + state_pension: 0 + private_pension_income: 6_500 + care_hours: 35 + benunits: + benunit: + members: [claimant, partner] + households: + household: + members: [claimant, partner] + country: SCOTLAND + region: SCOTLAND + council_tax: 2_000 + savings: 0 + output: + carer_support_payment: [0, 4_495.4] + # Guarantee Credit is paid: 21,392.80 - 19,995.40. Pension Credit income + # counts the Carer Support Payment component. + guarantee_credit: (363.25 + 48.15) * 52 - (9_000 + 6_500 + 86.45 * 52) + # A guarantee credit recipient's whole income is disregarded (SSI 2012/319 + # reg 24), so the Carer Support Payment does not reach the means test. + council_tax_reduction_applicable_income: 0 + council_tax_reduction: 2_000 + +- name: An English pensioner carer's Council Tax Reduction is unchanged + period: 2026 + absolute_error_margin: 0.01 + input: + people: + carer: + age: 70 + state_pension: 0 + private_pension_income: 14_000 + care_hours: 35 + benunits: + benunit: + members: [carer] + households: + household: + members: [carer] + country: ENGLAND + region: NORTH_WEST + council_tax: 2_000 + savings: 0 + output: + carers_allowance: 86.45 * 52 + carer_support_payment: 0 + scottish_carer_supplement: 0 + # (14,000 + 4,495.40 - 12,570) x 20% + income_tax: 1_185.08 + council_tax_reduction_applicable_income: 14_000 + 86.45 * 52 - 1_185.08 + # 2,000 - 0.2 x (17,310.32 - 15,815.80) + council_tax_reduction: 1_701.10 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 new file mode 100644 index 0000000000..8795cdd8c6 --- /dev/null +++ b/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py @@ -0,0 +1,409 @@ +"""Carer Support Payment in Council Tax Reduction income. + +Scottish carers receive Carer Support Payment in place of Carer's Allowance. +Council Tax Reduction income counted Carer's Allowance but left Carer Support +Payment out, so a Scottish carer's reduction was assessed as if the carer's +benefit were not paid. Scottish Council Tax Reduction counts the Carer Support +Payment component, with no cap at the Carer's Allowance amount: the Council +Tax Reduction (Scotland) Regulations +2021 (SSI 2021/249) reg 57(1)(b)(iva) at working age, and the Council Tax +Reduction (State Pension Credit) (Scotland) Regulations 2012 (SSI 2012/319) +reg 27(1)(j) at pension age. + +Neither counts the Scottish Carer Supplement, paid with Carer Support Payment +from 15 March 2026: reg 57(1) is a closed list that leaves it out, and reg +27(1)(j)(xxib) excepts it. Nor does the tax on the supplement count: at +working age SSI 2021/249 deducts income tax only from earnings (Part 6 +Chapter 3), and at pension age SSI 2012/319 reg 31(12) disregards the tax +payable on income taken into account, which the supplement is not. So in law +the supplement does not touch Council Tax Reduction at all. The model deducts +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. + +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 +over State Pension age: + +1. Counts the component: claiming Carer Support Payment raises Council Tax + Reduction income, before income tax and National Insurance and apart from + the other benefits it counts, by exactly the Carer Support Payment + component (86.45 a week), not by the component plus the supplement, and + by that amount before any overlapping-benefit reduction (see below). The + reduction itself never rises, and where both awards are partial it falls + by 20% of the rise in income less the rise in the applicable amount (the + carer premium comes with the claim). +2. Invariant to the supplement: setting the Scottish Carer Supplement to zero + leaves Carer Support Payment and the other benefits counted in Council + Tax Reduction income (Child Benefit, the income-related benefits, + Universal Credit and tax credits) unchanged, and changes that income only + through income tax: income plus income tax is unchanged. The supplement + never lowers the reduction, and where both awards are partial it raises + it by 20% of the tax on the supplement. +3. Differential: Council Tax Reduction and Housing Benefit assess the same + carer income. Where Guarantee Credit does not passport Housing Benefit, + Housing Benefit applicable income, before its disregard, childcare element + and tariff income, equals Council Tax Reduction income less the part of + Carer Support Payment that an overlapping benefit removes, which Housing + Benefit counts after the reduction (HB (SPC) Regs reg 29(4)(g)). This holds in + Scotland, where the carer's benefit is Carer Support Payment, and in + England and Wales, where it is Carer's Allowance. + +Invariants 1 to 3 concern Council Tax Reduction income under the general rules. +A pension-age family in receipt of a guarantee credit has its whole income +disregarded (SSI 2012/319 reg 24), and one in receipt of savings credit only is +assessed on the Secretary of State's Pension Credit income plus the savings +credit (reg 25), so those cells are left out of 1 to 3 and checked instead by: + +4. Pension Credit routes: where the family is in receipt of a guarantee credit, + Council Tax Reduction income is nil; where it is in receipt of savings credit + only, it equals Pension Credit income plus the Pension Credit paid. + +These compare the model's own income measures, so they hold whatever carer's +benefit the model pays. The model reduces Carer Support Payment by +overlapping benefits such as State Pension (the Carer's Assistance (Carer +Support Payment) (Scotland) Regulations 2023 reg 16(2)), and the supplement +with it. Whether Council Tax Reduction counts the payment before or after +that reduction is unsettled; until it is decided the model counts +carer_support_payment_pre_overlap. It applies the Housing Benefit applicable +amounts to every nation's Council Tax Reduction. +""" + +import numpy as np +from hypothesis import HealthCheck, example, given, settings +from hypothesis import strategies as st + +from policyengine_uk import Simulation + +YEAR = 2026 +PENSIONS = np.arange(0, 40_001, 2_000) +WEEKS = 52 +CARER_SUPPORT_PAYMENT = 86.45 * WEEKS +SCOTTISH_CARER_SUPPLEMENT = 11.70 * WEEKS +WITHDRAWAL_RATE = 0.2 +PROPERTY_SETTINGS = settings( + max_examples=10, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) +REGIONS = { + "ENGLAND": "NORTH_WEST", + "WALES": "WALES", + "SCOTLAND": "SCOTLAND", +} +NO_SCOTTISH_CARER_SUPPLEMENT = { + "gov.social_security_scotland.carer_support_payment.supplement": { + "2026-01-01.2100-12-31": 0 + } +} +# The benefits Council Tax Reduction income counts besides the personal ones. +OTHER_COUNTED_BENEFITS = [ + "child_benefit", + "income_support", + "jsa_income", + "esa_income", + "universal_credit", + "tax_credits", +] +BENUNIT_VARIABLES = [ + "council_tax_reduction_applicable_income", + "council_tax_reduction_applicable_amount", + "council_tax_benefit", + "guarantee_credit", + "housing_benefit_applicable_income", + "housing_benefit_applicable_income_disregard", + "housing_benefit_applicable_income_childcare_element", + "housing_benefit_tariff_income", + "in_receipt_of_guarantee_credit", + "in_receipt_of_savings_credit_only", + "pension_credit_income", + "pension_credit", + *OTHER_COUNTED_BENEFITS, +] +PERSON_VARIABLES = [ + "carers_allowance", + "carers_allowance_pre_overlap", + "carer_support_payment", + "carer_support_payment_pre_overlap", + "scottish_carer_supplement", + "income_tax", + "national_insurance", +] +CLAIMS = (True, False) +# A Scottish pensioner carer with no State Pension: across the private pension +# grid this family moves between the general rules and savings credit only. +SAVINGS_CREDIT_CARER = dict( + pension_age=True, + adults=[dict(age=80, state_pension=0.0)], + carer=0, + by_hours=True, + country="SCOTLAND", + council_tax=2_000.0, +) + + +def money(high): + return st.floats(0, high, allow_nan=False, allow_infinity=False) + + +@st.composite +def family(draw, countries=("SCOTLAND",)): + pension_age = draw(st.booleans()) + adults = [] + for _ in range(draw(st.integers(1, 2))): + if pension_age: + adult = dict( + age=draw(st.integers(67, 95)), + state_pension=draw(money(15_000)), + ) + else: + adult = dict( + age=draw(st.integers(25, 60)), + employment_income=draw(st.one_of(st.just(0.0), money(30_000))), + ) + adults.append(adult) + return dict( + pension_age=pension_age, + adults=adults, + carer=draw(st.integers(0, len(adults) - 1)), + # The carer qualifies either by caring hours or by a reported award. + by_hours=draw(st.booleans()), + country=draw(st.sampled_from(countries)), + council_tax=draw(st.floats(500, 3_000, allow_nan=False)), + ) + + +def situation(families): + """Each family at each private pension, claiming and not claiming.""" + people, benunits, households = {}, {}, {} + for i, fam in enumerate(families): + for k, pension in enumerate(PENSIONS): + for c, claims in enumerate(CLAIMS): + names = [] + for j, a in enumerate(fam["adults"]): + name = f"p{i}_{k}_{c}_{j}" + person = { + "age": {YEAR: a["age"]}, + "state_pension": {YEAR: a.get("state_pension", 0.0)}, + "employment_income": {YEAR: a.get("employment_income", 0.0)}, + # All private pension goes to the first adult. + "private_pension_income": {YEAR: float(pension) * (j == 0)}, + } + if j == fam["carer"]: + if fam["by_hours"]: + person["care_hours"] = {YEAR: 35} + else: + person["carers_allowance_reported"] = {YEAR: 1} + person["would_claim_carers_allowance"] = {YEAR: claims} + people[name] = person + names.append(name) + benunits[f"b{i}_{k}_{c}"] = { + "members": names, + "would_claim_uc": {YEAR: False}, + } + households[f"h{i}_{k}_{c}"] = { + "members": names, + "country": {YEAR: fam["country"]}, + "region": {YEAR: REGIONS[fam["country"]]}, + "council_tax": {YEAR: fam["council_tax"]}, + "savings": {YEAR: 0.0}, + } + return {"people": people, "benunits": benunits, "households": households} + + +def grid(families, reform=None): + """Arrays indexed by family, private pension and whether the carer claims + (index 0 claims, index 1 does not).""" + simulation = Simulation(situation=situation(families), reform=reform) + shape = (len(families), len(PENSIONS), len(CLAIMS)) + g = { + variable: np.asarray(simulation.calculate(variable, YEAR)).reshape(shape) + for variable in BENUNIT_VARIABLES + } + for variable in PERSON_VARIABLES: + values = simulation.calculate(variable, YEAR, map_to="benunit") + g[variable] = np.asarray(values).reshape(shape) + g["other_counted_benefits"] = sum(g[v] for v in OTHER_COUNTED_BENEFITS) + # Council Tax Reduction income before the taxes deducted from it and apart + # from the other benefits it counts. + g["income_before_tax"] = ( + g["council_tax_reduction_applicable_income"] + + g["income_tax"] + + g["national_insurance"] + - g["other_counted_benefits"] + ) + # Cells whose Council Tax Reduction income follows the general rules, not + # the Pension Credit routes of SSI 2012/319 regs 24 and 25. + g["general_rules"] = ~( + g["in_receipt_of_guarantee_credit"].astype(bool) + | g["in_receipt_of_savings_credit_only"].astype(bool) + ) + return g + + +def partial(g, i): + """Where the award is neither nil nor the whole council tax bill.""" + award = g["council_tax_benefit"][i] + return (award > 0.01) & (award < np.max(award) - 0.01) + + +@PROPERTY_SETTINGS +@given(st.lists(family(), min_size=1, max_size=3)) +@example([SAVINGS_CREDIT_CARER]) +def test_council_tax_reduction_income_counts_the_carer_support_payment_component( + families, +): + g = grid(families) + income = g["council_tax_reduction_applicable_income"] + award = g["council_tax_benefit"] + for i, fam in enumerate(families): + claimed, unclaimed = g["carer_support_payment_pre_overlap"][i].T + assert np.allclose(claimed, CARER_SUPPORT_PAYMENT, atol=0.01), fam + assert np.all(unclaimed == 0), fam + # The supplement is paid in full in each week some Carer Support + # Payment is paid after any overlapping-benefit reduction. + paid = g["carer_support_payment"][i, :, 0] > 0 + assert np.allclose( + g["scottish_carer_supplement"][i, :, 0], + SCOTTISH_CARER_SUPPLEMENT * paid, + atol=0.01, + ), fam + assert np.all(g["carers_allowance"][i] == 0), fam + # Only where the zero floor on income does not bind in either run, and + # both runs follow the general rules. + general = g["general_rules"][i, :, 0] & g["general_rules"][i, :, 1] + compared = (income[i, :, 0] > 0) & (income[i, :, 1] > 0) & general + # At the top of the pension grid every family follows the general + # rules with positive income, so the comparison is never empty. + assert compared.any(), fam + rise = g["income_before_tax"][i, :, 0] - g["income_before_tax"][i, :, 1] + assert np.allclose(rise[compared], CARER_SUPPORT_PAYMENT, atol=0.05), ( + fam, + rise[compared], + ) + # Claiming never raises the reduction: on the general rules income + # rises by more than the carer premium the claim brings. + assert np.all((award[i, :, 0] <= award[i, :, 1] + 0.01)[general]), fam + both_partial = partial(g, i)[:, 0] & partial(g, i)[:, 1] & general + amount = g["council_tax_reduction_applicable_amount"][i] + excess_rise = (income[i, :, 0] - amount[:, 0]) - ( + income[i, :, 1] - amount[:, 1] + ) + fall = award[i, :, 1] - award[i, :, 0] + assert np.allclose( + fall[both_partial], + WITHDRAWAL_RATE * excess_rise[both_partial], + atol=0.05, + ), (fam, fall[both_partial], excess_rise[both_partial]) + + +@PROPERTY_SETTINGS +@given(st.lists(family(), min_size=1, max_size=3)) +@example([SAVINGS_CREDIT_CARER]) +def test_council_tax_reduction_income_ignores_the_scottish_carer_supplement( + families, +): + g = grid(families) + without = grid(families, reform=NO_SCOTTISH_CARER_SUPPLEMENT) + for i, fam in enumerate(families): + # The carer claims in column 0; the supplement is paid where some + # Carer Support Payment is paid. + paid = g["carer_support_payment"][i, :, 0] > 0 + assert np.all((g["scottish_carer_supplement"][i, :, 0] > 0) == paid), fam + assert np.all(without["scottish_carer_supplement"][i] == 0), fam + for variable in [ + "carer_support_payment", + "carer_support_payment_pre_overlap", + "other_counted_benefits", + ]: + assert np.allclose(g[variable][i], without[variable][i], atol=0.01), ( + fam, + variable, + ) + income = g["council_tax_reduction_applicable_income"][i] + income_without = without["council_tax_reduction_applicable_income"][i] + # Only where the zero floor on income does not bind in either run, and + # both runs follow the general rules. + general = g["general_rules"][i] & without["general_rules"][i] + 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], + atol=0.05, + ), fam + award = g["council_tax_benefit"][i] + award_without = without["council_tax_benefit"][i] + # The supplement can only add tax, which lowers income, so it never + # lowers the award, even on the Pension Credit routes (whose income + # 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] + assert np.allclose( + (award - award_without)[both_partial], + WITHDRAWAL_RATE * tax_on_supplement[both_partial], + atol=0.05, + ), fam + # Without a claim there is no supplement, so nothing moves. + assert np.allclose(income[:, 1], income_without[:, 1], atol=0.01), fam + + +@PROPERTY_SETTINGS +@given(st.lists(family(countries=tuple(REGIONS)), min_size=1, max_size=3)) +def test_council_tax_reduction_and_housing_benefit_assess_the_same_carer_income( + families, +): + g = grid(families) + for i, fam in enumerate(families): + carer_benefit = ( + g["carers_allowance_pre_overlap"][i] + + g["carer_support_payment_pre_overlap"][i] + ) + assert np.all(carer_benefit[:, 0] > 0), fam + # Housing Benefit counts Carer Support Payment after any + # overlapping-benefit reduction; Council Tax Reduction, for now, + # before it. + removed_by_overlap = ( + g["carer_support_payment_pre_overlap"][i] - g["carer_support_payment"][i] + ) + ctr_income = g["council_tax_reduction_applicable_income"][i] + hb_income = g["housing_benefit_applicable_income"][i] + # Guarantee Credit passports pension-age Housing Benefit to nil + # income; the zero floors must not bind. + passported = fam["pension_age"] & (g["guarantee_credit"][i] > 0) + compared = ( + ~passported & g["general_rules"][i] & (hb_income > 0) & (ctr_income > 0) + ) + assert compared.any(), fam + hb_before_adjustments = ( + hb_income + + g["housing_benefit_applicable_income_disregard"][i] + + g["housing_benefit_applicable_income_childcare_element"][i] + - g["housing_benefit_tariff_income"][i] + ) + ctr_less_overlap = ctr_income - removed_by_overlap + assert np.allclose( + hb_before_adjustments[compared], ctr_less_overlap[compared], atol=0.05 + ), (fam, hb_before_adjustments[compared], ctr_less_overlap[compared]) + + +@PROPERTY_SETTINGS +@given(st.lists(family(), min_size=1, max_size=3)) +@example([SAVINGS_CREDIT_CARER]) +def test_council_tax_reduction_income_on_the_pension_credit_routes(families): + g = grid(families) + for i, fam in enumerate(families): + income = g["council_tax_reduction_applicable_income"][i] + guarantee = g["in_receipt_of_guarantee_credit"][i].astype(bool) + savings_only = g["in_receipt_of_savings_credit_only"][i].astype(bool) + assert not np.any(guarantee & savings_only), fam + assert np.all(income[guarantee] == 0), fam + expected = g["pension_credit_income"][i] + g["pension_credit"][i] + assert np.allclose(income[savings_only], expected[savings_only], atol=0.01), ( + fam, + income[savings_only], + expected[savings_only], + ) 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 e34a88f15c..b86cabc27d 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 @@ -25,6 +25,8 @@ class council_tax_reduction_applicable_income(Variable): "https://www.legislation.gov.uk/wsi/2013/3029/schedule/1/paragraph/8", "https://www.legislation.gov.uk/ssi/2012/319/regulation/24", "https://www.legislation.gov.uk/ssi/2012/319/regulation/25", + "https://www.legislation.gov.uk/ssi/2012/319/regulation/27", + "https://www.legislation.gov.uk/ssi/2021/249/regulation/57", "https://www.legislation.gov.uk/uksi/2012/2885/schedule/4", "https://www.legislation.gov.uk/wsi/2013/3029/schedule/3", "https://www.legislation.gov.uk/ssi/2012/319/schedule/2", @@ -49,6 +51,21 @@ def formula(benunit, period, parameters): ] personal_benefits = [ "carers_allowance", + # Scottish carers receive Carer Support Payment in place of Carer's + # Allowance. Scottish Council Tax Reduction counts it, with no cap at + # the Carer's Allowance amount: + # SSI 2021/249 reg 57(1)(b)(iva) at working age and SSI 2012/319 + # reg 27(1)(j) at pension age. Neither counts the Scottish Carer + # Supplement (reg 57(1) does not list it; reg 27(1)(j)(xxib) + # excepts it), so scottish_carer_supplement is not listed. + # Whether CTR counts CSP before or after the CSP Regs reg 16(2) + # overlapping-benefit reduction is unsettled: SSI 2012/319 reg + # 27(3) grosses up deductions other than the reg 27(5) + # adjustments, which do not list reg 16(2), while SSI 2021/249 reg + # 57(1)(b) counts the amount the applicant is entitled to. Until + # that is decided, the amount before the reduction is counted, as + # it was before the reduction was modelled. + "carer_support_payment_pre_overlap", "esa_contrib", "jsa_contrib", "state_pension", diff --git a/policyengine_uk/variables/gov/social_security_scotland/scottish_carer_supplement.py b/policyengine_uk/variables/gov/social_security_scotland/scottish_carer_supplement.py index de294f633b..7dae35df45 100644 --- a/policyengine_uk/variables/gov/social_security_scotland/scottish_carer_supplement.py +++ b/policyengine_uk/variables/gov/social_security_scotland/scottish_carer_supplement.py @@ -11,10 +11,9 @@ class scottish_carer_supplement(Variable): "reduces Carer Support Payment to £0, nothing is payable and no " "supplement is paid; where it reduces the payment but leaves some, " "the supplement is paid in full. It is a component of Carer Support " - "separate from the Carer Support Payment component. Pension Credit " - "and Housing Benefit, " - "at pension age and working age, do not count it as income; it is " - "taxable." + "separate from the Carer Support Payment component. Pension Credit, " + "Housing Benefit and Scottish Council Tax Reduction, at pension age " + "and working age, do not count it as income; it is taxable." ) definition_period = YEAR unit = GBP @@ -24,6 +23,8 @@ class scottish_carer_supplement(Variable): "https://www.legislation.gov.uk/uksi/2026/246/article/17/made", "https://www.legislation.gov.uk/uksi/2026/246/article/20/made", "https://www.legislation.gov.uk/uksi/2026/246/article/21/made", + "https://www.legislation.gov.uk/ssi/2012/319/regulation/27", + "https://www.legislation.gov.uk/ssi/2021/249/regulation/57", "https://www.legislation.gov.uk/uksi/2026/93/made", ]